Changeset 22256 in vbox
- Timestamp:
- Aug 14, 2009 12:33:11 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 51078
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp
r21839 r22256 109 109 110 110 /** Maximum PDU payload size we can handle in one piece. */ 111 #define ISCSI_ PDU_SIZE_MAX _256K111 #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 … … 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; … … 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 * … … 399 419 400 420 /** Default initiator name. */ 401 static const char *s_iscsiConfigDefaultInitiatorName = "iqn.200 8-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. */ … … 814 834 uint32_t aResBHS[12]; 815 835 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 816 864 LogFlowFunc(("entering\n")); 817 865 … … 891 939 break; 892 940 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 937 955 nsg = 3; 938 956 transit = true; … … 977 995 ISCSIOPCODE cmd; 978 996 ISCSILOGINSTATUSCLASS loginStatusClass; 979 980 /* Place login request in queue. */981 pImage->paCurrReq = aISCSIReq;982 pImage->cnCurrReq = cnISCSIReq;983 997 984 998 cnISCSIRes = 0; … … 1110 1124 break; 1111 1125 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 1112 1191 if (targetCSG == 1 && targetNSG == 3 && targetTransit) 1113 1192 { … … 1118 1197 break; 1119 1198 } 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 } 1120 1207 rc = VERR_PARSE_ERROR; 1121 1208 break; 1209 } 1122 1210 case 0x0300: /* full feature phase. */ 1123 1211 default: … … 1153 1241 case ISCSI_LOGIN_STATUS_CLASS_INITIATOR_ERROR: 1154 1242 iscsiTransportClose(pImage); 1155 pImage->paCurrReq = NULL;1156 pImage->cnCurrReq = 0;1157 1243 rc = VERR_IO_GEN_FAILURE; 1158 1244 goto out; … … 1164 1250 rc = VERR_PARSE_ERROR; 1165 1251 } 1166 1167 /* Remove login request from queue. */1168 pImage->paCurrReq = NULL;1169 pImage->cnCurrReq = 0;1170 1252 1171 1253 if (csg == 3) … … 1253 1335 if (RT_SUCCESS(rc)) 1254 1336 { 1255 /* Place logout request in queue. */1256 pImage->paCurrReq = aISCSIReq;1257 pImage->cnCurrReq = cnISCSIReq;1258 1259 1337 /* 1260 1338 * Read logout response from target. … … 1273 1351 else 1274 1352 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 1353 } 1280 1354 else … … 1436 1510 { 1437 1511 /* 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)) 1440 1515 { 1441 1516 /* SCSI Response in the wrong place or with a (target) failure. */ … … 1443 1518 break; 1444 1519 } 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. */ 1445 1524 pRequest->status = RT_N2H_U32(aResBHS[0]) & 0x000000ff; 1446 1525 uint32_t cbData = RT_N2H_U32(aResBHS[1]) & 0x00ffffff; 1447 1526 if (cbData >= 2) 1448 1527 { 1449 uint32_t cbStat = RT_N2H_U32( aStat[0]) >> 16;1528 uint32_t cbStat = RT_N2H_U32(((uint32_t *)aISCSIRes[1].pvSeg)[0]) >> 16; 1450 1529 if (cbStat + 2 > cbData || cbStat > pRequest->cbSense) 1451 1530 { … … 1453 1532 break; 1454 1533 } 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); 1457 1538 } 1458 1539 else if (cbData == 1) … … 1461 1542 break; 1462 1543 } 1544 else 1545 pRequest->cbSense = 0; 1463 1546 break; 1464 1547 } … … 1560 1643 if (rc != VERR_BROKEN_PIPE && rc != VERR_NET_CONNECTION_REFUSED) 1561 1644 break; 1645 /* No point in reestablishing the connection for a logout */ 1646 if (pImage->state == ISCSISTATE_IN_LOGOUT) 1647 break; 1562 1648 RTThreadSleep(500); 1563 if ( pImage->state != ISCSISTATE_IN_LOGIN 1564 && pImage->state != ISCSISTATE_IN_LOGOUT) 1649 if (pImage->state != ISCSISTATE_IN_LOGIN) 1565 1650 { 1566 1651 /* Attempt to re-login when a connection fails, but only when not 1567 * currently logging in or logging out. */1652 * currently logging in. */ 1568 1653 rc = iscsiAttach(pImage); 1569 1654 if (RT_FAILURE(rc)) … … 1601 1686 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED) 1602 1687 { 1688 /* No point in reestablishing the connection for a logout */ 1689 if (pImage->state == ISCSISTATE_IN_LOGOUT) 1690 break; 1603 1691 /* Connection broken while waiting for a response - wait a while and 1604 1692 * try to restart by re-sending the original request (if any). 1605 1693 * This also handles the connection reestablishment (login etc.). */ 1606 1694 RTThreadSleep(500); 1607 if ( pImage->state != ISCSISTATE_IN_LOGIN 1608 && pImage->state != ISCSISTATE_IN_LOGOUT) 1695 if (pImage->state != ISCSISTATE_IN_LOGIN) 1609 1696 { 1610 1697 /* Attempt to re-login when a connection fails, but only when not 1611 * currently logging in or logging out. */1698 * currently logging in. */ 1612 1699 rc = iscsiAttach(pImage); 1613 1700 if (RT_FAILURE(rc)) … … 2764 2851 2765 2852 /* 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. 2767 2854 */ 2768 cbToRead = RT_MIN(cbToRead, ISCSI_PDU_SIZE_MAX);2855 cbToRead = RT_MIN(cbToRead, pImage->cbRecvDataLength); 2769 2856 2770 2857 lba = uOffset / pImage->cbSector; … … 2795 2882 sr.pvSense = sense; 2796 2883 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 } 2798 2892 if (RT_FAILURE(rc)) 2799 2893 { … … 2802 2896 } 2803 2897 else 2804 *pcbActuallyRead = cbToRead;2898 *pcbActuallyRead = sr.cbT2IData; 2805 2899 2806 2900 out: … … 2838 2932 2839 2933 /* 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. 2841 2935 */ 2842 cbToWrite = RT_MIN(cbToWrite, ISCSI_PDU_SIZE_MAX);2936 cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength); 2843 2937 2844 2938 lba = uOffset / pImage->cbSector; … … 2869 2963 sr.pvSense = sense; 2870 2964 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 } 2872 2973 if (RT_FAILURE(rc)) 2873 2974 {
Note:
See TracChangeset
for help on using the changeset viewer.