haiku_loader: Toss iSCSITarget, add TCP stack to loader.
* This iSCSI implementation only worked on PPC big-endian atm. * We're pretty sure iSCSI support in haiku_loader doesn't make much sense anymore. iPXE on (on arm,x86,etc EFI/BIOS platforms) supports iSCSI boot of disks. * Haiku could use a iSCSI driver add-on, but it would exist much higher up and likely use standard drivers vs bare-minimum iSCSI target impementations. * Leaving TCP and adding to all arches since it could make sense for haiku's native network disk subsystem or network debugging? Change-Id: Ic181b93a1d8ffd77f69e00e372b44b79abbddb42 Reviewed-on: https://review.haiku-os.org/c/899 Reviewed-by: Alex von Gluck IV <kallisti5@unixzen.com> Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
parent
c3c2596d9b
commit
cf77ef1857
@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, Andreas Färber <andreas.faerber@web.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef ISCSI_CMDS_H
|
||||
#define ISCSI_CMDS_H
|
||||
|
||||
|
||||
#include <ByteOrder.h>
|
||||
|
||||
|
||||
// TODO Add Little Endian support by introducing more macros
|
||||
#if __BYTE_ORDER != __BIG_ENDIAN
|
||||
#error Only Big Endian systems supported yet.
|
||||
#endif
|
||||
|
||||
|
||||
// iSCSI Basic Header Segment (BHS) (RFC 3720 10.2.1)
|
||||
|
||||
#define ISCSI_BHS_BYTE0 \
|
||||
bool reserved : 1; \
|
||||
bool immediateDelivery : 1; \
|
||||
uint8 opcode : 6;
|
||||
|
||||
// TODO This macro is LE-incompatible
|
||||
#define ISCSI_BHS_START \
|
||||
ISCSI_BHS_BYTE0 \
|
||||
bool final : 1;
|
||||
|
||||
#define ISCSI_BHS_LENGTHS \
|
||||
uint8 totalAHSLength; \
|
||||
uint32 dataSegmentLength : 24;
|
||||
|
||||
#define ISCSI_BHS_TASK_TAG \
|
||||
uint32 initiatorTaskTag;
|
||||
|
||||
#define ISCSI_BHS_TAGS \
|
||||
ISCSI_BHS_TASK_TAG \
|
||||
uint32 targetTransferTag;
|
||||
|
||||
struct iscsi_basic_header_segment {
|
||||
ISCSI_BHS_START
|
||||
uint32 opcodeSpecific : 23;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint8 opcodeSpecific2[28];
|
||||
} _PACKED;
|
||||
|
||||
// initiator opcodes
|
||||
#define ISCSI_OPCODE_NOP_OUT 0x00
|
||||
#define ISCSI_OPCODE_SCSI_COMMAND 0x01
|
||||
#define ISCSI_OPCODE_LOGIN_REQUEST 0x03
|
||||
#define ISCSI_OPCODE_TEXT_REQUEST 0x04
|
||||
#define ISCSI_OPCODE_LOGOUT_REQUEST 0x06
|
||||
// target opcodes
|
||||
#define ISCSI_OPCODE_NOP_IN 0x20
|
||||
#define ISCSI_OPCODE_SCSI_RESPONSE 0x21
|
||||
#define ISCSI_OPCODE_LOGIN_RESPONSE 0x23
|
||||
#define ISCSI_OPCODE_TEXT_RESPONSE 0x24
|
||||
#define ISCSI_OPCODE_SCSI_DATA_IN 0x25
|
||||
#define ISCSI_OPCODE_LOGOUT_RESPONSE 0x26
|
||||
|
||||
// SCSI Command (RFC 3720 10.3)
|
||||
struct iscsi_scsi_command {
|
||||
iscsi_scsi_command()
|
||||
:
|
||||
reserved(0),
|
||||
opcode(ISCSI_OPCODE_SCSI_COMMAND),
|
||||
reserved2(0),
|
||||
reserved3(0)
|
||||
{
|
||||
}
|
||||
ISCSI_BHS_START
|
||||
bool r : 1;
|
||||
bool w : 1;
|
||||
uint8 reserved2 : 2;
|
||||
uint8 attr : 3;
|
||||
uint16 reserved3;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint32 expectedDataTransferLength;
|
||||
uint32 cmdSN;
|
||||
uint32 expStatSN;
|
||||
uint8 cdb[16];
|
||||
} _PACKED;
|
||||
|
||||
// SCSI Response (RFC 3720 10.4)
|
||||
struct iscsi_scsi_response {
|
||||
ISCSI_BHS_START
|
||||
uint8 reserved2 : 2;
|
||||
bool o : 1;
|
||||
bool u : 1;
|
||||
bool O : 1;
|
||||
bool U : 1;
|
||||
bool reserved3 : 1;
|
||||
uint8 response;
|
||||
uint8 status;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint32 reserved4[2];
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint32 snackTag;
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint32 expDataSN;
|
||||
uint32 bidirectionalReadResidualCount;
|
||||
uint32 residualCount;
|
||||
} _PACKED;
|
||||
|
||||
// SCSI Data-In (RFC 3270 10.7)
|
||||
struct iscsi_scsi_data_in {
|
||||
ISCSI_BHS_START
|
||||
bool acknowledge : 1;
|
||||
uint8 reserved2 : 3;
|
||||
bool O : 1;
|
||||
bool U : 1;
|
||||
bool S : 1;
|
||||
uint8 reserved3;
|
||||
uint8 status;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TAGS
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint32 dataSN;
|
||||
uint32 bufferOffset;
|
||||
uint32 residualCount;
|
||||
} _PACKED;
|
||||
|
||||
// Text Request (RFC 3720 10.10)
|
||||
struct iscsi_text_request {
|
||||
iscsi_text_request()
|
||||
:
|
||||
reserved(0),
|
||||
opcode(ISCSI_OPCODE_TEXT_REQUEST),
|
||||
reserved2(2)
|
||||
{
|
||||
reserved3[0] = 0;
|
||||
reserved3[1] = 0;
|
||||
reserved3[2] = 0;
|
||||
reserved3[3] = 0;
|
||||
}
|
||||
ISCSI_BHS_START
|
||||
bool c : 1; // continue
|
||||
uint32 reserved2 : 22;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TAGS
|
||||
uint32 cmdSN;
|
||||
uint32 expStatSN;
|
||||
uint32 reserved3[4];
|
||||
} _PACKED;
|
||||
|
||||
// Text Response (RFC 3720 10.11)
|
||||
struct iscsi_text_response {
|
||||
ISCSI_BHS_START
|
||||
bool c : 1; // continue
|
||||
uint32 reserved2 : 22;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TAGS
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint32 reserved3[3];
|
||||
} _PACKED;
|
||||
|
||||
struct iscsi_isid {
|
||||
uint8 t : 2;
|
||||
uint8 a : 6;
|
||||
uint16 b;
|
||||
uint8 c;
|
||||
uint16 d;
|
||||
} _PACKED;
|
||||
|
||||
// Login Request (RFC 3720 10.12)
|
||||
struct iscsi_login_request {
|
||||
iscsi_login_request()
|
||||
:
|
||||
reserved(false),
|
||||
immediateDelivery(1),
|
||||
opcode(ISCSI_OPCODE_LOGIN_REQUEST),
|
||||
reserved2(0),
|
||||
reserved3(0)
|
||||
{
|
||||
memset(reserved4, 0, sizeof(reserved4));
|
||||
}
|
||||
|
||||
ISCSI_BHS_BYTE0
|
||||
bool transit : 1;
|
||||
bool c : 1; // continue
|
||||
uint8 reserved2 : 2;
|
||||
uint8 currentStage : 2;
|
||||
uint8 nextStage : 2;
|
||||
uint8 versionMax;
|
||||
uint8 versionMin;
|
||||
ISCSI_BHS_LENGTHS
|
||||
iscsi_isid isid;
|
||||
uint16 tsih;
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint16 cid;
|
||||
uint16 reserved3;
|
||||
uint32 cmdSN;
|
||||
uint32 expStatSN;
|
||||
uint32 reserved4[4];
|
||||
} _PACKED;
|
||||
|
||||
#define ISCSI_SESSION_STAGE_SECURITY_NEGOTIATION 0
|
||||
#define ISCSI_SESSION_STAGE_LOGIN_OPERATIONAL_NEGOTIATION 1
|
||||
#define ISCSI_SESSION_STAGE_FULL_FEATURE_PHASE 3
|
||||
|
||||
#define ISCSI_VERSION 0x00
|
||||
|
||||
#define ISCSI_ISID_OUI 0
|
||||
#define ISCSI_ISID_EN 1
|
||||
#define ISCSI_ISID_RANDOM 2
|
||||
|
||||
// Login Response (RFC 3720 10.13)
|
||||
struct iscsi_login_response {
|
||||
ISCSI_BHS_BYTE0
|
||||
bool transit : 1;
|
||||
bool c : 1; // continue
|
||||
uint8 reserved2 : 2;
|
||||
uint8 currentStage : 2;
|
||||
uint8 nextStage : 2;
|
||||
uint8 versionMax;
|
||||
uint8 versionActive;
|
||||
ISCSI_BHS_LENGTHS
|
||||
iscsi_isid isid;
|
||||
uint16 tsih;
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint32 reserved3;
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint8 statusClass;
|
||||
uint8 statusDetail;
|
||||
uint16 reserved4;
|
||||
uint32 reserved5[2];
|
||||
} _PACKED;
|
||||
|
||||
// Logout Request (RFC 3720 10.14)
|
||||
struct iscsi_logout_request {
|
||||
iscsi_logout_request()
|
||||
:
|
||||
reserved(0),
|
||||
opcode(ISCSI_OPCODE_LOGOUT_REQUEST),
|
||||
final(true),
|
||||
reserved2(0),
|
||||
reserved4(0)
|
||||
{
|
||||
reserved3[0] = 0;
|
||||
reserved3[1] = 0;
|
||||
reserved5[0] = 0;
|
||||
reserved5[1] = 0;
|
||||
reserved5[2] = 0;
|
||||
reserved5[3] = 0;
|
||||
}
|
||||
ISCSI_BHS_START
|
||||
uint8 reasonCode : 7;
|
||||
uint16 reserved2;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint32 reserved3[2];
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint16 cid;
|
||||
uint16 reserved4;
|
||||
uint32 cmdSN;
|
||||
uint32 expStatSN;
|
||||
uint32 reserved5[4];
|
||||
} _PACKED;
|
||||
|
||||
#define ISCSI_LOGOUT_REASON_CLOSE_SESSION 0
|
||||
#define ISCSI_LOGOUT_REASON_CLOSE_CONNECTION 1
|
||||
#define ISCSI_LOGOUT_REASON_REMOVE_CONNECTION 2
|
||||
|
||||
// Logout Response (RFC 3720 10.15)
|
||||
struct iscsi_logout_response {
|
||||
ISCSI_BHS_START
|
||||
uint8 reserved2 : 7;
|
||||
uint8 response;
|
||||
uint8 reserved3;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint32 reserved4[2];
|
||||
ISCSI_BHS_TASK_TAG
|
||||
uint32 reserved5;
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint32 reserved6;
|
||||
uint16 time2Wait;
|
||||
uint16 time2Remain;
|
||||
uint32 reserved7;
|
||||
} _PACKED;
|
||||
|
||||
// NOP-Out (RFC 3270, 10.18)
|
||||
struct iscsi_nop_out {
|
||||
iscsi_nop_out()
|
||||
:
|
||||
reserved(0),
|
||||
opcode(ISCSI_OPCODE_NOP_OUT),
|
||||
final(true),
|
||||
reserved2(0)
|
||||
{
|
||||
reserved3[0] = 0;
|
||||
reserved3[1] = 0;
|
||||
reserved3[2] = 0;
|
||||
reserved3[3] = 0;
|
||||
}
|
||||
ISCSI_BHS_START
|
||||
uint32 reserved2 : 23;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TAGS
|
||||
uint32 cmdSN;
|
||||
uint32 expStatSN;
|
||||
uint32 reserved3[4];
|
||||
} _PACKED;
|
||||
|
||||
// NOP-In (RFC 3270, 10.19)
|
||||
struct iscsi_nop_in {
|
||||
ISCSI_BHS_START
|
||||
uint32 reserved2 : 23;
|
||||
ISCSI_BHS_LENGTHS
|
||||
uint64 lun;
|
||||
ISCSI_BHS_TAGS
|
||||
uint32 statSN;
|
||||
uint32 expCmdSN;
|
||||
uint32 maxCmdSN;
|
||||
uint32 reserved3[3];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
#endif
|
@ -9,13 +9,6 @@ for platform in [ MultiBootSubDirSetup ] {
|
||||
on $(platform) {
|
||||
UsePrivateHeaders kernel [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
|
||||
|
||||
local tcp = ;
|
||||
local iscsi = ;
|
||||
if $(TARGET_ARCH) = ppc {
|
||||
tcp = TCP.cpp ;
|
||||
iscsi = iSCSITarget.cpp ;
|
||||
}
|
||||
|
||||
BootStaticLibrary [ MultiBootGristFiles boot_net ] :
|
||||
ARP.cpp
|
||||
ChainBuffer.cpp
|
||||
@ -24,9 +17,8 @@ for platform in [ MultiBootSubDirSetup ] {
|
||||
NetDefs.cpp
|
||||
NetStack.cpp
|
||||
RemoteDisk.cpp
|
||||
TCP.cpp
|
||||
UDP.cpp
|
||||
$(tcp)
|
||||
$(iscsi)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -1,822 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, Andreas Färber <andreas.faerber@web.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <boot/net/iSCSITarget.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <boot/net/ChainBuffer.h>
|
||||
#include <boot/net/TCP.h>
|
||||
#include <iscsi_cmds.h>
|
||||
#include <scsi_cmds.h>
|
||||
|
||||
#include "real_time_clock.h"
|
||||
|
||||
|
||||
//#define TRACE_ISCSI
|
||||
|
||||
#ifndef TRACE_ISCSI
|
||||
#define TRACE(fmt, ...) ;
|
||||
#else
|
||||
#define TRACE(fmt, ...) printf("iSCSI: %s(): " fmt, __func__, ## __VA_ARGS__)
|
||||
#endif
|
||||
#define PANIC(fmt, ...) panic("iSCSI: %s(): " fmt, __func__, ## __VA_ARGS__)
|
||||
|
||||
|
||||
#define ISCSI_ALIGNMENT 4
|
||||
#define ISCSI_ALIGN(x) (((x) + ISCSI_ALIGNMENT - 1) & ~(ISCSI_ALIGNMENT - 1))
|
||||
#define ISCSI_PADDING(x) ((((x) % ISCSI_ALIGNMENT) == 0) ? 0 \
|
||||
: (ISCSI_ALIGNMENT - ((x) % ISCSI_ALIGNMENT)))
|
||||
|
||||
// derived from the schedulers
|
||||
static int
|
||||
_rand(void)
|
||||
{
|
||||
static int next = 0;
|
||||
if (next == 0)
|
||||
next = real_time_clock_usecs() / 1000;
|
||||
|
||||
next = next * 1103515245 + 12345;
|
||||
return next;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
iSCSITarget::DiscoverTargets(ip_addr_t address, uint16 port, NodeList* devicesList)
|
||||
{
|
||||
iSCSISession* session = new(nothrow) iSCSISession();
|
||||
if (session == NULL)
|
||||
return false;
|
||||
status_t error = session->Init(address, port);
|
||||
if (error != B_OK) {
|
||||
delete session;
|
||||
return false;
|
||||
}
|
||||
const char* request = "SendTargets=All";
|
||||
char* sendTargets = NULL;
|
||||
size_t sendTargetsLength = 0;
|
||||
error = session->Connection()->GetText(request, strlen(request) + 1,
|
||||
&sendTargets, &sendTargetsLength);
|
||||
session->Close();
|
||||
delete session;
|
||||
if (error != B_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool addedDisk = false;
|
||||
char* targetName = NULL;
|
||||
bool seenAddress = false;
|
||||
for (char* pair = sendTargets; pair < sendTargets + sendTargetsLength;
|
||||
pair += strlen(pair) + 1) {
|
||||
printf("%s\n", pair);
|
||||
if (strncmp(pair, "TargetName=", strlen("TargetName=")) == 0) {
|
||||
if (targetName != NULL && !seenAddress) {
|
||||
if (_AddDevice(address, port, targetName, devicesList))
|
||||
addedDisk = true;
|
||||
}
|
||||
seenAddress = false;
|
||||
targetName = pair + strlen("TargetName=");
|
||||
} else if (strncmp(pair, "TargetAddress=", strlen("TargetAddress="))
|
||||
== 0) {
|
||||
seenAddress = true;
|
||||
char* targetAddress = pair + strlen("TargetAddress=");
|
||||
char* comma = strrchr(targetAddress, ',');
|
||||
int addressLength = comma - targetAddress;
|
||||
targetAddress = strndup(targetAddress, addressLength);
|
||||
uint16 targetPort = ISCSI_PORT;
|
||||
char* colon = strrchr(targetAddress, ':');
|
||||
if (colon != NULL) {
|
||||
// colon could be part of an IPv6 address, e.g. [::1.2.3.4]
|
||||
char* bracket = strrchr(targetAddress, ']');
|
||||
if (bracket == NULL || bracket < colon) {
|
||||
targetPort = strtol(colon + 1, NULL, 10);
|
||||
colon[0] = '\0';
|
||||
}
|
||||
}
|
||||
if (targetName != NULL && isdigit(targetAddress[0])) {
|
||||
if (_AddDevice(ip_parse_address(targetAddress), targetPort,
|
||||
targetName, devicesList))
|
||||
addedDisk = true;
|
||||
}
|
||||
free(targetAddress);
|
||||
}
|
||||
}
|
||||
if (targetName != NULL && !seenAddress) {
|
||||
if (_AddDevice(address, port, targetName, devicesList))
|
||||
addedDisk = true;
|
||||
}
|
||||
free(sendTargets);
|
||||
return addedDisk;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
iSCSITarget::_AddDevice(ip_addr_t address, uint16 port,
|
||||
const char* targetName, NodeList* devicesList)
|
||||
{
|
||||
TRACE("=> %s @ %08lx:%u\n", targetName, address, port);
|
||||
iSCSITarget* disk = new(nothrow) iSCSITarget();
|
||||
if (disk == NULL)
|
||||
return false;
|
||||
status_t error = disk->Init(address, port, targetName);
|
||||
if (error != B_OK) {
|
||||
delete disk;
|
||||
return false;
|
||||
}
|
||||
TRACE("disk size = %llu\n", disk->Size());
|
||||
devicesList->Add(disk);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
iSCSITarget::iSCSITarget()
|
||||
:
|
||||
fSession(NULL),
|
||||
fTargetName(NULL),
|
||||
fTargetAlias(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
iSCSITarget::~iSCSITarget()
|
||||
{
|
||||
free(fTargetName);
|
||||
free(fTargetAlias);
|
||||
delete fSession;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSITarget::Init(ip_addr_t address, uint16 port, const char* targetName)
|
||||
{
|
||||
fTargetName = strdup(targetName);
|
||||
if (fTargetName == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fSession = new(nothrow) iSCSISession(fTargetName);
|
||||
if (fSession == NULL)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fSession->Init(address, port, &fTargetAlias);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (targetName == NULL)
|
||||
return B_OK;
|
||||
|
||||
error = _GetSize();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSITarget::_GetSize()
|
||||
{
|
||||
scsi_cmd_read_capacity cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = SCSI_OP_READ_CAPACITY;
|
||||
cmd.relative_address = 0;
|
||||
cmd.lun = 0;
|
||||
cmd.lba = 0;
|
||||
cmd.pmi = 0;
|
||||
cmd.control = 0;
|
||||
scsi_res_read_capacity resp;
|
||||
status_t error = fSession->Connection()->SendCommand(&cmd, sizeof(cmd),
|
||||
true, false, sizeof(resp),
|
||||
&resp, 0, sizeof(resp));
|
||||
if (error != B_OK) {
|
||||
TRACE("error %lx sending command!\n", error);
|
||||
return error;
|
||||
}
|
||||
TRACE("lba = %lu, block size = %lu\n", resp.lba, resp.block_size);
|
||||
fLastLBA = resp.lba;
|
||||
fBlockSize = resp.block_size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
iSCSITarget::ReadAt(void* /*cookie*/, off_t pos, void* buffer, size_t bufferSize)
|
||||
{
|
||||
TRACE("pos=%llu, size = %lu\n", pos, bufferSize);
|
||||
|
||||
if (fSession == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
if (buffer == NULL || pos < 0 || pos >= Size())
|
||||
return B_BAD_VALUE;
|
||||
if (bufferSize == 0)
|
||||
return 0;
|
||||
|
||||
uint32 blockOffset = pos % fBlockSize;
|
||||
|
||||
scsi_cmd_rw_16 cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = SCSI_OP_READ_16;
|
||||
cmd.force_unit_access = 0;
|
||||
cmd.disable_page_out = 0;
|
||||
cmd.lba = pos / fBlockSize;
|
||||
cmd.length = (blockOffset + bufferSize + fBlockSize - 1) / fBlockSize;
|
||||
cmd.control = 0;
|
||||
status_t error = fSession->Connection()->SendCommand(&cmd, sizeof(cmd),
|
||||
true, false, cmd.length * fBlockSize, buffer, blockOffset, bufferSize);
|
||||
if (error != B_OK) {
|
||||
TRACE("error %lx sending command!\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
iSCSITarget::WriteAt(void* /*cookie*/, off_t pos, const void* buffer, size_t bufferSize)
|
||||
{
|
||||
return B_PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSITarget::GetName(char* buffer, size_t bufferSize) const
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
snprintf(buffer, bufferSize, "iSCSI:%s", fTargetName);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
iSCSITarget::Size() const
|
||||
{
|
||||
return (fLastLBA + 1) * fBlockSize;
|
||||
}
|
||||
|
||||
|
||||
iSCSISession::iSCSISession(const char* targetName)
|
||||
:
|
||||
fDiscovery(targetName == NULL),
|
||||
fTargetName(targetName),
|
||||
fConnection(NULL)
|
||||
{
|
||||
fCommandSequenceNumber = _rand();
|
||||
}
|
||||
|
||||
|
||||
iSCSISession::~iSCSISession()
|
||||
{
|
||||
if (Active())
|
||||
Close();
|
||||
delete fConnection;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSISession::Init(ip_addr_t address, uint16 port, char** targetAlias)
|
||||
{
|
||||
fConnection = new(nothrow) iSCSIConnection();
|
||||
if (fConnection == NULL)
|
||||
return B_NO_MEMORY;
|
||||
status_t error = fConnection->Init(this);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = fConnection->Open(address, port);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
error = fConnection->Login(fTargetName, targetAlias);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSISession::Close()
|
||||
{
|
||||
if (fConnection == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
status_t error = fConnection->Logout(true);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
iSCSIConnection::iSCSIConnection()
|
||||
:
|
||||
fSession(NULL),
|
||||
fSocket(NULL),
|
||||
fConnected(false),
|
||||
fConnectionID(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
iSCSIConnection::~iSCSIConnection()
|
||||
{
|
||||
if (fSocket != NULL && fConnected) {
|
||||
if (Logout() != B_OK)
|
||||
fSocket->Close();
|
||||
}
|
||||
delete fSocket;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::Init(iSCSISession* session)
|
||||
{
|
||||
fSession = session;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t
|
||||
iSCSIConnection::Open(ip_addr_t address, uint16 port)
|
||||
{
|
||||
fSocket = new(nothrow) TCPSocket();
|
||||
if (fSocket == NULL)
|
||||
return B_NO_MEMORY;
|
||||
TRACE("connecting to target...\n");
|
||||
status_t error = fSocket->Connect(address, port);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
fConnected = true;
|
||||
TRACE("connected.\n");
|
||||
fConnectionID = _rand();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::Login(const char* targetName, char** targetAlias)
|
||||
{
|
||||
char data[256];
|
||||
size_t dataLength = 0;
|
||||
const char* keyValue;
|
||||
keyValue = "InitiatorName=iqn.2002-10.org.haiku-os:haiku.bootloader.hostX";
|
||||
strcpy(data + dataLength, keyValue);
|
||||
dataLength += strlen(keyValue) + 1;
|
||||
if (targetName != NULL) {
|
||||
dataLength += sprintf(data + dataLength, "TargetName=%s", targetName) + 1;
|
||||
} else {
|
||||
keyValue = "SessionType=Discovery";
|
||||
strcpy(data + dataLength, keyValue);
|
||||
dataLength += strlen(keyValue) + 1;
|
||||
}
|
||||
|
||||
iscsi_login_request req;
|
||||
req.transit = true;
|
||||
req.c = false;
|
||||
req.currentStage = ISCSI_SESSION_STAGE_LOGIN_OPERATIONAL_NEGOTIATION;
|
||||
req.nextStage = ISCSI_SESSION_STAGE_FULL_FEATURE_PHASE;
|
||||
req.versionMax = ISCSI_VERSION;
|
||||
req.versionMin = ISCSI_VERSION;
|
||||
req.totalAHSLength = 0;
|
||||
req.dataSegmentLength = dataLength;
|
||||
TRACE("data segment length = %lu\n", req.dataSegmentLength);
|
||||
req.isid.t = ISCSI_ISID_RANDOM;
|
||||
req.isid.a = 0;
|
||||
uint32 random = _rand();
|
||||
req.isid.b = random >> 8;
|
||||
req.isid.c = random & 0xff;
|
||||
req.isid.d = _rand();
|
||||
req.tsih = 0;
|
||||
req.initiatorTaskTag = _rand();
|
||||
req.cid = fConnectionID;
|
||||
req.cmdSN = fSession->CommandSequenceNumber();
|
||||
req.expStatSN = 0;
|
||||
status_t error = fSocket->Write(&req, sizeof(req));
|
||||
if (error != B_OK) {
|
||||
return error;
|
||||
}
|
||||
for (unsigned int i = dataLength; i < ISCSI_ALIGN(dataLength); i++)
|
||||
data[i] = '\0';
|
||||
dataLength = ISCSI_ALIGN(dataLength);
|
||||
TRACE("data length = %lu\n", dataLength);
|
||||
error = fSocket->Write(data, dataLength);
|
||||
if (error != B_OK) {
|
||||
TRACE("write error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("request sent.\n");
|
||||
|
||||
iscsi_login_response resp;
|
||||
size_t bytesRead = 0;
|
||||
error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
TRACE("response: opcode = %x, status class = %u, status detail = %u, transit = %u, data length = %lu\n",
|
||||
resp.opcode, resp.statusClass, resp.statusDetail, resp.transit, resp.dataSegmentLength);
|
||||
if (resp.dataSegmentLength > 0) {
|
||||
error = fSocket->Read(data, resp.dataSegmentLength, &bytesRead, 1000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response data read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
if (resp.dataSegmentLength % ISCSI_ALIGNMENT) {
|
||||
error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 100000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response padding read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
}
|
||||
for (char* pair = data; pair < data + resp.dataSegmentLength; pair += strlen(pair) + 1) {
|
||||
TRACE("%s\n", pair);
|
||||
if (targetAlias != NULL && strncmp(pair, "TargetAlias=", strlen("TargetAlias=")) == 0) {
|
||||
*targetAlias = strdup(pair + strlen("TargetAlias="));
|
||||
}
|
||||
}
|
||||
}
|
||||
fStatusSequenceNumber = resp.statSN;
|
||||
if (resp.statusClass != 0) {
|
||||
TRACE("response indicates failure.\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::Logout(bool closeSession)
|
||||
{
|
||||
iscsi_logout_request req;
|
||||
TRACE("req size = %lu\n", sizeof(req));
|
||||
req.immediateDelivery = true;
|
||||
req.reasonCode = closeSession ? ISCSI_LOGOUT_REASON_CLOSE_SESSION
|
||||
: ISCSI_LOGOUT_REASON_CLOSE_CONNECTION;
|
||||
req.totalAHSLength = 0;
|
||||
req.dataSegmentLength = 0;
|
||||
req.initiatorTaskTag = _rand();
|
||||
req.cid = closeSession ? 0 : fConnectionID;
|
||||
req.cmdSN = fSession->CommandSequenceNumber();
|
||||
req.expStatSN = fStatusSequenceNumber;
|
||||
status_t error = fSocket->Write(&req, sizeof(req));
|
||||
if (error != B_OK) {
|
||||
TRACE("request write error\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
iscsi_logout_response resp;
|
||||
TRACE("resp size = %lu\n", sizeof(resp));
|
||||
size_t bytesRead = 0;
|
||||
error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
TRACE("response: opcode = %x, response = %u\n",
|
||||
resp.opcode, resp.response);
|
||||
fStatusSequenceNumber = resp.statSN;
|
||||
if (resp.response != 0) {
|
||||
TRACE("response indicates failure.\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fSocket->Close();
|
||||
fConnected = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::GetText(const char* request, size_t requestLength, char** response, size_t* responseLength)
|
||||
{
|
||||
iscsi_text_request req;
|
||||
req.immediateDelivery = true;
|
||||
req.final = true;
|
||||
req.c = false;
|
||||
req.totalAHSLength = 0;
|
||||
req.dataSegmentLength = requestLength;
|
||||
req.lun = 0;
|
||||
req.initiatorTaskTag = _rand();
|
||||
req.targetTransferTag = 0xffffffffL;
|
||||
req.cmdSN = fSession->NextCommandSequenceNumber();
|
||||
req.expStatSN = fStatusSequenceNumber;
|
||||
status_t error = fSocket->Write(&req, sizeof(req));
|
||||
if (error != B_OK) {
|
||||
TRACE("iSCSI text request write error\n");
|
||||
return error;
|
||||
}
|
||||
error = fSocket->Write(request, requestLength);
|
||||
if (error != B_OK) {
|
||||
TRACE("iSCSI text request data write error\n");
|
||||
return error;
|
||||
}
|
||||
if (requestLength % ISCSI_ALIGNMENT != 0) {
|
||||
char buffer[3];
|
||||
memset(buffer, 0, 3);
|
||||
error = fSocket->Write(buffer, ISCSI_ALIGNMENT - (requestLength % ISCSI_ALIGNMENT));
|
||||
if (error != B_OK) {
|
||||
TRACE("iSCSI text request padding write error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
iscsi_logout_response resp;
|
||||
size_t bytesRead = 0;
|
||||
error = fSocket->Read(&resp, sizeof(resp), &bytesRead, 10000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
TRACE("response: opcode = %x\n",
|
||||
resp.opcode);
|
||||
*response = (char*)malloc(resp.dataSegmentLength);
|
||||
if (*response == NULL)
|
||||
return B_NO_MEMORY;
|
||||
error = fSocket->Read(*response, resp.dataSegmentLength, &bytesRead, 10000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("bytesRead = %lu\n", bytesRead);
|
||||
*responseLength = resp.dataSegmentLength;
|
||||
if ((resp.dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
error = fSocket->Read(NULL, ISCSI_PADDING(resp.dataSegmentLength), &bytesRead, 1000000LL);
|
||||
if (error != B_OK) {
|
||||
TRACE("response padding read error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
fStatusSequenceNumber = resp.statSN;
|
||||
if (resp.opcode != ISCSI_OPCODE_TEXT_RESPONSE) {
|
||||
PANIC("response opcode unexpected!");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::SendCommand(const void* command, size_t commandSize,
|
||||
bool r, bool w, uint32 expectedDataTransferLength,
|
||||
void* response, uint32 responseOffset, size_t responseLength)
|
||||
{
|
||||
TRACE("command size = %lu, offset = %lu, length = %lu\n", commandSize, responseOffset, responseLength);
|
||||
iscsi_scsi_command req;
|
||||
req.immediateDelivery = true;
|
||||
req.final = true;
|
||||
req.r = r;
|
||||
req.w = w;
|
||||
req.attr = 0;
|
||||
req.totalAHSLength = 0;
|
||||
req.dataSegmentLength = (commandSize > 16) ? commandSize - 16 : 0;
|
||||
req.lun = 0;
|
||||
req.initiatorTaskTag = _rand();
|
||||
req.expectedDataTransferLength = expectedDataTransferLength;
|
||||
req.cmdSN = fSession->NextCommandSequenceNumber();
|
||||
req.expStatSN = fStatusSequenceNumber;
|
||||
if (commandSize < 16)
|
||||
memset(req.cdb, 0, 16);
|
||||
memcpy(req.cdb, command, commandSize <= 16 ? commandSize : 16);
|
||||
status_t error = fSocket->Write(&req, sizeof(req));
|
||||
if (error != B_OK) {
|
||||
TRACE("write error\n");
|
||||
return error;
|
||||
}
|
||||
if (commandSize > 16) {
|
||||
error = fSocket->Write((uint8*)command + 16, commandSize - 16);
|
||||
if (error != B_OK) {
|
||||
TRACE("write error\n");
|
||||
return error;
|
||||
}
|
||||
if ((req.dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
char buffer[3];
|
||||
memset(buffer, 0, 3);
|
||||
error = fSocket->Write(buffer, ISCSI_ALIGNMENT - (req.dataSegmentLength % ISCSI_ALIGNMENT));
|
||||
if (error != B_OK) {
|
||||
TRACE("request padding write error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct iscsi_basic_header_segment resp;
|
||||
error = _ReadResponse(&resp);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
while (r && resp.opcode != ISCSI_OPCODE_SCSI_RESPONSE) {
|
||||
if (resp.opcode != ISCSI_OPCODE_SCSI_DATA_IN)
|
||||
PANIC("response opcode %x unexpected\n", resp.opcode);
|
||||
iscsi_scsi_data_in* dataIn = (iscsi_scsi_data_in*)&resp;
|
||||
TRACE("A=%u, S=%u, bufferOffset=%lu, length = %lu\n", dataIn->acknowledge, dataIn->S, dataIn->bufferOffset, resp.dataSegmentLength);
|
||||
if (resp.dataSegmentLength > 0) {
|
||||
size_t toRead = resp.dataSegmentLength;
|
||||
size_t toSkip = 0;
|
||||
if (dataIn->bufferOffset < responseOffset) {
|
||||
toSkip = MIN(responseOffset - dataIn->bufferOffset, resp.dataSegmentLength);
|
||||
error = _Read(NULL, toSkip);
|
||||
if (error != B_OK) {
|
||||
TRACE("response skip error\n");
|
||||
return error;
|
||||
}
|
||||
TRACE("skipped %lu response bytes\n", toSkip);
|
||||
toRead -= toSkip;
|
||||
}
|
||||
if (toRead > 0) {
|
||||
if (dataIn->bufferOffset + resp.dataSegmentLength > responseOffset + responseLength) {
|
||||
size_t cutOff = expectedDataTransferLength - (responseOffset + responseLength);
|
||||
toRead = MIN(expectedDataTransferLength - cutOff - dataIn->bufferOffset, resp.dataSegmentLength) - toSkip;
|
||||
}
|
||||
error = _Read((uint8*)response + dataIn->bufferOffset - responseOffset, toRead);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error: %lx\n", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
size_t toCutOff = resp.dataSegmentLength - toSkip - toRead;
|
||||
if (toCutOff > 0) {
|
||||
error = _Read(NULL, toCutOff);
|
||||
if (error != B_OK) {
|
||||
TRACE("response cut-off error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (toSkip + toRead + toCutOff != resp.dataSegmentLength)
|
||||
PANIC("inconcistency while reading detected!\n");
|
||||
}
|
||||
if ((resp.dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
error = _Read(NULL, ISCSI_PADDING(resp.dataSegmentLength));
|
||||
if (error != B_OK) {
|
||||
TRACE("response padding read error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
fStatusSequenceNumber = dataIn->statSN;
|
||||
if (dataIn->S) {
|
||||
// TODO check status
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
error = _ReadResponse(&resp);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("response: opcode = %x, AHS length = %x, data length = %lu\n",
|
||||
resp.opcode, resp.totalAHSLength, resp.dataSegmentLength);
|
||||
if (resp.opcode != ISCSI_OPCODE_SCSI_RESPONSE) {
|
||||
PANIC("response opcode unexpected!\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
iscsi_scsi_response* scsiResp = (iscsi_scsi_response*)&resp;
|
||||
TRACE("response: response = %x, status = %x, SNACK=%x\n",
|
||||
scsiResp->response, scsiResp->status, scsiResp->snackTag);
|
||||
if (resp.dataSegmentLength > 0) {
|
||||
void* buffer = NULL;
|
||||
if (scsiResp->status != SCSI_STATUS_GOOD)
|
||||
buffer = malloc(resp.dataSegmentLength);
|
||||
error = _Read(buffer, resp.dataSegmentLength);
|
||||
if (error != B_OK) {
|
||||
TRACE("response read error\n");
|
||||
return error;
|
||||
}
|
||||
#ifdef TRACE_ISCSI
|
||||
if (scsiResp->status != SCSI_STATUS_GOOD) {
|
||||
scsi_sense* sense = (scsi_sense*)((uint16*)buffer + 1);
|
||||
TRACE("error code = %u, sense key = %u, ILI = %u, asc = %x\n",
|
||||
sense->error_code, sense->sense_key, sense->ILI, (sense->asc << 8) | sense->ascq);
|
||||
}
|
||||
#endif
|
||||
free(buffer);
|
||||
}
|
||||
if ((resp.dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
error = _Read(NULL, ISCSI_PADDING(resp.dataSegmentLength));
|
||||
if (error != B_OK) {
|
||||
TRACE("response padding read error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
fStatusSequenceNumber = scsiResp->statSN;
|
||||
if (scsiResp->response != 0x00 || scsiResp->status != SCSI_STATUS_GOOD)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::_ReadResponse(iscsi_basic_header_segment* resp, bigtime_t timeout)
|
||||
{
|
||||
if (resp == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t error = _Read(resp, sizeof(iscsi_basic_header_segment), timeout);
|
||||
if (error != B_OK) {
|
||||
TRACE("initial read failed\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (resp->reserved == true) {
|
||||
TRACE("reserved bit is 1!\n");
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
// theoretically process header checksum here, if available
|
||||
|
||||
// At any time a target can send a NOP-In, requiring us to answer with a NOP-Out.
|
||||
// TODO handle asynchronous event message
|
||||
while (resp->opcode == ISCSI_OPCODE_NOP_IN) {
|
||||
iscsi_nop_in* nopIn = (iscsi_nop_in*)resp;
|
||||
// A NOP-In can also be the answer to our own NOP-Out though.
|
||||
if (nopIn->targetTransferTag == 0xffffffff)
|
||||
return B_OK;
|
||||
TRACE("received NOP-In (ping data length = %lu)\n", nopIn->dataSegmentLength);
|
||||
void* pingData = NULL;
|
||||
if (nopIn->dataSegmentLength > 0) {
|
||||
pingData = malloc(nopIn->dataSegmentLength);
|
||||
if (pingData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
error = _Read(pingData, nopIn->dataSegmentLength, timeout);
|
||||
if (error != B_OK) {
|
||||
TRACE("NOP-In ping data read error\n");
|
||||
free(pingData);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if ((nopIn->dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
error = _Read(NULL, ISCSI_PADDING(nopIn->dataSegmentLength), timeout);
|
||||
if (error != B_OK) {
|
||||
TRACE("NOP-In padding read error\n");
|
||||
free(pingData);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
iscsi_nop_out nopOut;
|
||||
nopOut.totalAHSLength = 0;
|
||||
nopOut.dataSegmentLength = nopIn->dataSegmentLength;
|
||||
nopOut.lun = nopIn->lun;
|
||||
nopOut.initiatorTaskTag = 0xffffffff;
|
||||
nopOut.targetTransferTag = nopIn->targetTransferTag;
|
||||
nopOut.cmdSN = fSession->NextCommandSequenceNumber();
|
||||
nopOut.expStatSN = fStatusSequenceNumber;
|
||||
error = fSocket->Write(&nopOut, sizeof(nopOut));
|
||||
if (error != B_OK) {
|
||||
TRACE("NOP-Out write error\n");
|
||||
free(pingData);
|
||||
return error;
|
||||
}
|
||||
if (nopOut.dataSegmentLength > 0) {
|
||||
error = fSocket->Write(pingData, nopOut.dataSegmentLength);
|
||||
free(pingData);
|
||||
if (error != B_OK) {
|
||||
TRACE("NOP-Out ping data write error\n");
|
||||
return error;
|
||||
}
|
||||
if ((nopOut.dataSegmentLength % ISCSI_ALIGNMENT) != 0) {
|
||||
char buffer[3];
|
||||
memset(buffer, 0, 3);
|
||||
error = fSocket->Write(buffer, ISCSI_ALIGNMENT - (nopOut.dataSegmentLength % ISCSI_ALIGNMENT));
|
||||
if (error != B_OK) {
|
||||
TRACE("NOP-Out padding write error\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error = _Read(resp, sizeof(iscsi_basic_header_segment), timeout);
|
||||
if (error != B_OK) {
|
||||
TRACE("read failed\n");
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
iSCSIConnection::_Read(void* buffer, size_t bufferSize, bigtime_t timeout)
|
||||
{
|
||||
size_t bytesRead;
|
||||
status_t error = fSocket->Read(buffer, bufferSize, &bytesRead, timeout);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
if (bytesRead < bufferSize) {
|
||||
dprintf("not enough data available: %lu vs. %lu\n", bytesRead, bufferSize);
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
@ -13,7 +13,6 @@
|
||||
#include <boot/stdio.h>
|
||||
#include <boot/stage2.h>
|
||||
#include <boot/net/IP.h>
|
||||
#include <boot/net/iSCSITarget.h>
|
||||
#include <boot/net/NetStack.h>
|
||||
#include <boot/net/RemoteDisk.h>
|
||||
#include <platform/openfirmware/devices.h>
|
||||
@ -76,21 +75,13 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
|
||||
}
|
||||
}
|
||||
|
||||
// init a remote disk, if possible
|
||||
// init a native remote disk, if possible
|
||||
RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
|
||||
if (remoteDisk != NULL) {
|
||||
devicesList->Add(remoteDisk);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ISCSI
|
||||
if (bootAddress != 0) {
|
||||
if (iSCSITarget::DiscoverTargets(bootAddress, ISCSI_PORT,
|
||||
devicesList))
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user