VirtualBox

Changeset 22256 in vbox


Ignore:
Timestamp:
Aug 14, 2009 12:33:11 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
51078
Message:

Storage/iSCSI: bunch of fixes which improve RFC compliance and error handling

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp

    r21839 r22256  
    109109
    110110/** Maximum PDU payload size we can handle in one piece. */
    111 #define ISCSI_PDU_SIZE_MAX _256K
     111#define ISCSI_DATA_LENGTH_MAX _256K
    112112
    113113/** 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)
    115115
    116116
     
    310310    /** Total volume size in bytes. Easiert that multiplying the above values all the time. */
    311311    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
    312318    /** Current state of the connection/session. */
    313319    ISCSISTATE          state;
     
    388394
    389395
     396/**
     397 * iSCSI login negotiation parameter
     398 */
     399typedef 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
    390410/*******************************************************************************
    391411*   Static Variables                                                           *
     
    399419
    400420/** Default initiator name. */
    401 static const char *s_iscsiConfigDefaultInitiatorName = "iqn.2008-04.com.sun.virtualbox.initiator";
     421static const char *s_iscsiConfigDefaultInitiatorName = "iqn.2009-08.com.sun.virtualbox.initiator";
    402422
    403423/** Default timeout, 10 seconds. */
     
    814834    uint32_t aResBHS[12];
    815835    char *pszNext;
     836
     837    bool fParameterNeg = true;;
     838    pImage->cbRecvDataLength = ISCSI_DATA_LENGTH_MAX;
     839    pImage->cbSendDataLength = ISCSI_DATA_LENGTH_MAX;
     840    char szMaxRecvDataSegmentLength[16];
     841    RTStrPrintf(szMaxRecvDataSegmentLength, sizeof(szMaxRecvDataSegmentLength), "%u", ISCSI_DATA_LENGTH_MAX);
     842    char szMaxBurstLength[16];
     843    RTStrPrintf(szMaxBurstLength, sizeof(szMaxBurstLength), "%u", ISCSI_DATA_LENGTH_MAX);
     844    char szFirstBurstLength[16];
     845    RTStrPrintf(szFirstBurstLength, sizeof(szFirstBurstLength), "%u", ISCSI_DATA_LENGTH_MAX);
     846    ISCSIPARAMETER aParameterNeg[] =
     847    {
     848        { "HeaderDigest", "None", 0 },
     849        { "DataDigest", "None", 0 },
     850        { "MaxConnections", "1", 0 },
     851        { "InitialR2T", "No", 0 },
     852        { "ImmediateData", "Yes", 0 },
     853        { "MaxRecvDataSegmentLength", szMaxRecvDataSegmentLength, 0 },
     854        { "MaxBurstLength", szMaxBurstLength, 0 },
     855        { "FirstBurstLength", szFirstBurstLength, 0 },
     856        { "DefaultTime2Wait", "0", 0 },
     857        { "DefaultTime2Retain", "60", 0 },
     858        { "DataPDUInOrder", "Yes", 0 },
     859        { "DataSequenceInOrder", "Yes", 0 },
     860        { "ErrorRecoveryLevel", "0", 0 },
     861        { "MaxOutstandingR2T", "1", 0 }
     862    };
     863
    816864    LogFlowFunc(("entering\n"));
    817865
     
    891939                break;
    892940            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;
     941                if (fParameterNeg)
     942                {
     943                    for (unsigned i = 0; i < RT_ELEMENTS(aParameterNeg); i++)
     944                    {
     945                        rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf,
     946                                                  aParameterNeg[i].pszParamName,
     947                                                  aParameterNeg[i].pszParamValue,
     948                                                  aParameterNeg[i].cbParamValue);
     949                        if (RT_FAILURE(rc))
     950                            goto out;
     951                    }
     952                    fParameterNeg = false;
     953                }
     954
    937955                nsg = 3;
    938956                transit = true;
     
    977995            ISCSIOPCODE cmd;
    978996            ISCSILOGINSTATUSCLASS loginStatusClass;
    979 
    980             /* Place login request in queue. */
    981             pImage->paCurrReq = aISCSIReq;
    982             pImage->cnCurrReq = cnISCSIReq;
    983997
    984998            cnISCSIRes = 0;
     
    11101124                                break;
    11111125                            case 0x0100:    /* login operational negotiation, step 0: check results. */
     1126                            {
     1127                                const char *pcszMaxRecvDataSegmentLength = NULL;
     1128                                const char *pcszMaxBurstLength = NULL;
     1129                                const char *pcszFirstBurstLength = NULL;
     1130                                rc = iscsiTextGetKeyValue(bBuf, aISCSIRes[1].cbSeg, "MaxRecvDataSegmentLength", &pcszMaxRecvDataSegmentLength);
     1131                                if (rc == VERR_INVALID_NAME)
     1132                                    rc = VINF_SUCCESS;
     1133                                if (RT_FAILURE(rc))
     1134                                {
     1135                                    rc = VERR_PARSE_ERROR;
     1136                                    break;
     1137                                }
     1138                                if (pcszMaxRecvDataSegmentLength && strlen(pcszMaxRecvDataSegmentLength) >= sizeof(szMaxRecvDataSegmentLength))
     1139                                {
     1140                                    rc = VERR_BUFFER_OVERFLOW;
     1141                                    break;
     1142                                }
     1143                                rc = iscsiTextGetKeyValue(bBuf, aISCSIRes[1].cbSeg, "MaxBurstLength", &pcszMaxBurstLength);
     1144                                if (rc == VERR_INVALID_NAME)
     1145                                    rc = VINF_SUCCESS;
     1146                                if (RT_FAILURE(rc))
     1147                                {
     1148                                    rc = VERR_PARSE_ERROR;
     1149                                    break;
     1150                                }
     1151                                if (pcszMaxBurstLength && strlen(pcszMaxBurstLength) >= sizeof(szMaxBurstLength))
     1152                                {
     1153                                    rc = VERR_BUFFER_OVERFLOW;
     1154                                    break;
     1155                                }
     1156                                rc = iscsiTextGetKeyValue(bBuf, aISCSIRes[1].cbSeg, "FirstBurstLength", &pcszFirstBurstLength);
     1157                                if (rc == VERR_INVALID_NAME)
     1158                                    rc = VINF_SUCCESS;
     1159                                if (RT_FAILURE(rc))
     1160                                {
     1161                                    rc = VERR_PARSE_ERROR;
     1162                                    break;
     1163                                }
     1164                                if (pcszFirstBurstLength && strlen(pcszFirstBurstLength) >= sizeof(szFirstBurstLength))
     1165                                {
     1166                                    rc = VERR_BUFFER_OVERFLOW;
     1167                                    break;
     1168                                }
     1169                                if (pcszMaxRecvDataSegmentLength)
     1170                                {
     1171                                    uint32_t cb = pImage->cbSendDataLength;
     1172                                    rc = RTStrToUInt32Full(pcszMaxRecvDataSegmentLength, 0, &cb);
     1173                                    AssertRC(rc);
     1174                                    pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
     1175                                }
     1176                                if (pcszMaxBurstLength)
     1177                                {
     1178                                    uint32_t cb = pImage->cbSendDataLength;
     1179                                    rc = RTStrToUInt32Full(pcszMaxBurstLength, 0, &cb);
     1180                                    AssertRC(rc);
     1181                                    pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
     1182                                }
     1183                                if (pcszFirstBurstLength)
     1184                                {
     1185                                    uint32_t cb = pImage->cbSendDataLength;
     1186                                    rc = RTStrToUInt32Full(pcszFirstBurstLength, 0, &cb);
     1187                                    AssertRC(rc);
     1188                                    pImage->cbSendDataLength = RT_MIN(pImage->cbSendDataLength, cb);
     1189                                }
     1190
    11121191                                if (targetCSG == 1 && targetNSG == 3 && targetTransit)
    11131192                                {
     
    11181197                                    break;
    11191198                                }
     1199                                else if (targetCSG == 1 && targetNSG == 1 && !targetTransit)
     1200                                {
     1201                                    /* Target wants to negotiate certain parameters and
     1202                                     * stay in login operational negotiation. */
     1203                                    csg = 1;
     1204                                    nsg = 3;
     1205                                    substate = 0;
     1206                                }
    11201207                                rc = VERR_PARSE_ERROR;
    11211208                                break;
     1209                            }
    11221210                            case 0x0300:    /* full feature phase. */
    11231211                            default:
     
    11531241                    case ISCSI_LOGIN_STATUS_CLASS_INITIATOR_ERROR:
    11541242                        iscsiTransportClose(pImage);
    1155                         pImage->paCurrReq = NULL;
    1156                         pImage->cnCurrReq = 0;
    11571243                        rc = VERR_IO_GEN_FAILURE;
    11581244                        goto out;
     
    11641250                        rc = VERR_PARSE_ERROR;
    11651251                }
    1166 
    1167                 /* Remove login request from queue. */
    1168                 pImage->paCurrReq = NULL;
    1169                 pImage->cnCurrReq = 0;
    11701252
    11711253                if (csg == 3)
     
    12531335        if (RT_SUCCESS(rc))
    12541336        {
    1255             /* Place logout request in queue. */
    1256             pImage->paCurrReq = aISCSIReq;
    1257             pImage->cnCurrReq = cnISCSIReq;
    1258 
    12591337            /*
    12601338             * Read logout response from target.
     
    12731351            else
    12741352                AssertMsgFailed(("iSCSI Logout response error, rc=%Rrc\n", rc));
    1275 
    1276             /* Remove logout request from queue. */
    1277             pImage->paCurrReq = NULL;
    1278             pImage->cnCurrReq = 0;
    12791353        }
    12801354        else
     
    14361510        {
    14371511            /* 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))
     1512             * the last Data-In PDU included successful completion status). Note
     1513             * that ExpStatSN has been bumped already in iscsiRecvPDU. */
     1514            if (!final || ((RT_N2H_U32(aResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(aResBHS[6]) != pImage->ExpStatSN - 1))
    14401515            {
    14411516                /* SCSI Response in the wrong place or with a (target) failure. */
     
    14431518                break;
    14441519            }
     1520            /* The following is a bit tricky, as in error situations we may
     1521             * get the status only instead of the result data plus optional
     1522             * status. Thus the status may have ended up partially in the
     1523             * data area. */
    14451524            pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
    14461525            uint32_t cbData = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
    14471526            if (cbData >= 2)
    14481527            {
    1449                 uint32_t cbStat = RT_N2H_U32(aStat[0]) >> 16;
     1528                uint32_t cbStat = RT_N2H_U32(((uint32_t *)aISCSIRes[1].pvSeg)[0]) >> 16;
    14501529                if (cbStat + 2 > cbData || cbStat > pRequest->cbSense)
    14511530                {
     
    14531532                    break;
    14541533                }
    1455                 pRequest->cbSense = RT_N2H_U32(aStat[0]) >> 16;
    1456                 memcpy(pRequest->pvSense, ((const uint8_t *)aStat) + 2, pRequest->cbSense);
     1534                pRequest->cbSense = cbStat;
     1535                memcpy(pRequest->pvSense, ((const uint8_t *)aISCSIRes[1].pvSeg) + 2, aISCSIRes[1].cbSeg - 2);
     1536                if (cnISCSIRes > 2 && aISCSIRes[2].cbSeg && (ssize_t)cbStat - aISCSIRes[1].cbSeg - 2 > 0)
     1537                    memcpy((char *)pRequest->pvSense + aISCSIRes[1].cbSeg, aISCSIRes[2].pvSeg, cbStat - aISCSIRes[1].cbSeg - 2);
    14571538            }
    14581539            else if (cbData == 1)
     
    14611542                break;
    14621543            }
     1544            else
     1545                pRequest->cbSense = 0;
    14631546            break;
    14641547        }
     
    15601643        if (rc != VERR_BROKEN_PIPE && rc != VERR_NET_CONNECTION_REFUSED)
    15611644            break;
     1645        /* No point in reestablishing the connection for a logout */
     1646        if (pImage->state == ISCSISTATE_IN_LOGOUT)
     1647            break;
    15621648        RTThreadSleep(500);
    1563         if (   pImage->state != ISCSISTATE_IN_LOGIN
    1564             && pImage->state != ISCSISTATE_IN_LOGOUT)
     1649        if (pImage->state != ISCSISTATE_IN_LOGIN)
    15651650        {
    15661651            /* Attempt to re-login when a connection fails, but only when not
    1567              * currently logging in or logging out. */
     1652             * currently logging in. */
    15681653            rc = iscsiAttach(pImage);
    15691654            if (RT_FAILURE(rc))
     
    16011686            if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
    16021687            {
     1688                /* No point in reestablishing the connection for a logout */
     1689                if (pImage->state == ISCSISTATE_IN_LOGOUT)
     1690                    break;
    16031691                /* Connection broken while waiting for a response - wait a while and
    16041692                 * try to restart by re-sending the original request (if any).
    16051693                 * This also handles the connection reestablishment (login etc.). */
    16061694                RTThreadSleep(500);
    1607                 if (   pImage->state != ISCSISTATE_IN_LOGIN
    1608                     && pImage->state != ISCSISTATE_IN_LOGOUT)
     1695                if (pImage->state != ISCSISTATE_IN_LOGIN)
    16091696                {
    16101697                    /* Attempt to re-login when a connection fails, but only when not
    1611                      * currently logging in or logging out. */
     1698                     * currently logging in. */
    16121699                    rc = iscsiAttach(pImage);
    16131700                    if (RT_FAILURE(rc))
     
    27642851
    27652852    /*
    2766      * Clip read size to a value which is supported by many targets.
     2853     * Clip read size to a value which is supported by the target.
    27672854     */
    2768     cbToRead = RT_MIN(cbToRead, ISCSI_PDU_SIZE_MAX);
     2855    cbToRead = RT_MIN(cbToRead, pImage->cbRecvDataLength);
    27692856
    27702857    lba = uOffset / pImage->cbSector;
     
    27952882    sr.pvSense = sense;
    27962883
    2797     rc = iscsiCommand(pImage, &sr);
     2884    for (unsigned i = 0; i < 10; i++)
     2885    {
     2886        rc = iscsiCommand(pImage, &sr);
     2887        if (    (RT_SUCCESS(rc) && !sr.cbSense)
     2888            ||  RT_FAILURE(rc))
     2889            break;
     2890        rc = VERR_READ_ERROR;
     2891    }
    27982892    if (RT_FAILURE(rc))
    27992893    {
     
    28022896    }
    28032897    else
    2804         *pcbActuallyRead = cbToRead;
     2898        *pcbActuallyRead = sr.cbT2IData;
    28052899
    28062900out:
     
    28382932
    28392933    /*
    2840      * Clip write size to a value which is supported by many targets.
     2934     * Clip write size to a value which is supported by the target.
    28412935     */
    2842     cbToWrite = RT_MIN(cbToWrite, ISCSI_PDU_SIZE_MAX);
     2936    cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength);
    28432937
    28442938    lba = uOffset / pImage->cbSector;
     
    28692963    sr.pvSense = sense;
    28702964
    2871     rc = iscsiCommand(pImage, &sr);
     2965    for (unsigned i = 0; i < 10; i++)
     2966    {
     2967        rc = iscsiCommand(pImage, &sr);
     2968        if (    (RT_SUCCESS(rc) && !sr.cbSense)
     2969            ||  RT_FAILURE(rc))
     2970            break;
     2971        rc = VERR_WRITE_ERROR;
     2972    }
    28722973    if (RT_FAILURE(rc))
    28732974    {
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette