387
393
} SCSIREQ, *PSCSIREQ;
397
* iSCSI login negotiation parameter
399
typedef struct ISCSIPARAMETER
401
/** Name of the parameter. */
402
const char *pszParamName;
403
/** Value of the parameter. */
404
const char *pszParamValue;
405
/** Length of the binary parameter. 0=zero-terminated string. */
390
410
/*******************************************************************************
391
411
* Static Variables *
392
412
*******************************************************************************/
435
455
static int iscsiTextAddKeyValue(uint8_t *pbBuf, size_t cbBuf, size_t *pcbBufCurr, const char *pcszKey, const char *pcszValue, size_t cbValue);
436
456
static int iscsiTextGetKeyValue(const uint8_t *pbBuf, size_t cbBuf, const char *pcszKey, const char **ppcszValue);
437
457
static int iscsiStrToBinary(const char *pcszValue, uint8_t *pbValue, size_t *pcbValue);
458
static int iscsiUpdateParameters(PISCSIIMAGE pImage, const uint8_t *pbBuf, size_t cbBuf);
439
460
/* Serial number arithmetic comparison. */
440
461
static bool serial_number_less(uint32_t sn1, uint32_t sn2);
813
834
ISCSIRES aISCSIRes[2];
814
835
uint32_t aResBHS[12];
838
bool fParameterNeg = true;;
839
pImage->cbRecvDataLength = ISCSI_DATA_LENGTH_MAX;
840
pImage->cbSendDataLength = ISCSI_DATA_LENGTH_MAX;
841
char szMaxDataLength[16];
842
RTStrPrintf(szMaxDataLength, sizeof(szMaxDataLength), "%u", ISCSI_DATA_LENGTH_MAX);
843
ISCSIPARAMETER aParameterNeg[] =
845
{ "HeaderDigest", "None", 0 },
846
{ "DataDigest", "None", 0 },
847
{ "MaxConnections", "1", 0 },
848
{ "InitialR2T", "No", 0 },
849
{ "ImmediateData", "Yes", 0 },
850
{ "MaxRecvDataSegmentLength", szMaxDataLength, 0 },
851
{ "MaxBurstLength", szMaxDataLength, 0 },
852
{ "FirstBurstLength", szMaxDataLength, 0 },
853
{ "DefaultTime2Wait", "0", 0 },
854
{ "DefaultTime2Retain", "60", 0 },
855
{ "DataPDUInOrder", "Yes", 0 },
856
{ "DataSequenceInOrder", "Yes", 0 },
857
{ "ErrorRecoveryLevel", "0", 0 },
858
{ "MaxOutstandingR2T", "1", 0 }
816
861
LogFlowFunc(("entering\n"));
818
863
Assert(pImage->state == ISCSISTATE_FREE);
892
937
case 0x0100: /* login operational negotiation, step 0: set parameters. */
894
RTStrPrintf(szMaxPDU, sizeof(szMaxPDU), "%u", ISCSI_PDU_SIZE_MAX);
895
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "HeaderDigest", "None", 0);
898
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataDigest", "None", 0);
901
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxConnections", "1", 0);
904
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "InitialR2T", "No", 0);
907
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "ImmediateData", "Yes", 0);
910
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxRecvDataSegmentLength", szMaxPDU, 0);
913
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxBurstLength", szMaxPDU, 0);
916
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "FirstBurstLength", szMaxPDU, 0);
919
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DefaultTime2Wait", "0", 0);
922
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DefaultTime2Retain", "60", 0);
925
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataPDUInOrder", "Yes", 0);
928
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataSequenceInOrder", "Yes", 0);
931
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "ErrorRecoveryLevel", "0", 0);
934
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxOutstandingR2T", "1", 0);
940
for (unsigned i = 0; i < RT_ELEMENTS(aParameterNeg); i++)
942
rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf,
943
aParameterNeg[i].pszParamName,
944
aParameterNeg[i].pszParamValue,
945
aParameterNeg[i].cbParamValue);
949
fParameterNeg = false;
1435
1456
if (cmd == ISCSIOP_SCSI_RES)
1437
1458
/* This is the final PDU which delivers the status (and may be omitted if
1438
* the last Data-In PDU included successful completion status). */
1439
if (!final || ((RT_N2H_U32(aResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(aResBHS[9]) != ExpDataSN))
1459
* the last Data-In PDU included successful completion status). Note
1460
* that ExpStatSN has been bumped already in iscsiRecvPDU. */
1461
if (!final || ((RT_N2H_U32(aResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(aResBHS[6]) != pImage->ExpStatSN - 1))
1441
1463
/* SCSI Response in the wrong place or with a (target) failure. */
1442
1464
rc = VERR_PARSE_ERROR;
1467
/* The following is a bit tricky, as in error situations we may
1468
* get the status only instead of the result data plus optional
1469
* status. Thus the status may have ended up partially in the
1445
1471
pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
1446
1472
uint32_t cbData = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
1447
1473
if (cbData >= 2)
1449
uint32_t cbStat = RT_N2H_U32(aStat[0]) >> 16;
1475
uint32_t cbStat = RT_N2H_U32(((uint32_t *)aISCSIRes[1].pvSeg)[0]) >> 16;
1450
1476
if (cbStat + 2 > cbData || cbStat > pRequest->cbSense)
1452
1478
rc = VERR_BUFFER_OVERFLOW;
1455
pRequest->cbSense = RT_N2H_U32(aStat[0]) >> 16;
1456
memcpy(pRequest->pvSense, ((const uint8_t *)aStat) + 2, pRequest->cbSense);
1481
pRequest->cbSense = cbStat;
1482
memcpy(pRequest->pvSense, ((const uint8_t *)aISCSIRes[1].pvSeg) + 2, aISCSIRes[1].cbSeg - 2);
1483
if (cnISCSIRes > 2 && aISCSIRes[2].cbSeg && (ssize_t)cbStat - aISCSIRes[1].cbSeg - 2 > 0)
1484
memcpy((char *)pRequest->pvSense + aISCSIRes[1].cbSeg, aISCSIRes[2].pvSeg, cbStat - aISCSIRes[1].cbSeg - 2);
1458
1486
else if (cbData == 1)
1460
1488
rc = VERR_PARSE_ERROR;
1492
pRequest->cbSense = 0;
1465
1495
else if (cmd == ISCSIOP_SCSI_DATA_IN)
1560
1590
if (rc != VERR_BROKEN_PIPE && rc != VERR_NET_CONNECTION_REFUSED)
1592
/* No point in reestablishing the connection for a logout */
1593
if (pImage->state == ISCSISTATE_IN_LOGOUT)
1562
1595
RTThreadSleep(500);
1563
if ( pImage->state != ISCSISTATE_IN_LOGIN
1564
&& pImage->state != ISCSISTATE_IN_LOGOUT)
1596
if (pImage->state != ISCSISTATE_IN_LOGIN)
1566
1598
/* Attempt to re-login when a connection fails, but only when not
1567
* currently logging in or logging out. */
1599
* currently logging in. */
1568
1600
rc = iscsiAttach(pImage);
1569
1601
if (RT_FAILURE(rc))
1601
1633
if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
1635
/* No point in reestablishing the connection for a logout */
1636
if (pImage->state == ISCSISTATE_IN_LOGOUT)
1603
1638
/* Connection broken while waiting for a response - wait a while and
1604
1639
* try to restart by re-sending the original request (if any).
1605
1640
* This also handles the connection reestablishment (login etc.). */
1606
1641
RTThreadSleep(500);
1607
if ( pImage->state != ISCSISTATE_IN_LOGIN
1608
&& pImage->state != ISCSISTATE_IN_LOGOUT)
1642
if (pImage->state != ISCSISTATE_IN_LOGIN)
1610
1644
/* Attempt to re-login when a connection fails, but only when not
1611
* currently logging in or logging out. */
1645
* currently logging in. */
1612
1646
rc = iscsiAttach(pImage);
1613
1647
if (RT_FAILURE(rc))
2071
* Retrieve the relevant parameter values and update the initiator state.
2073
* @returns VBOX status.
2074
* @param pImage Current iSCSI initiator state.
2075
* @param pbBuf Buffer containing key=value pairs.
2076
* @param cbBuf Length of buffer with key=value pairs.
2078
static int iscsiUpdateParameters(PISCSIIMAGE pImage, const uint8_t *pbBuf, size_t cbBuf)
2081
const char *pcszMaxRecvDataSegmentLength = NULL;
2082
const char *pcszMaxBurstLength = NULL;
2083
const char *pcszFirstBurstLength = NULL;
2084
rc = iscsiTextGetKeyValue(pbBuf, cbBuf, "MaxRecvDataSegmentLength", &pcszMaxRecvDataSegmentLength);
2085
if (rc == VERR_INVALID_NAME)
2088
return VERR_PARSE_ERROR;
2089
rc = iscsiTextGetKeyValue(pbBuf, cbBuf, "MaxBurstLength", &pcszMaxBurstLength);
2090
if (rc == VERR_INVALID_NAME)
2093
return VERR_PARSE_ERROR;
2094
rc = iscsiTextGetKeyValue(pbBuf, cbBuf, "FirstBurstLength", &pcszFirstBurstLength);
2095
if (rc == VERR_INVALID_NAME)
2098
return VERR_PARSE_ERROR;
2099
if (pcszMaxRecvDataSegmentLength)
2101
uint32_t cb = pImage->cbSendDataLength;
2102
rc = RTStrToUInt32Full(pcszMaxRecvDataSegmentLength, 0, &cb);
2104
pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
2106
if (pcszMaxBurstLength)
2108
uint32_t cb = pImage->cbSendDataLength;
2109
rc = RTStrToUInt32Full(pcszMaxBurstLength, 0, &cb);
2111
pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
2113
if (pcszFirstBurstLength)
2115
uint32_t cb = pImage->cbSendDataLength;
2116
rc = RTStrToUInt32Full(pcszFirstBurstLength, 0, &cb);
2118
pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
2120
return VINF_SUCCESS;
2036
2124
static bool serial_number_less(uint32_t s1, uint32_t s2)
2038
2126
return (s1 < s2 && s2 - s1 < 0x80000000) || (s1 > s2 && s1 - s2 > 0x80000000);
2794
2882
sr.cbSense = sizeof(sense);
2795
2883
sr.pvSense = sense;
2797
rc = iscsiCommand(pImage, &sr);
2885
for (unsigned i = 0; i < 10; i++)
2887
rc = iscsiCommand(pImage, &sr);
2888
if ( (RT_SUCCESS(rc) && !sr.cbSense)
2891
rc = VERR_READ_ERROR;
2798
2893
if (RT_FAILURE(rc))
2800
2895
AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc));
2801
2896
*pcbActuallyRead = 0;
2804
*pcbActuallyRead = cbToRead;
2899
*pcbActuallyRead = sr.cbT2IData;
2807
2902
LogFlowFunc(("returns %Rrc\n", rc));
2868
2963
sr.cbSense = sizeof(sense);
2869
2964
sr.pvSense = sense;
2871
rc = iscsiCommand(pImage, &sr);
2966
for (unsigned i = 0; i < 10; i++)
2968
rc = iscsiCommand(pImage, &sr);
2969
if ( (RT_SUCCESS(rc) && !sr.cbSense)
2972
rc = VERR_WRITE_ERROR;
2872
2974
if (RT_FAILURE(rc))
2874
2976
AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc));