~ubuntu-branches/ubuntu/karmic/virtualbox-ose/karmic-updates

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Storage/ISCSIHDDCore.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2009-09-14 18:25:07 UTC
  • mfrom: (0.4.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090914182507-c98g07mq16hjmn6d
Tags: 3.0.6-dfsg-1ubuntu1
* Merge from debian unstable (LP: #429697), remaining changes:
  - Enable DKMS support on virtualbox host and guest modules (LP: #267097)
    - Drop virtualbox-ose{-guest,}-modules-* package templates
    - Recommend *-source instead of *-modules packages
    - Replace error messages related to missing/mismatched
      kernel module accordingly
  - Autoload kernel module
    - LOAD_VBOXDRV_MODULE=1 in virtualbox-ose.default
  - Disable update action
    - patches/u01-disable-update-action.dpatch
  - Virtualbox should go in Accessories, not in System tools (LP: #288590)
    - virtualbox-ose-qt.files/virtualbox-ose.desktop
  - Add apport hook
    - virtualbox-ose.files/source_virtualbox-ose.py
    - virtualbox-ose.install
  - Add launchpad integration
    - control
    - lpi-bug.xpm
    - patches/u02-lp-integration.dpatch
  - virtualbox, virtualbox-* (names of the upstream proprietary packages)
    conflict with virtualbox-ose (LP: #379878)
* Make debug package depend on normal or guest utils package
* Drop patches/22-pulseaudio-stubs.dpatch (applied upstream)
* Rename Ubuntu specific patches to uXX-*.dpatch
* Fix lintian warnings in maintainer scripts

Show diffs side-by-side

added added

removed removed

Lines of Context:
108
108
 
109
109
 
110
110
/** Maximum PDU payload size we can handle in one piece. */
111
 
#define ISCSI_PDU_SIZE_MAX _256K
 
111
#define ISCSI_DATA_LENGTH_MAX _256K
112
112
 
113
113
/** Maximum PDU size we can handle in one piece. */
114
 
#define ISCSI_RECV_PDU_BUFFER_SIZE (ISCSI_PDU_SIZE_MAX + ISCSI_BHS_SIZE)
 
114
#define ISCSI_RECV_PDU_BUFFER_SIZE (ISCSI_DATA_LENGTH_MAX + ISCSI_BHS_SIZE)
115
115
 
116
116
 
117
117
/** Version of the iSCSI standard which this initiator driver can handle. */
309
309
    uint32_t            cbSector;
310
310
    /** Total volume size in bytes. Easiert that multiplying the above values all the time. */
311
311
    uint64_t            cbSize;
 
312
 
 
313
    /** Negotiated maximum data length when sending to target. */
 
314
    uint32_t            cbSendDataLength;
 
315
    /** Negotiated maximum data length when receiving from target. */
 
316
    uint32_t            cbRecvDataLength;
 
317
 
312
318
    /** Current state of the connection/session. */
313
319
    ISCSISTATE          state;
314
320
    /** Flag whether the first Login Response PDU has been seen. */
387
393
} SCSIREQ, *PSCSIREQ;
388
394
 
389
395
 
 
396
/**
 
397
 * iSCSI login negotiation parameter
 
398
 */
 
399
typedef struct ISCSIPARAMETER
 
400
{
 
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. */
 
406
    size_t cbParamValue;
 
407
} ISCSIPARAMETER;
 
408
 
 
409
 
390
410
/*******************************************************************************
391
411
*   Static Variables                                                           *
392
412
*******************************************************************************/
398
418
static const char *s_iscsiConfigDefaultLUN = "0";
399
419
 
400
420
/** Default initiator name. */
401
 
static const char *s_iscsiConfigDefaultInitiatorName = "iqn.2008-04.com.sun.virtualbox.initiator";
 
421
static const char *s_iscsiConfigDefaultInitiatorName = "iqn.2009-08.com.sun.virtualbox.initiator";
402
422
 
403
423
/** Default timeout, 10 seconds. */
404
424
static const char *s_iscsiConfigDefaultTimeout = "10000";
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);
438
459
 
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];
815
836
    char *pszNext;
 
837
 
 
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[] =
 
844
    {
 
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 }
 
859
    };
 
860
 
816
861
    LogFlowFunc(("entering\n"));
817
862
 
818
863
    Assert(pImage->state == ISCSISTATE_FREE);
890
935
                transit = true;
891
936
                break;
892
937
            case 0x0100:    /* login operational negotiation, step 0: set parameters. */
893
 
                char szMaxPDU[16];
894
 
                RTStrPrintf(szMaxPDU, sizeof(szMaxPDU), "%u", ISCSI_PDU_SIZE_MAX);
895
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "HeaderDigest", "None", 0);
896
 
                if (RT_FAILURE(rc))
897
 
                    goto out;
898
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataDigest", "None", 0);
899
 
                if (RT_FAILURE(rc))
900
 
                    goto out;
901
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxConnections", "1", 0);
902
 
                if (RT_FAILURE(rc))
903
 
                    goto out;
904
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "InitialR2T", "No", 0);
905
 
                if (RT_FAILURE(rc))
906
 
                    goto out;
907
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "ImmediateData", "Yes", 0);
908
 
                if (RT_FAILURE(rc))
909
 
                    goto out;
910
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxRecvDataSegmentLength", szMaxPDU, 0);
911
 
                if (RT_FAILURE(rc))
912
 
                    goto out;
913
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxBurstLength", szMaxPDU, 0);
914
 
                if (RT_FAILURE(rc))
915
 
                    goto out;
916
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "FirstBurstLength", szMaxPDU, 0);
917
 
                if (RT_FAILURE(rc))
918
 
                    goto out;
919
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DefaultTime2Wait", "0", 0);
920
 
                if (RT_FAILURE(rc))
921
 
                    goto out;
922
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DefaultTime2Retain", "60", 0);
923
 
                if (RT_FAILURE(rc))
924
 
                    goto out;
925
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataPDUInOrder", "Yes", 0);
926
 
                if (RT_FAILURE(rc))
927
 
                    goto out;
928
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "DataSequenceInOrder", "Yes", 0);
929
 
                if (RT_FAILURE(rc))
930
 
                    goto out;
931
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "ErrorRecoveryLevel", "0", 0);
932
 
                if (RT_FAILURE(rc))
933
 
                    goto out;
934
 
                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "MaxOutstandingR2T", "1", 0);
935
 
                if (RT_FAILURE(rc))
936
 
                    goto out;
 
938
                if (fParameterNeg)
 
939
                {
 
940
                    for (unsigned i = 0; i < RT_ELEMENTS(aParameterNeg); i++)
 
941
                    {
 
942
                        rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf,
 
943
                                                  aParameterNeg[i].pszParamName,
 
944
                                                  aParameterNeg[i].pszParamValue,
 
945
                                                  aParameterNeg[i].cbParamValue);
 
946
                        if (RT_FAILURE(rc))
 
947
                            goto out;
 
948
                    }
 
949
                    fParameterNeg = false;
 
950
                }
 
951
 
937
952
                nsg = 3;
938
953
                transit = true;
939
954
                break;
977
992
            ISCSIOPCODE cmd;
978
993
            ISCSILOGINSTATUSCLASS loginStatusClass;
979
994
 
980
 
            /* Place login request in queue. */
981
 
            pImage->paCurrReq = aISCSIReq;
982
 
            pImage->cnCurrReq = cnISCSIReq;
983
 
 
984
995
            cnISCSIRes = 0;
985
996
            aISCSIRes[cnISCSIRes].pvSeg = aResBHS;
986
997
            aISCSIRes[cnISCSIRes].cbSeg = sizeof(aResBHS);
1029
1040
                        switch (csg << 8 | substate)
1030
1041
                        {
1031
1042
                            case 0x0000:    /* security negotiation, step 0: receive final authentication. */
 
1043
                                rc = iscsiUpdateParameters(pImage, bBuf, aISCSIRes[1].cbSeg);
 
1044
                                if (RT_FAILURE(rc))
 
1045
                                    break;
 
1046
 
1032
1047
                                const char *pcszAuthMethod;
1033
1048
 
1034
1049
                                rc = iscsiTextGetKeyValue(bBuf, aISCSIRes[1].cbSeg, "AuthMethod", &pcszAuthMethod);
1057
1072
                                rc = VERR_PARSE_ERROR;
1058
1073
                                break;
1059
1074
                            case 0x0001:    /* security negotiation, step 1: receive final CHAP variant and challenge. */
 
1075
                                rc = iscsiUpdateParameters(pImage, bBuf, aISCSIRes[1].cbSeg);
 
1076
                                if (RT_FAILURE(rc))
 
1077
                                    break;
 
1078
 
1060
1079
                                const char *pcszChapAuthMethod;
1061
1080
                                const char *pcszChapIdxTarget;
1062
1081
                                const char *pcszChapChallengeStr;
1098
1117
                                transit = true;
1099
1118
                                break;
1100
1119
                            case 0x0002:    /* security negotiation, step 2: check authentication success. */
 
1120
                                rc = iscsiUpdateParameters(pImage, bBuf, aISCSIRes[1].cbSeg);
 
1121
                                if (RT_FAILURE(rc))
 
1122
                                    break;
 
1123
 
1101
1124
                                if (targetCSG == 0 && targetNSG == 1 && targetTransit)
1102
1125
                                {
1103
1126
                                    /* Target wants to continue in login operational state, authentication success. */
1109
1132
                                rc = VERR_PARSE_ERROR;
1110
1133
                                break;
1111
1134
                            case 0x0100:    /* login operational negotiation, step 0: check results. */
 
1135
                                rc = iscsiUpdateParameters(pImage, bBuf, aISCSIRes[1].cbSeg);
 
1136
                                if (RT_FAILURE(rc))
 
1137
                                    break;
 
1138
 
1112
1139
                                if (targetCSG == 1 && targetNSG == 3 && targetTransit)
1113
1140
                                {
1114
1141
                                    /* Target wants to continue in full feature phase, login finished. */
1117
1144
                                    substate = 0;
1118
1145
                                    break;
1119
1146
                                }
 
1147
                                else if (targetCSG == 1 && targetNSG == 1 && !targetTransit)
 
1148
                                {
 
1149
                                    /* Target wants to negotiate certain parameters and
 
1150
                                     * stay in login operational negotiation. */
 
1151
                                    csg = 1;
 
1152
                                    nsg = 3;
 
1153
                                    substate = 0;
 
1154
                                }
1120
1155
                                rc = VERR_PARSE_ERROR;
1121
1156
                                break;
1122
1157
                            case 0x0300:    /* full feature phase. */
1152
1187
                        goto restart;
1153
1188
                    case ISCSI_LOGIN_STATUS_CLASS_INITIATOR_ERROR:
1154
1189
                        iscsiTransportClose(pImage);
1155
 
                        pImage->paCurrReq = NULL;
1156
 
                        pImage->cnCurrReq = 0;
1157
1190
                        rc = VERR_IO_GEN_FAILURE;
1158
1191
                        goto out;
1159
1192
                    case ISCSI_LOGIN_STATUS_CLASS_TARGET_ERROR:
1164
1197
                        rc = VERR_PARSE_ERROR;
1165
1198
                }
1166
1199
 
1167
 
                /* Remove login request from queue. */
1168
 
                pImage->paCurrReq = NULL;
1169
 
                pImage->cnCurrReq = 0;
1170
 
 
1171
1200
                if (csg == 3)
1172
1201
                {
1173
1202
                    /*
1252
1281
        rc = iscsiSendPDU(pImage, aISCSIReq, cnISCSIReq);
1253
1282
        if (RT_SUCCESS(rc))
1254
1283
        {
1255
 
            /* Place logout request in queue. */
1256
 
            pImage->paCurrReq = aISCSIReq;
1257
 
            pImage->cnCurrReq = cnISCSIReq;
1258
 
 
1259
1284
            /*
1260
1285
             * Read logout response from target.
1261
1286
             */
1272
1297
            }
1273
1298
            else
1274
1299
                AssertMsgFailed(("iSCSI Logout response error, rc=%Rrc\n", rc));
1275
 
 
1276
 
            /* Remove logout request from queue. */
1277
 
            pImage->paCurrReq = NULL;
1278
 
            pImage->cnCurrReq = 0;
1279
1300
        }
1280
1301
        else
1281
1302
            AssertMsgFailed(("Could not send iSCSI Logout request, rc=%Rrc\n", rc));
1435
1456
        if (cmd == ISCSIOP_SCSI_RES)
1436
1457
        {
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))
1440
1462
            {
1441
1463
                /* SCSI Response in the wrong place or with a (target) failure. */
1442
1464
                rc = VERR_PARSE_ERROR;
1443
1465
                break;
1444
1466
            }
 
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
 
1470
             * data area. */
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)
1448
1474
            {
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)
1451
1477
                {
1452
1478
                    rc = VERR_BUFFER_OVERFLOW;
1453
1479
                    break;
1454
1480
                }
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);
1457
1485
            }
1458
1486
            else if (cbData == 1)
1459
1487
            {
1460
1488
                rc = VERR_PARSE_ERROR;
1461
1489
                break;
1462
1490
            }
 
1491
            else
 
1492
                pRequest->cbSense = 0;
1463
1493
            break;
1464
1494
        }
1465
1495
        else if (cmd == ISCSIOP_SCSI_DATA_IN)
1559
1589
            break;
1560
1590
        if (rc != VERR_BROKEN_PIPE && rc != VERR_NET_CONNECTION_REFUSED)
1561
1591
            break;
 
1592
        /* No point in reestablishing the connection for a logout */
 
1593
        if (pImage->state == ISCSISTATE_IN_LOGOUT)
 
1594
            break;
1562
1595
        RTThreadSleep(500);
1563
 
        if (   pImage->state != ISCSISTATE_IN_LOGIN
1564
 
            && pImage->state != ISCSISTATE_IN_LOGOUT)
 
1596
        if (pImage->state != ISCSISTATE_IN_LOGIN)
1565
1597
        {
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))
1570
1602
                break;
1600
1632
        {
1601
1633
            if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
1602
1634
            {
 
1635
                /* No point in reestablishing the connection for a logout */
 
1636
                if (pImage->state == ISCSISTATE_IN_LOGOUT)
 
1637
                    break;
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)
1609
1643
                {
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))
1614
1648
                        break;
2033
2067
}
2034
2068
 
2035
2069
 
 
2070
/**
 
2071
 * Retrieve the relevant parameter values and update the initiator state.
 
2072
 *
 
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.
 
2077
 */
 
2078
static int iscsiUpdateParameters(PISCSIIMAGE pImage, const uint8_t *pbBuf, size_t cbBuf)
 
2079
{
 
2080
    int rc;
 
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)
 
2086
        rc = VINF_SUCCESS;
 
2087
    if (RT_FAILURE(rc))
 
2088
        return VERR_PARSE_ERROR;
 
2089
    rc = iscsiTextGetKeyValue(pbBuf, cbBuf, "MaxBurstLength", &pcszMaxBurstLength);
 
2090
    if (rc == VERR_INVALID_NAME)
 
2091
        rc = VINF_SUCCESS;
 
2092
    if (RT_FAILURE(rc))
 
2093
        return VERR_PARSE_ERROR;
 
2094
    rc = iscsiTextGetKeyValue(pbBuf, cbBuf, "FirstBurstLength", &pcszFirstBurstLength);
 
2095
    if (rc == VERR_INVALID_NAME)
 
2096
        rc = VINF_SUCCESS;
 
2097
    if (RT_FAILURE(rc))
 
2098
        return VERR_PARSE_ERROR;
 
2099
    if (pcszMaxRecvDataSegmentLength)
 
2100
    {
 
2101
        uint32_t cb = pImage->cbSendDataLength;
 
2102
        rc = RTStrToUInt32Full(pcszMaxRecvDataSegmentLength, 0, &cb);
 
2103
        AssertRC(rc);
 
2104
        pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
 
2105
    }
 
2106
    if (pcszMaxBurstLength)
 
2107
    {
 
2108
        uint32_t cb = pImage->cbSendDataLength;
 
2109
        rc = RTStrToUInt32Full(pcszMaxBurstLength, 0, &cb);
 
2110
        AssertRC(rc);
 
2111
        pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
 
2112
    }
 
2113
    if (pcszFirstBurstLength)
 
2114
    {
 
2115
        uint32_t cb = pImage->cbSendDataLength;
 
2116
        rc = RTStrToUInt32Full(pcszFirstBurstLength, 0, &cb);
 
2117
        AssertRC(rc);
 
2118
        pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
 
2119
    }
 
2120
    return VINF_SUCCESS;
 
2121
}
 
2122
 
 
2123
 
2036
2124
static bool serial_number_less(uint32_t s1, uint32_t s2)
2037
2125
{
2038
2126
    return (s1 < s2 && s2 - s1 < 0x80000000) || (s1 > s2 && s1 - s2 > 0x80000000);
2763
2851
    }
2764
2852
 
2765
2853
    /*
2766
 
     * Clip read size to a value which is supported by many targets.
 
2854
     * Clip read size to a value which is supported by the target.
2767
2855
     */
2768
 
    cbToRead = RT_MIN(cbToRead, ISCSI_PDU_SIZE_MAX);
 
2856
    cbToRead = RT_MIN(cbToRead, pImage->cbRecvDataLength);
2769
2857
 
2770
2858
    lba = uOffset / pImage->cbSector;
2771
2859
    tls = (uint16_t)(cbToRead / pImage->cbSector);
2794
2882
    sr.cbSense = sizeof(sense);
2795
2883
    sr.pvSense = sense;
2796
2884
 
2797
 
    rc = iscsiCommand(pImage, &sr);
 
2885
    for (unsigned i = 0; i < 10; i++)
 
2886
    {
 
2887
        rc = iscsiCommand(pImage, &sr);
 
2888
        if (    (RT_SUCCESS(rc) && !sr.cbSense)
 
2889
            ||  RT_FAILURE(rc))
 
2890
            break;
 
2891
        rc = VERR_READ_ERROR;
 
2892
    }
2798
2893
    if (RT_FAILURE(rc))
2799
2894
    {
2800
2895
        AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc));
2801
2896
        *pcbActuallyRead = 0;
2802
2897
    }
2803
2898
    else
2804
 
        *pcbActuallyRead = cbToRead;
 
2899
        *pcbActuallyRead = sr.cbT2IData;
2805
2900
 
2806
2901
out:
2807
2902
    LogFlowFunc(("returns %Rrc\n", rc));
2837
2932
    *pcbPostRead = 0;
2838
2933
 
2839
2934
    /*
2840
 
     * Clip write size to a value which is supported by many targets.
 
2935
     * Clip write size to a value which is supported by the target.
2841
2936
     */
2842
 
    cbToWrite = RT_MIN(cbToWrite, ISCSI_PDU_SIZE_MAX);
 
2937
    cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength);
2843
2938
 
2844
2939
    lba = uOffset / pImage->cbSector;
2845
2940
    tls = (uint16_t)(cbToWrite / pImage->cbSector);
2868
2963
    sr.cbSense = sizeof(sense);
2869
2964
    sr.pvSense = sense;
2870
2965
 
2871
 
    rc = iscsiCommand(pImage, &sr);
 
2966
    for (unsigned i = 0; i < 10; i++)
 
2967
    {
 
2968
        rc = iscsiCommand(pImage, &sr);
 
2969
        if (    (RT_SUCCESS(rc) && !sr.cbSense)
 
2970
            ||  RT_FAILURE(rc))
 
2971
            break;
 
2972
        rc = VERR_WRITE_ERROR;
 
2973
    }
2872
2974
    if (RT_FAILURE(rc))
2873
2975
    {
2874
2976
        AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc));