Ticket #5319: iscsi-draft-01.diff

File iscsi-draft-01.diff, 29.3 KB (added by andreasf, 14 years ago)

draft patch

  • new file headers/private/kernel/boot/net/iSCSITarget.h

     headers/private/kernel/boot/net/iSCSITarget.h     |  352 +++++++++++
     src/system/boot/loader/net/Jamfile                |    3 +
     src/system/boot/loader/net/iSCSITarget.cpp        |  654 +++++++++++++++++++++
     src/system/boot/platform/openfirmware/devices.cpp |   54 ++-
     4 files changed, 1058 insertions(+), 5 deletions(-)
    
    diff --git a/headers/private/kernel/boot/net/iSCSITarget.h b/headers/private/kernel/boot/net/iSCSITarget.h
    new file mode 100644
    index 0000000..736076a
    - +  
     1/*
     2 * Copyright 2010, Andreas Faerber <andreas.faerber@web.de>
     3 * All rights reserved. Distributed under the terms of the MIT License.
     4 */
     5#ifndef BOOT_NET_ISCSITARGET_H
     6#define BOOT_NET_ISCSITARGET_H
     7
     8#include <ByteOrder.h>
     9#include <SupportDefs.h>
     10#include <util/kernel_cpp.h>
     11
     12#include <boot/platform.h>
     13#include <boot/stdio.h>
     14#include <boot/vfs.h>
     15#include <boot/net/NetDefs.h>
     16
     17#define ISCSI_PORT 3260
     18
     19// iSCSI Basic Header Segment (BHS) (RFC 3720 10.2.1)
     20
     21#define ISCSI_BHS_BYTE0         \
     22    bool reserved:1;            \
     23    bool immediateDelivery:1;   \
     24    uint8 opcode:6;
     25#define ISCSI_BHS_START         \
     26    ISCSI_BHS_BYTE0             \
     27    bool final:1;
     28#define ISCSI_BHS_LENGTHS       \
     29    uint8 totalAHSLength;       \
     30    uint32 dataSegmentLength:24;
     31#define ISCSI_BHS_TASK_TAG      \
     32    uint32 initiatorTaskTag;
     33#define ISCSI_BHS_TAGS      \
     34    ISCSI_BHS_TASK_TAG          \
     35    uint32 targetTransferTag;
     36
     37struct iscsi_basic_header_segment {
     38    ISCSI_BHS_START
     39    uint32 opcodeSpecific:23;
     40    ISCSI_BHS_LENGTHS
     41    uint64 lun;
     42    ISCSI_BHS_TASK_TAG
     43    uint8 opcodeSpecific2[28];
     44} __attribute__ ((__packed__));
     45
     46// initiator opcodes
     47#define ISCSI_OPCODE_NOP_OUT        0x00
     48#define ISCSI_OPCODE_SCSI_COMMAND   0x01
     49#define ISCSI_OPCODE_LOGIN_REQUEST  0x03
     50#define ISCSI_OPCODE_TEXT_REQUEST   0x04
     51#define ISCSI_OPCODE_LOGOUT_REQUEST 0x06
     52// target opcodes
     53#define ISCSI_OPCODE_NOP_IN             0x20
     54#define ISCSI_OPCODE_SCSI_RESPONSE      0x21
     55#define ISCSI_OPCODE_LOGIN_RESPONSE     0x23
     56#define ISCSI_OPCODE_TEXT_RESPONSE      0x24
     57#define ISCSI_OPCODE_LOGOUT_RESPONSE    0x26
     58
     59// SCSI Command (RFC 3720 10.3)
     60struct iscsi_scsi_command {
     61    iscsi_scsi_command()
     62        :
     63        reserved(0),
     64        opcode(ISCSI_OPCODE_SCSI_COMMAND),
     65        reserved2(0),
     66        reserved3(0)
     67    {
     68    }
     69    ISCSI_BHS_START
     70    bool r:1;
     71    bool w:1;
     72    uint8 reserved2:2;
     73    uint8 attr:3;
     74    uint16 reserved3;
     75    ISCSI_BHS_LENGTHS
     76    uint64 lun;
     77    ISCSI_BHS_TASK_TAG
     78    uint32 expectedDataTransferLength;
     79    uint32 cmdSN;
     80    uint32 expStatSN;
     81    uint8 cdb[16];
     82} __attribute__ ((__packed__));
     83
     84// SCSI Response (RFC 3720 10.4)
     85struct iscsi_scsi_response {
     86    ISCSI_BHS_START
     87    uint8 reserved2:2;
     88    bool o:1;
     89    bool u:1;
     90    bool O:1;
     91    bool U:1;
     92    bool reserved3:1;
     93    uint8 response;
     94    uint8 status;
     95    ISCSI_BHS_LENGTHS
     96    uint32 reserved4[2];
     97    ISCSI_BHS_TASK_TAG
     98    uint32 snackTag;
     99    uint32 statSN;
     100    uint32 expCmdSN;
     101    uint32 maxCmdSN;
     102    uint32 expDataSN;
     103    uint32 bidirectionalReadResidualCount;
     104    uint32 residualCount;
     105} __attribute__ ((__packed__));
     106
     107// Text Request (RFC 3720 10.10)
     108struct iscsi_text_request {
     109    iscsi_text_request()
     110        :
     111        reserved(0),
     112        opcode(ISCSI_OPCODE_TEXT_REQUEST),
     113        reserved2(2)
     114    {
     115        reserved3[0] = 0;
     116        reserved3[1] = 0;
     117        reserved3[2] = 0;
     118        reserved3[3] = 0;
     119    }
     120    ISCSI_BHS_START
     121    bool c:1; // continue
     122    uint32 reserved2:22;
     123    ISCSI_BHS_LENGTHS
     124    uint64 lun;
     125    ISCSI_BHS_TAGS
     126    uint32 cmdSN;
     127    uint32 expStatSN;
     128    uint32 reserved3[4];
     129} __attribute__ ((__packed__));
     130
     131// Text Response (RFC 3720 10.11)
     132struct iscsi_text_response {
     133    ISCSI_BHS_START
     134    bool c:1; // continue
     135    uint32 reserved2:22;
     136    ISCSI_BHS_LENGTHS
     137    uint64 lun;
     138    ISCSI_BHS_TAGS
     139    uint32 statSN;
     140    uint32 expCmdSN;
     141    uint32 maxCmdSN;
     142    uint32 reserved3[3];
     143} __attribute__ ((__packed__));
     144
     145struct iscsi_isid {
     146    uint8 t:2;
     147    uint8 a:6;
     148    uint16 b;
     149    uint8 c;
     150    uint16 d;
     151} __attribute__ ((__packed__));
     152
     153// Login Request (RFC 3720 10.12)
     154struct iscsi_login_request {
     155    iscsi_login_request()
     156        :
     157        reserved(false),
     158        immediateDelivery(1),
     159        opcode(ISCSI_OPCODE_LOGIN_REQUEST),
     160        reserved2(0),
     161        reserved3(0)
     162    {
     163        memset(reserved4, 0, sizeof(reserved4));
     164    }
     165
     166    ISCSI_BHS_BYTE0
     167    bool transit:1;
     168    bool c:1;                   // continue
     169    uint8 reserved2:2;
     170    uint8 currentStage:2;
     171    uint8 nextStage:2;
     172    uint8 versionMax;
     173    uint8 versionMin;
     174    ISCSI_BHS_LENGTHS
     175    iscsi_isid isid;
     176    uint16 tsih;
     177    ISCSI_BHS_TASK_TAG
     178    uint16 cid;
     179    uint16 reserved3;
     180    uint32 cmdSN;
     181    uint32 expStatSN;
     182    uint32 reserved4[4];
     183} __attribute__ ((__packed__));
     184
     185#define ISCSI_SESSION_STAGE_SECURITY_NEGOTIATION            0
     186#define ISCSI_SESSION_STAGE_LOGIN_OPERATIONAL_NEGOTIATION   1
     187#define ISCSI_SESSION_STAGE_FULL_FEATURE_PHASE              3
     188
     189#define ISCSI_VERSION 0x00
     190
     191#define ISCSI_ISID_OUI      0
     192#define ISCSI_ISID_EN       1
     193#define ISCSI_ISID_RANDOM   2
     194
     195// Login Response (RFC 3720 10.13)
     196struct iscsi_login_response {
     197    ISCSI_BHS_BYTE0
     198    bool transit:1;
     199    bool c:1;                   // continue
     200    uint8 reserved2:2;
     201    uint8 currentStage:2;
     202    uint8 nextStage:2;
     203    uint8 versionMax;
     204    uint8 versionActive;
     205    ISCSI_BHS_LENGTHS
     206    iscsi_isid isid;
     207    uint16 tsih;
     208    ISCSI_BHS_TASK_TAG
     209    uint32 reserved3;
     210    uint32 statSN;
     211    uint32 expCmdSN;
     212    uint32 maxCmdSN;
     213    uint8 statusClass;
     214    uint8 statusDetail;
     215    uint16 reserved4;
     216    uint32 reserved5[2];
     217} __attribute__ ((__packed__));
     218
     219// Logout Request (RFC 3720 10.14)
     220struct iscsi_logout_request {
     221    iscsi_logout_request()
     222        :
     223        reserved(0),
     224        opcode(ISCSI_OPCODE_LOGOUT_REQUEST),
     225        final(true),
     226        reserved2(0),
     227        reserved4(0)
     228    {
     229        reserved3[0] = 0;
     230        reserved3[1] = 0;
     231        reserved5[0] = 0;
     232        reserved5[1] = 0;
     233        reserved5[2] = 0;
     234        reserved5[3] = 0;
     235    }
     236    ISCSI_BHS_START
     237    uint8 reasonCode:7;
     238    uint16 reserved2;
     239    ISCSI_BHS_LENGTHS
     240    uint32 reserved3[2];
     241    ISCSI_BHS_TASK_TAG
     242    uint16 cid;
     243    uint16 reserved4;
     244    uint32 cmdSN;
     245    uint32 expStatSN;
     246    uint32 reserved5[4];
     247} __attribute__ ((__packed__));
     248
     249#define ISCSI_LOGOUT_REASON_CLOSE_SESSION       0
     250#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION    1
     251#define ISCSI_LOGOUT_REASON_REMOVE_CONNECTION   2
     252
     253// Logout Response (RFC 3720 10.15)
     254struct iscsi_logout_response {
     255    ISCSI_BHS_START
     256    uint8 reserved2:7;
     257    uint8 response;
     258    uint8 reserved3;
     259    ISCSI_BHS_LENGTHS
     260    uint32 reserved4[2];
     261    ISCSI_BHS_TASK_TAG
     262    uint32 reserved5;
     263    uint32 statSN;
     264    uint32 expCmdSN;
     265    uint32 maxCmdSN;
     266    uint32 reserved6;
     267    uint16 time2Wait;
     268    uint16 time2Remain;
     269    uint32 reserved7;
     270} __attribute__ ((__packed__));
     271
     272class TCPSocket;
     273
     274class iSCSISession;
     275
     276class iSCSIConnection {
     277public:
     278    iSCSIConnection();
     279    virtual ~iSCSIConnection();
     280
     281    status_t Init(iSCSISession* session);
     282    status_t Open(ip_addr_t address, uint16 port);
     283    status_t Login(const char* targetName = NULL, char** targetAlias = NULL);
     284    status_t Logout(bool closeSession = false);
     285    status_t GetText(const char* request, size_t requestLength, char** response, size_t* responseLength);
     286    status_t SendCommand(const void* command, size_t commandSize,
     287        bool r, bool w, uint32 expectedDataTransferLength,
     288        void** response, size_t* responseLength);
     289    status_t ReadData();
     290
     291    bool Active() const { return fConnected; }
     292
     293private:
     294    status_t _ReadResponse(void* buffer, size_t bufferSize, size_t* bytesRead, bigtime_t timeout = 100000LL);
     295
     296    iSCSISession* fSession;
     297    TCPSocket* fSocket;
     298    bool fConnected;
     299    uint16 fConnectionID;
     300    uint32 fStatusSequenceNumber;
     301};
     302
     303class iSCSISession {
     304public:
     305    iSCSISession(const char* targetName = NULL);
     306    virtual ~iSCSISession();
     307
     308    status_t Init(ip_addr_t address, uint16 port, char** targetAlias = NULL);
     309    status_t Close();
     310
     311    uint32 CommandSequenceNumber() const { return fCommandSequenceNumber; }
     312    uint32 NextCommandSequenceNumber() { return fCommandSequenceNumber++; }
     313    iSCSIConnection* Connection() const { return fConnection; }
     314
     315    bool Active() { return fConnection != NULL && fConnection->Active(); }
     316
     317private:
     318    bool fDiscovery;
     319    const char* fTargetName;
     320    uint32 fCommandSequenceNumber;
     321    iSCSIConnection* fConnection;//XXX should be multiple
     322};
     323
     324class iSCSITarget : public Node {
     325public:
     326    iSCSITarget();
     327    virtual ~iSCSITarget();
     328    status_t Init(ip_addr_t address, uint16 port, const char* targetName);
     329
     330    virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
     331        size_t bufferSize);
     332    virtual ssize_t WriteAt(void* cookie, off_t pos, const void* buffer,
     333        size_t bufferSize);
     334
     335    virtual status_t GetName(char* buffer, size_t bufferSize) const;
     336    virtual off_t Size() const;
     337
     338    static bool DiscoverTargets(ip_addr_t address, uint16 port,
     339        void (*targetCallback)(Node* node, void* opaque), void* opaque);
     340    static bool _AddDevice(ip_addr_t address, uint16 port,
     341        const char* targetName,
     342        void (*callback)(Node* node, void* opaque), void* opaque);
     343
     344private:
     345    iSCSISession* fSession;
     346    char* fTargetName;
     347    char* fTargetAlias;
     348    uint32 fLastLBA;
     349    uint32 fBlockSize;
     350};
     351
     352#endif
  • src/system/boot/loader/net/Jamfile

    diff --git a/src/system/boot/loader/net/Jamfile b/src/system/boot/loader/net/Jamfile
    index 8555a7d..a0c54b2 100644
    a b  
    11SubDir HAIKU_TOP src system boot loader net ;
    22
    33UsePrivateHeaders kernel [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
     4UsePrivateHeaders drivers ;
    45
    56SubDirC++Flags -fno-rtti ;
    67
    KernelStaticLibrary boot_net :  
    1314    NetStack.cpp
    1415    RemoteDisk.cpp
    1516    UDP.cpp
    1617    TCP.cpp
     18    iSCSITarget.cpp
    1719
    1820    : -fno-pic
    1921;
  • new file src/system/boot/loader/net/iSCSITarget.cpp

    diff --git a/src/system/boot/loader/net/iSCSITarget.cpp b/src/system/boot/loader/net/iSCSITarget.cpp
    new file mode 100644
    index 0000000..bf4734b
    - +  
     1/*
     2 * Copyright 2010, Andreas Faerber <andreas.faerber@web.de>
     3 * All rights reserved. Distributed under the terms of the MIT License.
     4 */
     5
     6#include <boot/net/iSCSITarget.h>
     7
     8#include <stdio.h>
     9#include <string.h>
     10#include <ctype.h>
     11#include <KernelExport.h>
     12
     13#include <boot/net/ChainBuffer.h>
     14#include <boot/net/TCP.h>
     15#include <scsi_cmds.h>
     16
     17
     18
     19#define ISCSI_ALIGNMENT 4
     20#define ISCSI_ALIGN(x) (((x) + ISCSI_ALIGNMENT - 1) & ~(ISCSI_ALIGNMENT - 1))
     21#define ISCSI_PADDING(x) ((((x) % ISCSI_ALIGNMENT) == 0) ? 0 \
     22    : (ISCSI_ALIGNMENT - ((x) % ISCSI_ALIGNMENT)))
     23
     24// derived from the schedulers
     25static int
     26_rand(void)
     27{
     28    static int next = 0;
     29    if (next == 0)
     30        next = system_time();
     31
     32    next = next * 1103515245 + 12345;
     33    return next;
     34}
     35
     36
     37bool
     38iSCSITarget::DiscoverTargets(ip_addr_t address, uint16 port,
     39    void (*targetCallback)(Node* node, void* opaque), void* opaque)
     40{
     41    iSCSISession* session = new(nothrow) iSCSISession();
     42    if (session == NULL)
     43        return false;
     44    status_t error = session->Init(address, port);
     45    if (error != B_OK) {
     46        delete session;
     47        return false;
     48    }
     49    const char* request = "SendTargets=All";
     50    char* sendTargets = NULL;
     51    size_t sendTargetsLength = 0;
     52    error = session->Connection()->GetText(request, strlen(request) + 1,
     53        &sendTargets, &sendTargetsLength);
     54    session->Close();
     55    delete session;
     56    if (error != B_OK) {
     57        return false;
     58    }
     59    bool addedDisk = false;
     60    char* targetName = NULL;
     61    bool seenAddress = false;
     62    for (char* pair = sendTargets; pair < sendTargets + sendTargetsLength;
     63            pair += strlen(pair) + 1) {
     64        printf("%s\n", pair);
     65        if (strncmp(pair, "TargetName=", strlen("TargetName=")) == 0) {
     66            if (targetName != NULL && !seenAddress) {
     67                if (_AddDevice(address, port, targetName, targetCallback, opaque))
     68                    addedDisk = true;
     69            }
     70            seenAddress = false;
     71            targetName = pair + strlen("TargetName=");
     72        } else if (strncmp(pair, "TargetAddress=", strlen("TargetAddress="))
     73                == 0) {
     74            seenAddress = true;
     75            char* targetAddress = pair + strlen("TargetAddress=");
     76            char* comma = strrchr(targetAddress, ',');
     77            int addressLength = comma - targetAddress;
     78            targetAddress = strndup(targetAddress, addressLength);
     79            uint16 targetPort = ISCSI_PORT;
     80            char* colon = strrchr(targetAddress, ':');
     81            if (colon != NULL) {
     82                // colon could be part of an IPv6 address, e.g. [::1.2.3.4]
     83                char* bracket = strrchr(targetAddress, ']');
     84                if (bracket == NULL || bracket < colon) {
     85                    targetPort = strtol(colon + 1, NULL, 10);
     86                    colon[0] = '\0';
     87                }
     88            }
     89            if (targetName != NULL && isdigit(targetAddress[0])) {
     90                if (_AddDevice(ip_parse_address(targetAddress), targetPort,
     91                        targetName, targetCallback, opaque))
     92                    addedDisk = true;
     93            }
     94            free(targetAddress);
     95        }
     96    }
     97    if (targetName != NULL && !seenAddress) {
     98        if (_AddDevice(address, port, targetName, targetCallback, opaque))
     99            addedDisk = true;
     100    }
     101    free(sendTargets);
     102    return addedDisk;
     103}
     104
     105
     106bool
     107iSCSITarget::_AddDevice(ip_addr_t address, uint16 port,
     108    const char* targetName, void (*callback)(Node* node, void* opaque),
     109    void* opaque)
     110{
     111    printf("=> %s @ %08lx:%u\n", targetName, address, port);
     112    iSCSITarget* disk = new(nothrow) iSCSITarget();
     113    if (disk == NULL)
     114        return false;
     115    status_t error = disk->Init(address, port, targetName);
     116    if (error != B_OK) {
     117        delete disk;
     118        return false;
     119    }
     120    printf("disk size = %llu\n", disk->Size());
     121    callback(disk, opaque);
     122    return true;
     123}
     124
     125
     126iSCSITarget::iSCSITarget()
     127    :
     128    fSession(NULL),
     129    fTargetName(NULL),
     130    fTargetAlias(NULL)
     131{
     132}
     133
     134
     135iSCSITarget::~iSCSITarget()
     136{
     137    free(fTargetName);
     138    free(fTargetAlias);
     139    delete fSession;
     140}
     141
     142
     143status_t
     144iSCSITarget::Init(ip_addr_t address, uint16 port, const char* targetName)
     145{
     146    fTargetName = strdup(targetName);
     147    if (fTargetName == NULL)
     148        return B_NO_MEMORY;
     149
     150    fSession = new(nothrow) iSCSISession(fTargetName);
     151    if (fSession == NULL)
     152        return B_NO_MEMORY;
     153    status_t error = fSession->Init(address, port, &fTargetAlias);
     154    if (error != B_OK)
     155        return error;
     156    if (targetName == NULL)
     157        return B_OK;
     158
     159    scsi_cmd_read_capacity cmd;
     160    memset(&cmd, 0, sizeof(cmd));
     161    cmd.opcode = SCSI_OP_READ_CAPACITY;
     162    cmd.relative_address = 0;
     163    cmd.lun = 0;
     164    cmd.lba = 0;
     165    cmd.pmi = 0;
     166    cmd.control = 0;
     167    scsi_res_read_capacity* resp;
     168    size_t respLength;
     169    error = fSession->Connection()->SendCommand(&cmd, sizeof(cmd),
     170        false, false, 0,
     171        (void**)&resp, &respLength);
     172    if (error != B_OK)
     173        return error;
     174    printf("lba = %lu, block size = %lu\n", resp->lba, resp->block_size);
     175    fLastLBA = resp->lba;
     176    fBlockSize = resp->block_size;
     177    return B_OK;
     178}
     179
     180
     181ssize_t
     182iSCSITarget::ReadAt(void* /*cookie*/, off_t pos, void* buffer, size_t bufferSize)
     183{
     184    printf("!!!! iSCSITarget::ReadAt(): size = %lu\n", bufferSize);
     185    fSession->Connection()->ReadData();
     186
     187    scsi_cmd_rw_12 cmd;
     188    memset(&cmd, 0, sizeof(cmd));
     189    cmd.opcode = SCSI_OP_READ_12;
     190    cmd.relative_address = 0;
     191    cmd.force_unit_access = 0;
     192    cmd.disable_page_out = 0;
     193    cmd.lun = 0;
     194    cmd.lba = pos / fBlockSize;
     195    cmd.length = bufferSize;
     196    cmd.control = 0;
     197    void* resp;
     198    size_t respLength;
     199    status_t error = fSession->Connection()->SendCommand(&cmd, sizeof(cmd),
     200        true, false, cmd.length, &resp, &respLength);
     201    if (error != B_OK)
     202        return error;
     203    printf("====> length = %lu\n", respLength);
     204   
     205    error = fSession->Connection()->ReadData();
     206    return B_PERMISSION_DENIED;
     207}
     208
     209
     210ssize_t
     211iSCSITarget::WriteAt(void* /*cookie*/, off_t pos, const void* buffer, size_t bufferSize)
     212{
     213    return B_PERMISSION_DENIED;
     214}
     215
     216
     217status_t
     218iSCSITarget::GetName(char* buffer, size_t bufferSize) const
     219{
     220    if (buffer == NULL)
     221        return B_BAD_VALUE;
     222
     223    snprintf(buffer, bufferSize, "iSCSI:%s", fTargetName);
     224
     225    return B_OK;
     226}
     227
     228
     229off_t
     230iSCSITarget::Size() const
     231{
     232    return fLastLBA * fBlockSize;
     233}
     234
     235
     236iSCSISession::iSCSISession(const char* targetName)
     237    :
     238    fDiscovery(targetName == NULL),
     239    fTargetName(targetName),
     240    fConnection(NULL)
     241{
     242    fCommandSequenceNumber = _rand();
     243}
     244
     245
     246iSCSISession::~iSCSISession()
     247{
     248    if (Active())
     249        Close();
     250    delete fConnection;
     251}
     252
     253
     254status_t
     255iSCSISession::Init(ip_addr_t address, uint16 port, char** targetAlias)
     256{
     257    fConnection = new(nothrow) iSCSIConnection();
     258    if (fConnection == NULL)
     259        return B_NO_MEMORY;
     260    status_t error = fConnection->Init(this);
     261    if (error != B_OK)
     262        return error;
     263    error = fConnection->Open(address, port);
     264    if (error != B_OK)
     265        return error;
     266    error = fConnection->Login(fTargetName, targetAlias);
     267    if (error != B_OK)
     268        return error;
     269    return B_OK;
     270}
     271
     272
     273status_t
     274iSCSISession::Close()
     275{
     276    if (fConnection == NULL)
     277        return B_NO_INIT;
     278
     279    status_t error = fConnection->Logout(true);
     280    if (error != B_OK)
     281        return error;
     282    return B_OK;
     283}
     284
     285
     286iSCSIConnection::iSCSIConnection()
     287    :
     288    fSession(NULL),
     289    fSocket(NULL),
     290    fConnected(false),
     291    fConnectionID(0)
     292{
     293}
     294
     295
     296iSCSIConnection::~iSCSIConnection()
     297{
     298    if (fSocket != NULL && fConnected) {
     299        if (Logout() != B_OK)
     300            fSocket->Close();
     301    }
     302    delete fSocket;
     303}
     304
     305
     306status_t
     307iSCSIConnection::Init(iSCSISession* session)
     308{
     309    fSession = session;
     310    return B_OK;
     311}
     312
     313status_t
     314iSCSIConnection::Open(ip_addr_t address, uint16 port)
     315{
     316    fSocket = new(nothrow) TCPSocket();
     317    if (fSocket == NULL)
     318        return B_NO_MEMORY;
     319    printf("iSCSI initiator connecting to target...\n");
     320    status_t error = fSocket->Connect(address, port);
     321    if (error != B_OK)
     322        return error;
     323    fConnected = true;
     324    printf("connected.\n");
     325    fConnectionID = _rand();
     326    return B_OK;
     327}
     328
     329
     330status_t
     331iSCSIConnection::Login(const char* targetName, char** targetAlias)
     332{
     333    char data[256];
     334    size_t dataLength = 0;
     335    const char* keyValue;
     336    keyValue = "InitiatorName=iqn.2002-10.org.haiku-os:haiku.bootloader.hostX";
     337    strcpy(data + dataLength, keyValue);
     338    dataLength += strlen(keyValue) + 1;
     339    if (targetName != NULL) {
     340        dataLength += sprintf(data + dataLength, "TargetName=%s", targetName) + 1;
     341    } else {
     342        keyValue = "SessionType=Discovery";
     343        strcpy(data + dataLength, keyValue);
     344        dataLength += strlen(keyValue) + 1;
     345    }
     346
     347    iscsi_login_request req;
     348    req.transit = true;
     349    req.c = false;
     350    req.currentStage = ISCSI_SESSION_STAGE_LOGIN_OPERATIONAL_NEGOTIATION;
     351    req.nextStage    = ISCSI_SESSION_STAGE_FULL_FEATURE_PHASE;
     352    req.versionMax = ISCSI_VERSION;
     353    req.versionMin = ISCSI_VERSION;
     354    req.totalAHSLength = 0;
     355    req.dataSegmentLength = dataLength;
     356    printf("data segment length = %lu\n", req.dataSegmentLength);
     357    req.isid.t = ISCSI_ISID_RANDOM;
     358    req.isid.a = 0;
     359    uint32 random = _rand();
     360    req.isid.b = random >> 8;
     361    req.isid.c = random & 0xff;
     362    req.isid.d = _rand();
     363    req.tsih = 0;
     364    req.initiatorTaskTag = _rand();
     365    req.cid = fConnectionID;
     366    req.cmdSN = fSession->CommandSequenceNumber();
     367    req.expStatSN = 0;
     368    status_t error = fSocket->Write(&req, sizeof(req));
     369    if (error != B_OK) {
     370        return error;
     371    }
     372    for (unsigned int i = dataLength; i < ISCSI_ALIGN(dataLength); i++)
     373        data[i] = '\0';
     374    dataLength = ISCSI_ALIGN(dataLength);
     375    printf("data length = %lu\n", dataLength);
     376    error = fSocket->Write(data, dataLength);
     377    if (error != B_OK) {
     378        printf("write error\n");
     379        return error;
     380    }
     381    printf("iSCSI login request sent.\n");
     382
     383    iscsi_login_response resp;
     384    size_t bytesRead = 0;
     385    error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
     386    if (error != B_OK) {
     387        printf("iSCSI login response read error\n");
     388        return error;
     389    }
     390    printf("bytesRead = %lu\n", bytesRead);
     391    printf("iSCSI login response: opcode = %x, status class = %u, status detail = %u, transit = %u, data length = %lu\n",
     392        resp.opcode, resp.statusClass, resp.statusDetail, resp.transit, resp.dataSegmentLength);
     393    if (resp.dataSegmentLength > 0) {
     394        error = fSocket->Read(data, resp.dataSegmentLength, &bytesRead, 1000000LL);
     395        if (error != B_OK) {
     396            printf("iSCSI login response data read error\n");
     397            return error;
     398        }
     399        printf("bytesRead = %lu\n", bytesRead);
     400        if (resp.dataSegmentLength % ISCSI_ALIGNMENT) {
     401            error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 100000LL);
     402            if (error != B_OK) {
     403                printf("iSCSI login response padding read error\n");
     404                return error;
     405            }
     406            printf("bytesRead = %lu\n", bytesRead);
     407        }
     408        for (char* pair = data; pair < data + resp.dataSegmentLength; pair += strlen(pair) + 1) {
     409            printf("%s\n", pair);
     410            if (targetAlias != NULL && strncmp(pair, "TargetAlias=", strlen("TargetAlias=")) == 0) {
     411                *targetAlias = strdup(pair + strlen("TargetAlias="));
     412            }
     413        }
     414    }
     415    fStatusSequenceNumber = resp.statSN;
     416    if (resp.statusClass != 0) {
     417        printf("iSCSI login response indicates failure.\n");
     418        return B_BAD_VALUE;
     419    }
     420    return B_OK;
     421}
     422
     423
     424status_t
     425iSCSIConnection::Logout(bool closeSession)
     426{
     427    iscsi_logout_request req;
     428    printf("req size = %lu\n", sizeof(req));
     429    req.immediateDelivery = true;
     430    req.reasonCode = closeSession ? ISCSI_LOGOUT_REASON_CLOSE_SESSION
     431        : ISCSI_LOGOUT_REASON_CLOSE_CONNECTION;
     432    req.totalAHSLength = 0;
     433    req.dataSegmentLength = 0;
     434    req.initiatorTaskTag = _rand();
     435    req.cid = closeSession ? 0 : fConnectionID;
     436    req.cmdSN = fSession->CommandSequenceNumber();
     437    req.expStatSN = fStatusSequenceNumber;
     438    status_t error = fSocket->Write(&req, sizeof(req));
     439    if (error != B_OK) {
     440        printf("iSCSI logout request write error\n");
     441        return error;
     442    }
     443    printf("iSCSI logout request sent.\n");
     444
     445    iscsi_logout_response resp;
     446    printf("resp size = %lu\n", sizeof(resp));
     447    size_t bytesRead = 0;
     448    error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
     449    if (error != B_OK) {
     450        printf("iSCSI logout response read error\n");
     451        return error;
     452    }
     453    printf("bytesRead = %lu\n", bytesRead);
     454    printf("iSCSI logout response: opcode = %x, response = %u\n",
     455        resp.opcode, resp.response);
     456    fStatusSequenceNumber = resp.statSN;
     457    if (resp.response != 0) {
     458        printf("iSCSI logout response indicates failure.\n");
     459        return error;
     460    }
     461
     462    fSocket->Close();
     463    fConnected = false;
     464    printf("disconnected\n");
     465    return B_OK;
     466}
     467
     468
     469status_t
     470iSCSIConnection::GetText(const char* request, size_t requestLength, char** response, size_t* responseLength)
     471{
     472    iscsi_text_request req;
     473    req.immediateDelivery = true;
     474    req.final = true;
     475    req.c = false;
     476    req.totalAHSLength = 0;
     477    req.dataSegmentLength = requestLength;
     478    req.lun = 0;
     479    req.initiatorTaskTag = _rand();
     480    req.targetTransferTag = 0xffffffffL;
     481    req.cmdSN = fSession->NextCommandSequenceNumber();
     482    req.expStatSN = fStatusSequenceNumber;
     483    status_t error = fSocket->Write(&req, sizeof(req));
     484    if (error != B_OK) {
     485        printf("iSCSI text request write error\n");
     486        return error;
     487    }
     488    error = fSocket->Write(request, requestLength);
     489    if (error != B_OK) {
     490        printf("iSCSI text request data write error\n");
     491        return error;
     492    }
     493    if (requestLength % ISCSI_ALIGNMENT != 0) {
     494        char buffer[3];
     495        memset(buffer, 0, 3);
     496        error = fSocket->Write(buffer, ISCSI_ALIGNMENT - (requestLength % ISCSI_ALIGNMENT));
     497        if (error != B_OK) {
     498            printf("iSCSI text request padding write error\n");
     499            return error;
     500        }
     501    }
     502    printf("iSCSI text request sent.\n");
     503
     504    iscsi_logout_response resp;
     505    printf("resp size = %lu\n", sizeof(resp));
     506    size_t bytesRead = 0;
     507    error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
     508    if (error != B_OK) {
     509        printf("iSCSI text response read error\n");
     510        return error;
     511    }
     512    printf("bytesRead = %lu\n", bytesRead);
     513    printf("iSCSI text response: opcode = %x\n",
     514        resp.opcode);
     515    *response = (char*)malloc(resp.dataSegmentLength);
     516    if (*response == NULL)
     517        return B_NO_MEMORY;
     518    error = fSocket->Read(*response, resp.dataSegmentLength, &bytesRead, 10000000LL);
     519    if (error != B_OK) {
     520        printf("iSCSI text response read error\n");
     521        return error;
     522    }
     523    printf("bytesRead = %lu\n", bytesRead);
     524    *responseLength = resp.dataSegmentLength;
     525    if (resp.dataSegmentLength % ISCSI_ALIGNMENT != 0) {
     526        error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 1000000LL);
     527        if (error != B_OK) {
     528            printf("iSCSI text response padding read error\n");
     529            return error;
     530        }
     531    }
     532    fStatusSequenceNumber = resp.statSN;
     533   
     534    return B_OK;
     535}
     536
     537
     538status_t
     539iSCSIConnection::SendCommand(const void* command, size_t commandSize,
     540    bool r, bool w, uint32 expectedDataTransferLength,
     541    void** response, size_t* responseLength)
     542{
     543    printf("iSCSIConnection::SendCommand(): command size = %lu\n", commandSize);
     544    iscsi_scsi_command req;
     545    printf("req size = %lu\n", sizeof(req));
     546    req.immediateDelivery = true;
     547    req.final = true;
     548    req.r = r;
     549    req.w = w;
     550    req.attr = 0;
     551    req.totalAHSLength = 0;
     552    req.dataSegmentLength = 0;
     553    req.lun = 0;
     554    req.initiatorTaskTag = _rand();
     555    req.expectedDataTransferLength = expectedDataTransferLength;
     556    req.cmdSN = fSession->NextCommandSequenceNumber();
     557    req.expStatSN = fStatusSequenceNumber;
     558    if (commandSize > 16)
     559        memset(req.cdb, 0, 16);
     560    memcpy(req.cdb, command, commandSize <= 16 ? commandSize : 16);
     561    status_t error = fSocket->Write(&req, sizeof(req));
     562    if (error != B_OK) {
     563        printf("iSCSI SCSI command write error\n");
     564        return error;
     565    }
     566    printf("iSCSI SCSI command sent.\n");
     567
     568    iscsi_scsi_response resp;
     569    printf("resp size = %lu\n", sizeof(resp));
     570    size_t bytesRead = 0;
     571    error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
     572    if (error != B_OK) {
     573        printf("iSCSI SCSI response read error\n");
     574        return error;
     575    }
     576    printf("bytesRead = %lu\n", bytesRead);
     577    printf("iSCSI SCSI response: opcode = %x, response = %x, status = %x, AHS length = %x\n",
     578        resp.opcode, resp.response, resp.status, resp.totalAHSLength);
     579    if (resp.dataSegmentLength > 0) {
     580        *response = malloc(resp.dataSegmentLength);
     581        if (*response == NULL)
     582            return B_NO_MEMORY;
     583        error = fSocket->Read(*response, resp.dataSegmentLength, &bytesRead, 10000000LL);
     584        if (error != B_OK) {
     585            printf("iSCSI text response read error\n");
     586            return error;
     587        }
     588        printf("bytesRead = %lu\n", bytesRead);
     589    }
     590    *responseLength = resp.dataSegmentLength;
     591    if (resp.dataSegmentLength % ISCSI_ALIGNMENT != 0) {
     592        error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 1000000LL);
     593        if (error != B_OK) {
     594            printf("iSCSI SCSI response padding read error\n");
     595            return error;
     596        }
     597    }
     598    if (resp.response != 0x00 || resp.status != SCSI_STATUS_GOOD)
     599        return B_BAD_VALUE;
     600
     601    return B_OK;
     602}
     603
     604
     605status_t
     606iSCSIConnection::ReadData()
     607{
     608    iscsi_basic_header_segment resp;
     609    size_t bytesRead = 0;
     610    status_t error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
     611    if (error != B_OK) {
     612        printf("iSCSI SCSI response read error\n");
     613        return error;
     614    }
     615    printf("bytesRead = %lu\n", bytesRead);
     616    printf("iSCSI response: opcode = %x, AHS length = %u, data length = %lu\n",
     617        resp.opcode, resp.totalAHSLength, resp.dataSegmentLength);
     618    if (resp.totalAHSLength > 0) {
     619        error = fSocket->Read(NULL, resp.totalAHSLength, &bytesRead, 1000000LL);
     620        if (error != B_OK) {
     621            printf("iSCSI response header read error\n");
     622            return error;
     623        }
     624        printf("bytesRead = %lu\n", bytesRead);
     625    }
     626    if (resp.dataSegmentLength > 0) {
     627        error = fSocket->Read(NULL, resp.dataSegmentLength, &bytesRead, 1000000LL);
     628        if (error != B_OK) {
     629            printf("iSCSI response data read error\n");
     630            return error;
     631        }
     632        printf("bytesRead = %lu\n", bytesRead);
     633    }
     634    if (resp.dataSegmentLength % ISCSI_ALIGNMENT != 0) {
     635        error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 1000000LL);
     636        if (error != B_OK) {
     637            printf("iSCSI SCSI response padding read error\n");
     638            return error;
     639        }
     640    }
     641    return B_OK;
     642}
     643
     644
     645status_t
     646iSCSIConnection::_ReadResponse(void* buffer, size_t bufferSize, size_t* bytesRead, bigtime_t timeout)
     647{
     648    // assuming bufferSize >= 48
     649    status_t error = fSocket->Read(buffer, bufferSize, bytesRead, timeout);
     650    if (error != B_OK)
     651        return error;
     652    //if (*bytesRead >= 1)
     653    return error;
     654}
  • src/system/boot/platform/openfirmware/devices.cpp

    diff --git a/src/system/boot/platform/openfirmware/devices.cpp b/src/system/boot/platform/openfirmware/devices.cpp
    index 601ac50..4eb00c0 100644
    a b  
    1212#include <boot/stage2.h>
    1313#include <boot/net/NetStack.h>
    1414#include <boot/net/RemoteDisk.h>
     15#include <boot/net/IP.h>
     16#include <boot/net/iSCSITarget.h>
    1517#include <platform/openfirmware/devices.h>
    1618#include <platform/openfirmware/openfirmware.h>
    1719#include <util/kernel_cpp.h>
     
    2224char sBootPath[192];
    2325
    2426
     27static void
     28iscsi_add_boot_device(Node* node, void* opaque)
     29{
     30    NodeList* devicesList = static_cast<NodeList*>(opaque);
     31    //devicesList->Add(node);
     32
     33    uint8 buffer[512];
     34    node->ReadAt(NULL, 0, buffer, sizeof(buffer));
     35    of_exit();
     36}
     37
    2538status_t
    2639platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
    2740{
    platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)  
    4558            status_t error = net_stack_init();
    4659            if (error != B_OK)
    4760                return error;
    48        
     61
     62            bool foundDisk = false;
     63            ip_addr_t bootAddress = 0;
     64            char* bootArgs = strrchr(sBootPath, ':');
     65            if (bootArgs != NULL) {
     66                bootArgs++;
     67                char* comma = strchr(bootArgs, ',');
     68                if (comma != NULL && comma - bootArgs > 0) {
     69                    comma[0] = '\0';
     70                    bootAddress = ip_parse_address(bootArgs);
     71                    comma[0] = ',';
     72                }
     73            }
     74            if (bootAddress == 0) {
     75                int package = of_finddevice("/options");
     76                char defaultServerIP[16];
     77                int bytesRead = of_getprop(package, "default-server-ip",
     78                    defaultServerIP, sizeof(defaultServerIP) - 1);
     79                if (bytesRead != OF_FAILED && bytesRead > 1) {
     80                    defaultServerIP[bytesRead] = '\0';
     81                    bootAddress = ip_parse_address(defaultServerIP);
     82                }
     83            }
     84
     85            if (bootAddress != 0) {
     86                if (iSCSITarget::DiscoverTargets(bootAddress, ISCSI_PORT,
     87                        iscsi_add_boot_device, devicesList))
     88                    foundDisk = true;
     89                //of_exit();//XXX
     90            }
     91
    4992            // init a remote disk, if possible
    5093            RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
    51             if (!remoteDisk)
    52                 return B_ENTRY_NOT_FOUND;
     94            if (remoteDisk)
     95                devicesList->Add(remoteDisk);
    5396
    54             devicesList->Add(remoteDisk);
    55             return B_OK;
     97            return foundDisk ? B_OK : B_ENTRY_NOT_FOUND;
    5698        }
    5799
    58100        if (strcmp("block", type) != 0) {