Changeset 63880 in vbox for trunk/src/VBox/Storage
- Timestamp:
- Sep 19, 2016 11:31:10 AM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 110744
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Storage/ISCSI.cpp
r63829 r63880 1208 1208 } 1209 1209 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 */ 1216 static 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. 1214 1267 * 1215 1268 * @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. 1216 1272 * @param pImage The iSCSI connection state to be used. 1217 1273 */ 1218 static DECLCALLBACK(int) iscsiAttach(void *pvUser)1219 { 1220 int rc = VINF_SUCCESS; /* (MSC is used uninitialized) */1274 static int iscsiLogin(PISCSIIMAGE pImage) 1275 { 1276 int rc = VINF_SUCCESS; 1221 1277 uint32_t itt; 1222 1278 uint32_t csg, nsg, substate; … … 1235 1291 ISCSIRES aISCSIRes[2]; 1236 1292 uint32_t aResBHS[12]; 1237 unsigned cRetries = 5;1238 1293 char *pszNext; 1239 PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser; 1240 1241 bool fParameterNeg = true;; 1294 bool fParameterNeg = true; 1242 1295 pImage->cbRecvDataLength = ISCSI_DATA_LENGTH_MAX; 1243 1296 pImage->cbSendDataLength = RT_MIN(ISCSI_DATA_LENGTH_MAX, pImage->cbWriteSplit); … … 1262 1315 }; 1263 1316 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 fail1270 * 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 1295 1317 if (!iscsiIsClientConnected(pImage)) 1296 1318 { 1297 1319 rc = iscsiTransportOpen(pImage); 1298 1320 if (RT_FAILURE(rc)) 1299 goto out;1321 return rc; 1300 1322 } 1301 1323 … … 1317 1339 isid_tsih = pImage->ISID << 16; /* TSIH field currently always 0 */ 1318 1340 1319 do { 1341 do 1342 { 1320 1343 transit = false; 1321 1344 cbBuf = 0; … … 1326 1349 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "SessionType", "Normal", 0); 1327 1350 if (RT_FAILURE(rc)) 1328 goto out;1351 break; 1329 1352 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "InitiatorName", pImage->pszInitiatorName, 0); 1330 1353 if (RT_FAILURE(rc)) 1331 goto out;1354 break; 1332 1355 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "TargetName", pImage->pszTargetName, 0); 1333 1356 if (RT_FAILURE(rc)) 1334 goto out;1357 break; 1335 1358 if (pImage->pszInitiatorUsername == NULL) 1336 1359 { … … 1338 1361 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "AuthMethod", "None", 0); 1339 1362 if (RT_FAILURE(rc)) 1340 goto out;1363 break; 1341 1364 nsg = 1; 1342 1365 transit = true; 1343 1366 } 1344 1367 else 1345 {1346 1368 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "AuthMethod", "CHAP,None", 0); 1347 if (RT_FAILURE(rc))1348 goto out;1349 }1350 1369 break; 1351 1370 case 0x0001: /* security negotiation, step 1: propose CHAP_MD5 variant. */ 1352 1371 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_A", "5", 0); 1353 if (RT_FAILURE(rc))1354 goto out;1355 1372 break; 1356 1373 case 0x0002: /* security negotiation, step 2: send authentication info. */ 1357 1374 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_N", pImage->pszInitiatorUsername, 0); 1358 1375 if (RT_FAILURE(rc)) 1359 goto out;1376 break; 1360 1377 chap_md5_compute_response(aResponse, bChapIdx, pbChallenge, cbChallenge, 1361 1378 pImage->pbInitiatorSecret, pImage->cbInitiatorSecret); 1362 1379 rc = iscsiTextAddKeyValue(bBuf, sizeof(bBuf), &cbBuf, "CHAP_R", (const char *)aResponse, RTMD5HASHSIZE); 1363 1380 if (RT_FAILURE(rc)) 1364 goto out;1381 break; 1365 1382 nsg = 1; 1366 1383 transit = true; … … 1376 1393 aParameterNeg[i].cbParamValue); 1377 1394 if (RT_FAILURE(rc)) 1378 goto out;1395 break; 1379 1396 } 1380 1397 fParameterNeg = false; … … 1390 1407 break; 1391 1408 } 1409 1410 if (RT_FAILURE(rc)) 1411 break; 1392 1412 1393 1413 aReqBHS[0] = RT_H2N_U32( ISCSI_IMMEDIATE_DELIVERY_BIT … … 1433 1453 1434 1454 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)) 1436 1456 { 1437 1457 /* … … 1439 1459 * start from the beginning. 1440 1460 */ 1441 cRetries--; 1442 goto restart; 1461 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED) 1462 rc = VERR_TRY_AGAIN; 1463 break; 1443 1464 } 1444 else if (RT_FAILURE(rc)) 1445 break; 1465 1446 1466 /** @todo collect partial login responses with Continue bit set. */ 1447 1467 Assert(aISCSIRes[0].pvSeg == aResBHS); … … 1628 1648 memcpy(pImage->pszTargetAddress, pcszTargetRedir, cb); 1629 1649 } 1630 rc = iscsiTransportOpen(pImage);1631 goto restart;1650 rc = VINF_TRY_AGAIN; 1651 break; 1632 1652 case ISCSI_LOGIN_STATUS_CLASS_INITIATOR_ERROR: 1633 1653 { 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))); 1678 1656 iscsiTransportClose(pImage); 1679 1657 rc = VERR_IO_GEN_FAILURE; 1680 goto out;1658 break; 1681 1659 } 1682 1660 case ISCSI_LOGIN_STATUS_CLASS_TARGET_ERROR: … … 1687 1665 rc = VERR_PARSE_ERROR; 1688 1666 } 1667 1668 if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN) 1669 break; 1689 1670 1690 1671 if (csg == 3) … … 1698 1679 } 1699 1680 else 1700 {1701 1681 AssertMsgFailed(("%s: ignoring unexpected PDU with first word = %#08x\n", __FUNCTION__, RT_N2H_U32(aResBHS[0]))); 1702 }1703 1682 } 1704 1683 else … … 1706 1685 } while (true); 1707 1686 1708 out: 1709 if (RT_FAILURE(rc))1687 if ( RT_FAILURE(rc) 1688 && rc != VERR_TRY_AGAIN) 1710 1689 { 1711 1690 /* … … 1725 1704 pImage->state = ISCSISTATE_FREE; 1726 1705 } 1727 else 1706 else if (RT_FAILURE(rc)) 1728 1707 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 */ 1719 static 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 } 1729 1754 1730 1755 if (RT_SUCCESS(rc)) … … 1869 1894 * cannot be established. Get out before bad things happen (and make 1870 1895 * 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); 1912 1925 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) 1970 1948 { 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; 1974 1952 } 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 1982 1957 { 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)) 1985 1968 { 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; 1987 2030 break; 1988 2031 } 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) 1996 2033 { 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 } 2000 2055 } 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 2060 2083 if (RT_SUCCESS(rc)) 2061 2084 ASMAtomicWriteU32(&pImage->cLoginsSinceIo, 0); … … 4686 4709 VDTYPE enmType, void **ppBackendData) 4687 4710 { 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)); 4689 4715 int rc; 4690 PISCSIIMAGE pImage;4691 4692 NOREF(enmType); /**< @todo r=klaus make use of the type info. */4693 4716 4694 4717 /* 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 4713 4750 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 4743 4752 LogFlowFunc(("returns %Rrc (pBackendData=%#p)\n", rc, *ppBackendData)); 4744 4753 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.