VirtualBox

Changeset 63880 in vbox for trunk/src/VBox/Storage


Ignore:
Timestamp:
Sep 19, 2016 11:31:10 AM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
110744
Message:

Storage/iSCSI: Cleanup, get rid goto ... last part

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Storage/ISCSI.cpp

    r63829 r63880  
    12081208}
    12091209
    1210 
    1211 /**
    1212  * Attach to an iSCSI target. Performs all operations necessary to enter
    1213  * Full Feature Phase.
     1210/**
     1211 * Returns a human readable version of the given initiator login error detail.
     1212 *
     1213 * @returns String with the error detail.
     1214 * @param   u8Detail        The detail indicator from the response.
     1215 */
     1216static const char *iscsiGetLoginErrorDetail(uint8_t u8Detail)
     1217{
     1218    const char *pszDetail = NULL;
     1219
     1220    switch (u8Detail)
     1221    {
     1222        case 0x00:
     1223            pszDetail = "Miscelleanous iSCSI intiaitor error";
     1224            break;
     1225        case 0x01:
     1226            pszDetail = "Authentication failure";
     1227            break;
     1228        case 0x02:
     1229            pszDetail = "Authorization failure";
     1230            break;
     1231        case 0x03:
     1232            pszDetail = "Not found";
     1233            break;
     1234        case 0x04:
     1235            pszDetail = "Target removed";
     1236            break;
     1237        case 0x05:
     1238            pszDetail = "Unsupported version";
     1239            break;
     1240        case 0x06:
     1241            pszDetail = "Too many connections";
     1242            break;
     1243        case 0x07:
     1244            pszDetail = "Missing parameter";
     1245            break;
     1246        case 0x08:
     1247            pszDetail = "Can't include in session";
     1248            break;
     1249        case 0x09:
     1250            pszDetail = "Session type not supported";
     1251            break;
     1252        case 0x0a:
     1253            pszDetail = "Session does not exist";
     1254            break;
     1255        case 0x0b:
     1256            pszDetail = "Invalid request type during login";
     1257            break;
     1258        default:
     1259            pszDetail = "Unknown status detail";
     1260    }
     1261
     1262    return pszDetail;
     1263}
     1264
     1265/**
     1266 * Attempts one login attempt to the given target.
    12141267 *
    12151268 * @returns VBox status code.
     1269 * @retval  VINF_TRY_AGAIN when getting redirected and having to start over.
     1270 * @retval  VERR_TRY_AGAIN in case the connection was lost while receiving a reply
     1271 *                         from the target and the login attempt can be repeated.
    12161272 * @param   pImage      The iSCSI connection state to be used.
    12171273 */
    1218 static DECLCALLBACK(int) iscsiAttach(void *pvUser)
    1219 {
    1220     int rc = VINF_SUCCESS;      /* (MSC is used uninitialized) */
     1274static int iscsiLogin(PISCSIIMAGE pImage)
     1275{
     1276    int rc = VINF_SUCCESS;
    12211277    uint32_t itt;
    12221278    uint32_t csg, nsg, substate;
     
    12351291    ISCSIRES aISCSIRes[2];
    12361292    uint32_t aResBHS[12];
    1237     unsigned cRetries = 5;
    12381293    char *pszNext;
    1239     PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser;
    1240 
    1241     bool fParameterNeg = true;;
     1294    bool fParameterNeg = true;
    12421295    pImage->cbRecvDataLength = ISCSI_DATA_LENGTH_MAX;
    12431296    pImage->cbSendDataLength = RT_MIN(ISCSI_DATA_LENGTH_MAX, pImage->cbWriteSplit);
     
    12621315    };
    12631316
    1264     LogFlowFunc(("entering\n"));
    1265 
    1266     Assert(pImage->state == ISCSISTATE_FREE);
    1267 
    1268     /*
    1269      * If there were too many logins without any successful I/O just fail
    1270      * and assume the target is not working properly.
    1271      */
    1272     if (ASMAtomicReadU32(&pImage->cLoginsSinceIo) == 3)
    1273         return VERR_BROKEN_PIPE;
    1274 
    1275     RTSemMutexRequest(pImage->Mutex, RT_INDEFINITE_WAIT);
    1276 
    1277     /* Make 100% sure the connection isn't reused for a new login. */
    1278     iscsiTransportClose(pImage);
    1279 
    1280 restart:
    1281     if (!cRetries)
    1282     {
    1283         /*
    1284          * Prevent the iSCSI initiator to go into normal state if we are here,
    1285          * even if there is no error code set.
    1286          */
    1287         if (RT_SUCCESS(rc))
    1288         {
    1289             AssertMsgFailed(("Success status code set while out of retries\n"));
    1290             rc = VERR_IPE_UNEXPECTED_STATUS;
    1291         }
    1292         goto out;
    1293     }
    1294 
    12951317    if (!iscsiIsClientConnected(pImage))
    12961318    {
    12971319        rc = iscsiTransportOpen(pImage);
    12981320        if (RT_FAILURE(rc))
    1299             goto out;
     1321            return rc;
    13001322    }
    13011323
     
    13171339    isid_tsih = pImage->ISID << 16;  /* TSIH field currently always 0 */
    13181340
    1319     do {
     1341    do
     1342    {
    13201343        transit = false;
    13211344        cbBuf = 0;
     
    13261349                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "SessionType", "Normal", 0);
    13271350                if (RT_FAILURE(rc))
    1328                     goto out;
     1351                    break;
    13291352                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "InitiatorName", pImage->pszInitiatorName, 0);
    13301353                if (RT_FAILURE(rc))
    1331                     goto out;
     1354                    break;
    13321355                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "TargetName", pImage->pszTargetName, 0);
    13331356                if (RT_FAILURE(rc))
    1334                     goto out;
     1357                    break;
    13351358                if (pImage->pszInitiatorUsername == NULL)
    13361359                {
     
    13381361                    rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "AuthMethod", "None", 0);
    13391362                    if (RT_FAILURE(rc))
    1340                         goto out;
     1363                        break;
    13411364                    nsg = 1;
    13421365                    transit = true;
    13431366                }
    13441367                else
    1345                 {
    13461368                    rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "AuthMethod", "CHAP,None", 0);
    1347                     if (RT_FAILURE(rc))
    1348                         goto out;
    1349                 }
    13501369                break;
    13511370            case 0x0001:    /* security negotiation, step 1: propose CHAP_MD5 variant. */
    13521371                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_A", "5", 0);
    1353                 if (RT_FAILURE(rc))
    1354                     goto out;
    13551372                break;
    13561373            case 0x0002:    /* security negotiation, step 2: send authentication info. */
    13571374                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_N", pImage->pszInitiatorUsername, 0);
    13581375                if (RT_FAILURE(rc))
    1359                     goto out;
     1376                    break;
    13601377                chap_md5_compute_response(aResponse, bChapIdx, pbChallenge, cbChallenge,
    13611378                                          pImage->pbInitiatorSecret, pImage->cbInitiatorSecret);
    13621379                rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_R", (const char *)aResponse, RTMD5HASHSIZE);
    13631380                if (RT_FAILURE(rc))
    1364                     goto out;
     1381                    break;
    13651382                nsg = 1;
    13661383                transit = true;
     
    13761393                                                  aParameterNeg[i].cbParamValue);
    13771394                        if (RT_FAILURE(rc))
    1378                             goto out;
     1395                            break;
    13791396                    }
    13801397                    fParameterNeg = false;
     
    13901407                break;
    13911408        }
     1409
     1410        if (RT_FAILURE(rc))
     1411            break;
    13921412
    13931413        aReqBHS[0] = RT_H2N_U32(    ISCSI_IMMEDIATE_DELIVERY_BIT
     
    14331453
    14341454            rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes, ISCSIPDU_NO_REATTACH);
    1435             if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
     1455            if (RT_FAILURE(rc))
    14361456            {
    14371457                /*
     
    14391459                 * start from the beginning.
    14401460                 */
    1441                 cRetries--;
    1442                 goto restart;
     1461                if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
     1462                    rc = VERR_TRY_AGAIN;
     1463                break;
    14431464            }
    1444             else if (RT_FAILURE(rc))
    1445                 break;
     1465
    14461466            /** @todo collect partial login responses with Continue bit set. */
    14471467            Assert(aISCSIRes[0].pvSeg == aResBHS);
     
    16281648                            memcpy(pImage->pszTargetAddress, pcszTargetRedir, cb);
    16291649                        }
    1630                         rc = iscsiTransportOpen(pImage);
    1631                         goto restart;
     1650                        rc = VINF_TRY_AGAIN;
     1651                        break;
    16321652                    case ISCSI_LOGIN_STATUS_CLASS_INITIATOR_ERROR:
    16331653                    {
    1634                         const char *pszDetail = NULL;
    1635 
    1636                         switch ((RT_N2H_U32(aResBHS[9]) >> 16) & 0xff)
    1637                         {
    1638                             case 0x00:
    1639                                 pszDetail = "Miscelleanous iSCSI intiaitor error";
    1640                                 break;
    1641                             case 0x01:
    1642                                 pszDetail = "Authentication failure";
    1643                                 break;
    1644                             case 0x02:
    1645                                 pszDetail = "Authorization failure";
    1646                                 break;
    1647                             case 0x03:
    1648                                 pszDetail = "Not found";
    1649                                 break;
    1650                             case 0x04:
    1651                                 pszDetail = "Target removed";
    1652                                 break;
    1653                             case 0x05:
    1654                                 pszDetail = "Unsupported version";
    1655                                 break;
    1656                             case 0x06:
    1657                                 pszDetail = "Too many connections";
    1658                                 break;
    1659                             case 0x07:
    1660                                 pszDetail = "Missing parameter";
    1661                                 break;
    1662                             case 0x08:
    1663                                 pszDetail = "Can't include in session";
    1664                                 break;
    1665                             case 0x09:
    1666                                 pszDetail = "Session type not supported";
    1667                                 break;
    1668                             case 0x0a:
    1669                                 pszDetail = "Session does not exist";
    1670                                 break;
    1671                             case 0x0b:
    1672                                 pszDetail = "Invalid request type during login";
    1673                                 break;
    1674                             default:
    1675                                 pszDetail = "Unknown status detail";
    1676                         }
    1677                         LogRel(("iSCSI: login to target failed with: %s\n", pszDetail));
     1654                        LogRel(("iSCSI: login to target failed with: %s\n",
     1655                                iscsiGetLoginErrorDetail((RT_N2H_U32(aResBHS[9]) >> 16) & 0xff)));
    16781656                        iscsiTransportClose(pImage);
    16791657                        rc = VERR_IO_GEN_FAILURE;
    1680                         goto out;
     1658                        break;
    16811659                    }
    16821660                    case ISCSI_LOGIN_STATUS_CLASS_TARGET_ERROR:
     
    16871665                        rc = VERR_PARSE_ERROR;
    16881666                }
     1667
     1668                if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN)
     1669                    break;
    16891670
    16901671                if (csg == 3)
     
    16981679            }
    16991680            else
    1700             {
    17011681                AssertMsgFailed(("%s: ignoring unexpected PDU with first word = %#08x\n", __FUNCTION__, RT_N2H_U32(aResBHS[0])));
    1702             }
    17031682        }
    17041683        else
     
    17061685    } while (true);
    17071686
    1708 out:
    1709     if (RT_FAILURE(rc))
     1687    if (   RT_FAILURE(rc)
     1688        && rc != VERR_TRY_AGAIN)
    17101689    {
    17111690        /*
     
    17251704        pImage->state = ISCSISTATE_FREE;
    17261705    }
    1727     else
     1706    else if (RT_FAILURE(rc))
    17281707        pImage->state = ISCSISTATE_NORMAL;
     1708
     1709    return rc;
     1710}
     1711
     1712/**
     1713 * Attach to an iSCSI target. Performs all operations necessary to enter
     1714 * Full Feature Phase.
     1715 *
     1716 * @returns VBox status code.
     1717 * @param   pImage      The iSCSI connection state to be used.
     1718 */
     1719static DECLCALLBACK(int) iscsiAttach(void *pvUser)
     1720{
     1721    int rc = VINF_SUCCESS;
     1722    unsigned cRetries = 5;
     1723    PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser;
     1724
     1725    LogFlowFunc(("entering\n"));
     1726
     1727    Assert(pImage->state == ISCSISTATE_FREE);
     1728
     1729    /*
     1730     * If there were too many logins without any successful I/O just fail
     1731     * and assume the target is not working properly.
     1732     */
     1733    if (ASMAtomicReadU32(&pImage->cLoginsSinceIo) == 3)
     1734        return VERR_BROKEN_PIPE;
     1735
     1736    RTSemMutexRequest(pImage->Mutex, RT_INDEFINITE_WAIT);
     1737
     1738    /* Make 100% sure the connection isn't reused for a new login. */
     1739    iscsiTransportClose(pImage);
     1740
     1741    /* Try to log in a few number of times. */
     1742    while (cRetries > 0)
     1743    {
     1744        rc = iscsiLogin(pImage);
     1745        if (rc == VINF_SUCCESS) /* Login succeeded, continue with full feature phase. */
     1746            break;
     1747        else if (rc == VERR_TRY_AGAIN) /* Lost connection during receive. */
     1748            cRetries--;
     1749        else if (RT_FAILURE(rc))
     1750            break;
     1751        else /* For redirects try again. */
     1752            AssertMsg(rc == VINF_TRY_AGAIN, ("Unexpected status code %Rrc\n", rc));
     1753    }
    17291754
    17301755    if (RT_SUCCESS(rc))
     
    18691894     * cannot be established. Get out before bad things happen (and make
    18701895     * sure the caller suspends the VM again). */
    1871     if (pImage->state != ISCSISTATE_NORMAL)
    1872     {
    1873         rc = VERR_NET_CONNECTION_REFUSED;
    1874         goto out;
    1875     }
    1876 
    1877     /*
    1878      * Send SCSI command to target with all I2T data included.
    1879      */
    1880     cbData = 0;
    1881     if (pRequest->enmXfer == SCSIXFER_FROM_TARGET)
    1882         cbData = (uint32_t)pRequest->cbT2IData;
    1883     else
    1884         cbData = (uint32_t)pRequest->cbI2TData;
    1885 
    1886     RTSemMutexRequest(pImage->Mutex, RT_INDEFINITE_WAIT);
    1887 
    1888     itt = iscsiNewITT(pImage);
    1889     memset(aReqBHS, 0, sizeof(aReqBHS));
    1890     aReqBHS[0] = RT_H2N_U32(    ISCSI_FINAL_BIT | ISCSI_TASK_ATTR_SIMPLE | ISCSIOP_SCSI_CMD
    1891                             |   (pRequest->enmXfer << 21)); /* I=0,F=1,Attr=Simple */
    1892     aReqBHS[1] = RT_H2N_U32(0x00000000 | ((uint32_t)pRequest->cbI2TData & 0xffffff)); /* TotalAHSLength=0 */
    1893     aReqBHS[2] = RT_H2N_U32(pImage->LUN >> 32);
    1894     aReqBHS[3] = RT_H2N_U32(pImage->LUN & 0xffffffff);
    1895     aReqBHS[4] = itt;
    1896     aReqBHS[5] = RT_H2N_U32(cbData);
    1897     aReqBHS[6] = RT_H2N_U32(pImage->CmdSN);
    1898     aReqBHS[7] = RT_H2N_U32(pImage->ExpStatSN);
    1899     memcpy(aReqBHS + 8, pRequest->abCDB, pRequest->cbCDB);
    1900     pImage->CmdSN++;
    1901 
    1902     aISCSIReq[cnISCSIReq].pcvSeg = aReqBHS;
    1903     aISCSIReq[cnISCSIReq].cbSeg = sizeof(aReqBHS);
    1904     cnISCSIReq++;
    1905 
    1906     if (    pRequest->enmXfer == SCSIXFER_TO_TARGET
    1907         ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
    1908     {
    1909         Assert(pRequest->cI2TSegs == 1);
    1910         aISCSIReq[cnISCSIReq].pcvSeg = pRequest->paI2TSegs[0].pvSeg;
    1911         aISCSIReq[cnISCSIReq].cbSeg = pRequest->paI2TSegs[0].cbSeg;  /* Padding done by transport. */
     1896    if (pImage->state == ISCSISTATE_NORMAL)
     1897    {
     1898        /*
     1899         * Send SCSI command to target with all I2T data included.
     1900         */
     1901        cbData = 0;
     1902        if (pRequest->enmXfer == SCSIXFER_FROM_TARGET)
     1903            cbData = (uint32_t)pRequest->cbT2IData;
     1904        else
     1905            cbData = (uint32_t)pRequest->cbI2TData;
     1906
     1907        RTSemMutexRequest(pImage->Mutex, RT_INDEFINITE_WAIT);
     1908
     1909        itt = iscsiNewITT(pImage);
     1910        memset(aReqBHS, 0, sizeof(aReqBHS));
     1911        aReqBHS[0] = RT_H2N_U32(    ISCSI_FINAL_BIT | ISCSI_TASK_ATTR_SIMPLE | ISCSIOP_SCSI_CMD
     1912                                |   (pRequest->enmXfer << 21)); /* I=0,F=1,Attr=Simple */
     1913        aReqBHS[1] = RT_H2N_U32(0x00000000 | ((uint32_t)pRequest->cbI2TData & 0xffffff)); /* TotalAHSLength=0 */
     1914        aReqBHS[2] = RT_H2N_U32(pImage->LUN >> 32);
     1915        aReqBHS[3] = RT_H2N_U32(pImage->LUN & 0xffffffff);
     1916        aReqBHS[4] = itt;
     1917        aReqBHS[5] = RT_H2N_U32(cbData);
     1918        aReqBHS[6] = RT_H2N_U32(pImage->CmdSN);
     1919        aReqBHS[7] = RT_H2N_U32(pImage->ExpStatSN);
     1920        memcpy(aReqBHS + 8, pRequest->abCDB, pRequest->cbCDB);
     1921        pImage->CmdSN++;
     1922
     1923        aISCSIReq[cnISCSIReq].pcvSeg = aReqBHS;
     1924        aISCSIReq[cnISCSIReq].cbSeg = sizeof(aReqBHS);
    19121925        cnISCSIReq++;
    1913     }
    1914 
    1915     rc = iscsiSendPDU(pImage, aISCSIReq, cnISCSIReq, ISCSIPDU_DEFAULT);
    1916     if (RT_FAILURE(rc))
    1917         goto out_release;
    1918 
    1919     /* Place SCSI request in queue. */
    1920     pImage->paCurrReq = aISCSIReq;
    1921     pImage->cnCurrReq = cnISCSIReq;
    1922 
    1923     /*
    1924      * Read SCSI response/data in PDUs from target.
    1925      */
    1926     if (    pRequest->enmXfer == SCSIXFER_FROM_TARGET
    1927         ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
    1928     {
    1929         Assert(pRequest->cT2ISegs == 1);
    1930         pDst = (uint32_t *)pRequest->paT2ISegs[0].pvSeg;
    1931         cbBufLength = pRequest->paT2ISegs[0].cbSeg;
    1932     }
    1933     else
    1934         cbBufLength = 0;
    1935 
    1936     do {
    1937         uint32_t cnISCSIRes = 0;
    1938         ISCSIRES aISCSIRes[4];
    1939         uint32_t aResBHS[12];
    1940 
    1941         aISCSIRes[cnISCSIRes].pvSeg = aResBHS;
    1942         aISCSIRes[cnISCSIRes].cbSeg = sizeof(aResBHS);
    1943         cnISCSIRes++;
    1944         if (cbBufLength != 0 &&
    1945             (   pRequest->enmXfer == SCSIXFER_FROM_TARGET
    1946              ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET))
    1947         {
    1948             aISCSIRes[cnISCSIRes].pvSeg = pDst;
    1949             aISCSIRes[cnISCSIRes].cbSeg = cbBufLength;
    1950             cnISCSIRes++;
    1951         }
    1952         /* Always reserve space for the status - it's impossible to tell
    1953          * beforehand whether this will be the final PDU or not. */
    1954         aISCSIRes[cnISCSIRes].pvSeg = aStatus;
    1955         aISCSIRes[cnISCSIRes].cbSeg = sizeof(aStatus);
    1956         cnISCSIRes++;
    1957 
    1958         rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes, ISCSIPDU_DEFAULT);
    1959         if (RT_FAILURE(rc))
    1960             break;
    1961 
    1962         final = !!(RT_N2H_U32(aResBHS[0]) & ISCSI_FINAL_BIT);
    1963         ISCSIOPCODE cmd = (ISCSIOPCODE)(RT_N2H_U32(aResBHS[0]) & ISCSIOP_MASK);
    1964         if (cmd == ISCSIOP_SCSI_RES)
    1965         {
    1966             /* This is the final PDU which delivers the status (and may be omitted if
    1967              * the last Data-In PDU included successful completion status). Note
    1968              * that ExpStatSN has been bumped already in iscsiRecvPDU. */
    1969             if (!final || ((RT_N2H_U32(aResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(aResBHS[6]) != pImage->ExpStatSN - 1))
     1926
     1927        if (    pRequest->enmXfer == SCSIXFER_TO_TARGET
     1928            ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
     1929        {
     1930            Assert(pRequest->cI2TSegs == 1);
     1931            aISCSIReq[cnISCSIReq].pcvSeg = pRequest->paI2TSegs[0].pvSeg;
     1932            aISCSIReq[cnISCSIReq].cbSeg = pRequest->paI2TSegs[0].cbSeg;  /* Padding done by transport. */
     1933            cnISCSIReq++;
     1934        }
     1935
     1936        rc = iscsiSendPDU(pImage, aISCSIReq, cnISCSIReq, ISCSIPDU_DEFAULT);
     1937        if (RT_SUCCESS(rc))
     1938        {
     1939            /* Place SCSI request in queue. */
     1940            pImage->paCurrReq = aISCSIReq;
     1941            pImage->cnCurrReq = cnISCSIReq;
     1942
     1943            /*
     1944             * Read SCSI response/data in PDUs from target.
     1945             */
     1946            if (    pRequest->enmXfer == SCSIXFER_FROM_TARGET
     1947                ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
    19701948            {
    1971                 /* SCSI Response in the wrong place or with a (target) failure. */
    1972                 rc = VERR_PARSE_ERROR;
    1973                 break;
     1949                Assert(pRequest->cT2ISegs == 1);
     1950                pDst = (uint32_t *)pRequest->paT2ISegs[0].pvSeg;
     1951                cbBufLength = pRequest->paT2ISegs[0].cbSeg;
    19741952            }
    1975             /* The following is a bit tricky, as in error situations we may
    1976              * get the status only instead of the result data plus optional
    1977              * status. Thus the status may have ended up partially in the
    1978              * data area. */
    1979             pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
    1980             cbData = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
    1981             if (cbData >= 2)
     1953            else
     1954                cbBufLength = 0;
     1955
     1956            do
    19821957            {
    1983                 uint32_t cbStat = RT_N2H_U32(((uint32_t *)aISCSIRes[1].pvSeg)[0]) >> 16;
    1984                 if (cbStat + 2 > cbData)
     1958                uint32_t cnISCSIRes = 0;
     1959                ISCSIRES aISCSIRes[4];
     1960                uint32_t aResBHS[12];
     1961
     1962                aISCSIRes[cnISCSIRes].pvSeg = aResBHS;
     1963                aISCSIRes[cnISCSIRes].cbSeg = sizeof(aResBHS);
     1964                cnISCSIRes++;
     1965                if (cbBufLength != 0 &&
     1966                    (   pRequest->enmXfer == SCSIXFER_FROM_TARGET
     1967                     ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET))
    19851968                {
    1986                     rc = VERR_BUFFER_OVERFLOW;
     1969                    aISCSIRes[cnISCSIRes].pvSeg = pDst;
     1970                    aISCSIRes[cnISCSIRes].cbSeg = cbBufLength;
     1971                    cnISCSIRes++;
     1972                }
     1973                /* Always reserve space for the status - it's impossible to tell
     1974                 * beforehand whether this will be the final PDU or not. */
     1975                aISCSIRes[cnISCSIRes].pvSeg = aStatus;
     1976                aISCSIRes[cnISCSIRes].cbSeg = sizeof(aStatus);
     1977                cnISCSIRes++;
     1978
     1979                rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes, ISCSIPDU_DEFAULT);
     1980                if (RT_FAILURE(rc))
     1981                    break;
     1982
     1983                final = !!(RT_N2H_U32(aResBHS[0]) & ISCSI_FINAL_BIT);
     1984                ISCSIOPCODE cmd = (ISCSIOPCODE)(RT_N2H_U32(aResBHS[0]) & ISCSIOP_MASK);
     1985                if (cmd == ISCSIOP_SCSI_RES)
     1986                {
     1987                    /* This is the final PDU which delivers the status (and may be omitted if
     1988                     * the last Data-In PDU included successful completion status). Note
     1989                     * that ExpStatSN has been bumped already in iscsiRecvPDU. */
     1990                    if (!final || ((RT_N2H_U32(aResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(aResBHS[6]) != pImage->ExpStatSN - 1))
     1991                    {
     1992                        /* SCSI Response in the wrong place or with a (target) failure. */
     1993                        rc = VERR_PARSE_ERROR;
     1994                        break;
     1995                    }
     1996                    /* The following is a bit tricky, as in error situations we may
     1997                     * get the status only instead of the result data plus optional
     1998                     * status. Thus the status may have ended up partially in the
     1999                     * data area. */
     2000                    pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
     2001                    cbData = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
     2002                    if (cbData >= 2)
     2003                    {
     2004                        uint32_t cbStat = RT_N2H_U32(((uint32_t *)aISCSIRes[1].pvSeg)[0]) >> 16;
     2005                        if (cbStat + 2 > cbData)
     2006                        {
     2007                            rc = VERR_BUFFER_OVERFLOW;
     2008                            break;
     2009                        }
     2010                        /* Truncate sense data if it doesn't fit into the buffer. */
     2011                        pRequest->cbSense = RT_MIN(cbStat, pRequest->cbSense);
     2012                        memcpy(pRequest->abSense,
     2013                               ((const char *)aISCSIRes[1].pvSeg) + 2,
     2014                               RT_MIN(aISCSIRes[1].cbSeg - 2, pRequest->cbSense));
     2015                        if (   cnISCSIRes > 2 && aISCSIRes[2].cbSeg
     2016                            && (ssize_t)pRequest->cbSense - aISCSIRes[1].cbSeg + 2 > 0)
     2017                        {
     2018                            memcpy((char *)pRequest->abSense + aISCSIRes[1].cbSeg - 2,
     2019                                   aISCSIRes[2].pvSeg,
     2020                                   pRequest->cbSense - aISCSIRes[1].cbSeg + 2);
     2021                        }
     2022                    }
     2023                    else if (cbData == 1)
     2024                    {
     2025                        rc = VERR_PARSE_ERROR;
     2026                        break;
     2027                    }
     2028                    else
     2029                        pRequest->cbSense = 0;
    19872030                    break;
    19882031                }
    1989                 /* Truncate sense data if it doesn't fit into the buffer. */
    1990                 pRequest->cbSense = RT_MIN(cbStat, pRequest->cbSense);
    1991                 memcpy(pRequest->abSense,
    1992                        ((const char *)aISCSIRes[1].pvSeg) + 2,
    1993                        RT_MIN(aISCSIRes[1].cbSeg - 2, pRequest->cbSense));
    1994                 if (   cnISCSIRes > 2 && aISCSIRes[2].cbSeg
    1995                     && (ssize_t)pRequest->cbSense - aISCSIRes[1].cbSeg + 2 > 0)
     2032                else if (cmd == ISCSIOP_SCSI_DATA_IN)
    19962033                {
    1997                     memcpy((char *)pRequest->abSense + aISCSIRes[1].cbSeg - 2,
    1998                            aISCSIRes[2].pvSeg,
    1999                            pRequest->cbSense - aISCSIRes[1].cbSeg + 2);
     2034                    /* A Data-In PDU carries some data that needs to be added to the received
     2035                     * data in response to the command. There may be both partial and complete
     2036                     * Data-In PDUs, so collect data until the status is included or the status
     2037                     * is sent in a separate SCSI Result frame (see above). */
     2038                    if (final && aISCSIRes[2].cbSeg != 0)
     2039                    {
     2040                        /* The received PDU is partially stored in the buffer for status.
     2041                         * Must not happen under normal circumstances and is a target error. */
     2042                        rc = VERR_BUFFER_OVERFLOW;
     2043                        break;
     2044                    }
     2045                    uint32_t len = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
     2046                    pDst = (uint32_t *)((char *)pDst + len);
     2047                    cbBufLength -= len;
     2048                    ExpDataSN++;
     2049                    if (final && (RT_N2H_U32(aResBHS[0]) & ISCSI_STATUS_BIT) != 0)
     2050                    {
     2051                        pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
     2052                        pRequest->cbSense = 0;
     2053                        break;
     2054                    }
    20002055                }
    2001             }
    2002             else if (cbData == 1)
    2003             {
    2004                 rc = VERR_PARSE_ERROR;
    2005                 break;
    2006             }
    2007             else
    2008                 pRequest->cbSense = 0;
    2009             break;
    2010         }
    2011         else if (cmd == ISCSIOP_SCSI_DATA_IN)
    2012         {
    2013             /* A Data-In PDU carries some data that needs to be added to the received
    2014              * data in response to the command. There may be both partial and complete
    2015              * Data-In PDUs, so collect data until the status is included or the status
    2016              * is sent in a separate SCSI Result frame (see above). */
    2017             if (final && aISCSIRes[2].cbSeg != 0)
    2018             {
    2019                 /* The received PDU is partially stored in the buffer for status.
    2020                  * Must not happen under normal circumstances and is a target error. */
    2021                 rc = VERR_BUFFER_OVERFLOW;
    2022                 break;
    2023             }
    2024             uint32_t len = RT_N2H_U32(aResBHS[1]) & 0x00ffffff;
    2025             pDst = (uint32_t *)((char *)pDst + len);
    2026             cbBufLength -= len;
    2027             ExpDataSN++;
    2028             if (final && (RT_N2H_U32(aResBHS[0]) & ISCSI_STATUS_BIT) != 0)
    2029             {
    2030                 pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff;
    2031                 pRequest->cbSense = 0;
    2032                 break;
    2033             }
    2034         }
    2035         else
    2036         {
    2037             rc = VERR_PARSE_ERROR;
    2038             break;
    2039         }
    2040     } while (true);
    2041 
    2042     /* Remove SCSI request from queue. */
    2043     pImage->paCurrReq = NULL;
    2044     pImage->cnCurrReq = 0;
    2045 
    2046 out_release:
    2047     if (rc == VERR_TIMEOUT)
    2048     {
    2049         /* Drop connection in case the target plays dead. Much better than
    2050          * delaying the next requests until the timed out command actually
    2051          * finishes. Also keep in mind that command shouldn't take longer than
    2052          * about 30-40 seconds, or the guest will lose its patience. */
    2053         iscsiTransportClose(pImage);
    2054         pImage->state = ISCSISTATE_FREE;
    2055         rc = VERR_BROKEN_PIPE;
    2056     }
    2057     RTSemMutexRelease(pImage->Mutex);
    2058 
    2059 out:
     2056                else
     2057                {
     2058                    rc = VERR_PARSE_ERROR;
     2059                    break;
     2060                }
     2061            } while (true);
     2062
     2063            /* Remove SCSI request from queue. */
     2064            pImage->paCurrReq = NULL;
     2065            pImage->cnCurrReq = 0;
     2066        }
     2067
     2068        if (rc == VERR_TIMEOUT)
     2069        {
     2070            /* Drop connection in case the target plays dead. Much better than
     2071             * delaying the next requests until the timed out command actually
     2072             * finishes. Also keep in mind that command shouldn't take longer than
     2073             * about 30-40 seconds, or the guest will lose its patience. */
     2074            iscsiTransportClose(pImage);
     2075            pImage->state = ISCSISTATE_FREE;
     2076            rc = VERR_BROKEN_PIPE;
     2077        }
     2078        RTSemMutexRelease(pImage->Mutex);
     2079    }
     2080    else
     2081        rc = VERR_NET_CONNECTION_REFUSED;
     2082
    20602083    if (RT_SUCCESS(rc))
    20612084        ASMAtomicWriteU32(&pImage->cLoginsSinceIo, 0);
     
    46864709                                   VDTYPE enmType, void **ppBackendData)
    46874710{
    4688     LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n", pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
     4711    RT_NOREF1(enmType); /**< @todo r=klaus make use of the type info. */
     4712
     4713    LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x pVDIfsDisk=%#p pVDIfsImage=%#p enmType=%u ppBackendData=%#p\n",
     4714                 pszFilename, uOpenFlags, pVDIfsDisk, pVDIfsImage, enmType, ppBackendData));
    46894715    int rc;
    4690     PISCSIIMAGE pImage;
    4691 
    4692     NOREF(enmType); /**< @todo r=klaus make use of the type info. */
    46934716
    46944717    /* Check open flags. All valid flags are supported. */
    4695     if (uOpenFlags & ~VD_OPEN_FLAGS_MASK)
    4696     {
    4697         rc = VERR_INVALID_PARAMETER;
    4698         goto out;
    4699     }
    4700 
    4701     /* Check remaining arguments. */
    4702     if (   !VALID_PTR(pszFilename)
    4703         || !*pszFilename
    4704         || strchr(pszFilename, '"'))
    4705     {
    4706         rc = VERR_INVALID_PARAMETER;
    4707         goto out;
    4708     }
    4709 
    4710     pImage = (PISCSIIMAGE)RTMemAllocZ(sizeof(ISCSIIMAGE));
    4711     if (!pImage)
    4712     {
     4718    AssertReturn(!(uOpenFlags & ~VD_OPEN_FLAGS_MASK), VERR_INVALID_PARAMETER);
     4719    AssertReturn((VALID_PTR(pszFilename) && *pszFilename), VERR_INVALID_PARAMETER);
     4720
     4721    PISCSIIMAGE pImage = (PISCSIIMAGE)RTMemAllocZ(sizeof(ISCSIIMAGE));
     4722    if (RT_LIKELY(pImage))
     4723    {
     4724        pImage->pszFilename = pszFilename;
     4725        pImage->pszInitiatorName = NULL;
     4726        pImage->pszTargetName = NULL;
     4727        pImage->pszTargetAddress = NULL;
     4728        pImage->pszInitiatorUsername = NULL;
     4729        pImage->pbInitiatorSecret = NULL;
     4730        pImage->pszTargetUsername = NULL;
     4731        pImage->pbTargetSecret = NULL;
     4732        pImage->paCurrReq = NULL;
     4733        pImage->pvRecvPDUBuf = NULL;
     4734        pImage->pszHostname = NULL;
     4735        pImage->pVDIfsDisk = pVDIfsDisk;
     4736        pImage->pVDIfsImage = pVDIfsImage;
     4737        pImage->cLogRelErrors = 0;
     4738
     4739        rc = iscsiOpenImage(pImage, uOpenFlags);
     4740        if (RT_SUCCESS(rc))
     4741        {
     4742            LogFlowFunc(("target %s cVolume %d, cbSector %d\n", pImage->pszTargetName, pImage->cVolume, pImage->cbSector));
     4743            LogRel(("iSCSI: target address %s, target name %s, SCSI LUN %lld\n", pImage->pszTargetAddress, pImage->pszTargetName, pImage->LUN));
     4744            *ppBackendData = pImage;
     4745        }
     4746        else
     4747            RTMemFree(pImage);
     4748    }
     4749    else
    47134750        rc = VERR_NO_MEMORY;
    4714         goto out;
    4715     }
    4716 
    4717     pImage->pszFilename = pszFilename;
    4718     pImage->pszInitiatorName = NULL;
    4719     pImage->pszTargetName = NULL;
    4720     pImage->pszTargetAddress = NULL;
    4721     pImage->pszInitiatorUsername = NULL;
    4722     pImage->pbInitiatorSecret = NULL;
    4723     pImage->pszTargetUsername = NULL;
    4724     pImage->pbTargetSecret = NULL;
    4725     pImage->paCurrReq = NULL;
    4726     pImage->pvRecvPDUBuf = NULL;
    4727     pImage->pszHostname = NULL;
    4728     pImage->pVDIfsDisk = pVDIfsDisk;
    4729     pImage->pVDIfsImage = pVDIfsImage;
    4730     pImage->cLogRelErrors = 0;
    4731 
    4732     rc = iscsiOpenImage(pImage, uOpenFlags);
    4733     if (RT_SUCCESS(rc))
    4734     {
    4735         LogFlowFunc(("target %s cVolume %d, cbSector %d\n", pImage->pszTargetName, pImage->cVolume, pImage->cbSector));
    4736         LogRel(("iSCSI: target address %s, target name %s, SCSI LUN %lld\n", pImage->pszTargetAddress, pImage->pszTargetName, pImage->LUN));
    4737         *ppBackendData = pImage;
    4738     }
    4739     else
    4740         RTMemFree(pImage);
    4741 
    4742 out:
     4751
    47434752    LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData));
    47444753    return rc;
Note: See TracChangeset for help on using the changeset viewer.

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