Changeset 31608 in vbox for trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp
- Timestamp:
- Aug 12, 2010 3:48:14 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 64735
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp
r31588 r31608 342 342 /** Length of Target2Initiator data buffer. */ 343 343 size_t cbT2IData; 344 /** Length of sense buffer. */ 344 /** Length of sense buffer 345 * This contains the number of sense bytes received upon completion. */ 345 346 size_t cbSense; 346 347 /** Completion status of the command. */ … … 376 377 /** The sense buffer. */ 377 378 uint8_t abSense[96]; 379 /** Status code to return if we got sense data. */ 380 int rcSense; 381 /** Number of retries if the command completes with sense 382 * data before we return with an error. 383 */ 384 unsigned cSenseRetries; 378 385 /** The number of entries in the I2T S/G list. */ 379 386 unsigned cI2TSegs; … … 661 668 static uint32_t iscsiNewITT(PISCSIIMAGE pImage); 662 669 static int iscsiSendPDU(PISCSIIMAGE pImage, PISCSIREQ paReq, uint32_t cnReq, uint32_t uFlags); 663 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes , bool fSelect);670 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes); 664 671 static int iscsiRecvPDUAsync(PISCSIIMAGE pImage); 665 672 static int iscsiSendPDUAsync(PISCSIIMAGE pImage); … … 777 784 778 785 return pIScsiCmd; 786 } 787 788 /** 789 * Removes all commands from the table and returns the 790 * list head 791 * 792 * @returns Pointer to the head of teh command list. 793 * @param pImage iSCSI connection to use. 794 */ 795 static PISCSICMD iscsiCmdRemoveAll(PISCSIIMAGE pImage) 796 { 797 PISCSICMD pIScsiCmdHead = NULL; 798 799 for (unsigned idx = 0; idx < RT_ELEMENTS(pImage->aCmdsWaiting); idx++) 800 { 801 PISCSICMD pHead; 802 PISCSICMD pTail; 803 804 pHead = pImage->aCmdsWaiting[idx]; 805 pImage->aCmdsWaiting[idx] = NULL; 806 807 /* Get the tail. */ 808 pTail = pHead; 809 while (pTail->pNext) 810 pTail = pTail->pNext; 811 812 /* Concatenate. */ 813 pTail->pNext = pIScsiCmdHead; 814 pIScsiCmdHead = pHead; 815 } 816 817 return pIScsiCmdHead; 779 818 } 780 819 … … 829 868 830 869 831 static int iscsiTransportRead(PISCSIIMAGE pImage, PISCSIRES paResponse, unsigned int cnResponse , bool fSelect)870 static int iscsiTransportRead(PISCSIIMAGE pImage, PISCSIRES paResponse, unsigned int cnResponse) 832 871 { 833 872 int rc = VINF_SUCCESS; … … 860 899 } 861 900 Assert(cMilliesRemaining < 1000000); 862 if (fSelect) 863 { 864 rc = pImage->pInterfaceNetCallbacks->pfnSelectOne(pImage->Socket, 865 cMilliesRemaining); 866 if (RT_FAILURE(rc)) 867 break; 868 } 901 rc = pImage->pInterfaceNetCallbacks->pfnSelectOne(pImage->Socket, 902 cMilliesRemaining); 903 if (RT_FAILURE(rc)) 904 break; 869 905 rc = pImage->pInterfaceNetCallbacks->pfnRead(pImage->Socket, 870 906 pDst, residual, … … 1351 1387 cnISCSIRes++; 1352 1388 1353 rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes , true);1389 rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes); 1354 1390 if (RT_FAILURE(rc)) 1355 1391 break; … … 1642 1678 aISCSIRes.pvSeg = aResBHS; 1643 1679 aISCSIRes.cbSeg = sizeof(aResBHS); 1644 rc = iscsiRecvPDU(pImage, itt, &aISCSIRes, 1 , true);1680 rc = iscsiRecvPDU(pImage, itt, &aISCSIRes, 1); 1645 1681 if (RT_SUCCESS(rc)) 1646 1682 { … … 1802 1838 cnISCSIRes++; 1803 1839 1804 rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes , true);1840 rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes); 1805 1841 if (RT_FAILURE(rc)) 1806 1842 break; … … 1981 2017 * @param cnRes Number of valid iSCSI response sections in the array. 1982 2018 */ 1983 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes , bool fSelect)2019 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes) 1984 2020 { 1985 2021 int rc = VINF_SUCCESS; … … 1990 2026 aResBuf.pvSeg = pImage->pvRecvPDUBuf; 1991 2027 aResBuf.cbSeg = pImage->cbRecvPDUBuf; 1992 rc = iscsiTransportRead(pImage, &aResBuf, 1 , fSelect);2028 rc = iscsiTransportRead(pImage, &aResBuf, 1); 1993 2029 if (RT_FAILURE(rc)) 1994 2030 { … … 2145 2181 2146 2182 /** 2183 * Reset the PDU buffer 2184 * 2185 * @param pImage The iSCSI connection state to be used. 2186 */ 2187 static void iscsiRecvPDUReset(PISCSIIMAGE pImage) 2188 { 2189 pImage->cbRecvPDUResidual = ISCSI_BHS_SIZE; 2190 pImage->fRecvPDUBHS = true; 2191 pImage->pbRecvPDUBufCur = (uint8_t *)pImage->pvRecvPDUBuf; 2192 } 2193 2194 static void iscsiPDUTxAdd(PISCSIIMAGE pImage, PISCSIPDUTX pIScsiPDUTx, bool fFront) 2195 { 2196 if (!fFront) 2197 { 2198 /* Link the PDU at the tail of the list. */ 2199 if (!pImage->pIScsiPDUTxHead) 2200 pImage->pIScsiPDUTxHead = pIScsiPDUTx; 2201 else 2202 pImage->pIScsiPDUTxTail->pNext = pIScsiPDUTx; 2203 pImage->pIScsiPDUTxTail = pIScsiPDUTx; 2204 } 2205 else 2206 { 2207 /* Link PDU to at the front of the list. */ 2208 pIScsiPDUTx->pNext = pImage->pIScsiPDUTxHead; 2209 pImage->pIScsiPDUTxHead = pIScsiPDUTx; 2210 if (!pImage->pIScsiPDUTxTail) 2211 pImage->pIScsiPDUTxTail = pIScsiPDUTx; 2212 } 2213 } 2214 2215 /** 2147 2216 * Receives a PDU in a non blocking way. 2148 2217 * … … 2162 2231 /* 2163 2232 * We are receiving a new PDU, don't read more than the BHS initially 2164 * until we now the real size of the PDU.2233 * until we know the real size of the PDU. 2165 2234 */ 2166 pImage->cbRecvPDUResidual = ISCSI_BHS_SIZE; 2167 pImage->fRecvPDUBHS = true; 2168 pImage->pbRecvPDUBufCur = (uint8_t *)pImage->pvRecvPDUBuf; 2235 iscsiRecvPDUReset(pImage); 2169 2236 LogFlow(("Receiving new PDU\n")); 2170 2237 } … … 2378 2445 2379 2446 /* Link the PDU to the list. */ 2380 if (!pImage->pIScsiPDUTxHead) 2381 pImage->pIScsiPDUTxHead = pIScsiPDUTx; 2382 else 2383 pImage->pIScsiPDUTxTail->pNext = pIScsiPDUTx; 2384 pImage->pIScsiPDUTxTail = pIScsiPDUTx; 2447 iscsiPDUTxAdd(pImage, pIScsiPDUTx, false /* fFront */); 2385 2448 2386 2449 /* Start transfer of a PDU if there is no one active at the moment. */ … … 2468 2531 break; 2469 2532 case ISCSIOP_ASYN_MSG: 2470 /* Asynchronous Messages must not have the final bit unse rand may not contain2533 /* Asynchronous Messages must not have the final bit unset and may not contain 2471 2534 * an initiator task tag. */ 2472 2535 if ( ((hw0 & ISCSI_FINAL_BIT) == 0) … … 2490 2553 } 2491 2554 2555 2492 2556 /** 2493 2557 * Prepares a PDU to transfer for the given command and adds it to the list. … … 2498 2562 uint32_t *paReqBHS; 2499 2563 size_t cbData = 0; 2564 size_t cbSegs = 0; 2500 2565 PSCSIREQ pScsiReq; 2501 2566 PISCSIPDUTX pIScsiPDU = NULL; … … 2547 2612 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = pIScsiPDU->aBHS; 2548 2613 cnISCSIReq++; 2614 cbSegs = sizeof(pIScsiPDU->aBHS); 2549 2615 /* Padding is not necessary for the BHS. */ 2550 2616 … … 2556 2622 pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg = pScsiReq->paI2TSegs[cSeg].cbSeg; 2557 2623 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = pScsiReq->paI2TSegs[cSeg].pvSeg; 2624 cbSegs += pScsiReq->paI2TSegs[cSeg].cbSeg; 2558 2625 cnISCSIReq++; 2559 2626 … … 2564 2631 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = &pImage->aPadding[0]; 2565 2632 pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg = 4 - (pScsiReq->paI2TSegs[cSeg].cbSeg & 3); 2633 cbSegs += pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg; 2566 2634 cnISCSIReq++; 2567 2635 } … … 2570 2638 2571 2639 pIScsiPDU->cISCSIReq = cnISCSIReq; 2572 pIScsiPDU->cbSgLeft = pScsiReq->cbI2TData + sizeof(pIScsiPDU->aBHS);2640 pIScsiPDU->cbSgLeft = cbSegs; 2573 2641 RTSgBufInit(&pIScsiPDU->SgBuf, pIScsiPDU->aISCSIReq, cnISCSIReq); 2574 2642 2575 2643 /* Link the PDU to the list. */ 2576 if (!pImage->pIScsiPDUTxHead) 2577 pImage->pIScsiPDUTxHead = pIScsiPDU; 2578 else 2579 pImage->pIScsiPDUTxTail->pNext = pIScsiPDU; 2580 pImage->pIScsiPDUTxTail = pIScsiPDU; 2644 iscsiPDUTxAdd(pImage, pIScsiPDU, false /* fFront */); 2581 2645 2582 2646 /* Start transfer of a PDU if there is no one active at the moment. */ … … 2673 2737 if (final && cbData > pScsiReq->cbT2IData) 2674 2738 { 2675 /* The received PDU is partially stored in the buffer for status.2739 /* The received PDU is bigger than what we requested. 2676 2740 * Must not happen under normal circumstances and is a target error. */ 2677 2741 rc = VERR_BUFFER_OVERFLOW; … … 2695 2759 } 2696 2760 2761 /* Log any errors here but ignore the PDU. */ 2762 if (RT_FAILURE(rc)) 2763 { 2764 LogRel(("iSCSI: Received malformed PDU from target %s (rc=%Rrc), ignoring\n", pImage->pszTargetName, rc)); 2765 rc = VINF_SUCCESS; 2766 } 2767 2697 2768 return rc; 2698 2769 } 2699 2700 2770 2701 2771 /** … … 3069 3139 PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser; 3070 3140 3071 /* Initiali se the initial event mask. */3141 /* Initialize the initial event mask. */ 3072 3142 pImage->fPollEvents = VD_INTERFACETCPNET_EVT_READ | VD_INTERFACETCPNET_EVT_ERROR; 3073 3143 … … 3093 3163 { 3094 3164 rc = iscsiPDUTxPrepare(pImage, pIScsiCmd); 3165 AssertRC(rc); 3095 3166 break; 3096 3167 } … … 3110 3181 else if (RT_SUCCESS(rc)) 3111 3182 { 3183 Assert(pImage->state == ISCSISTATE_NORMAL); 3112 3184 LogFlow(("Got socket events %#x\n", fEvents)); 3113 3185 … … 3129 3201 else if (fEvents & VD_INTERFACETCPNET_EVT_ERROR) 3130 3202 { 3131 /** @todo: Determine type of error, reset states, reconnect 3132 * and resend all active PDUs. 3203 PISCSICMD pIScsiCmdHead = NULL; 3204 PISCSICMD pIScsiCmd = NULL; 3205 PISCSICMD pIScsiCmdCur = NULL; 3206 PISCSIPDUTX pIScsiPDUTx = NULL; 3207 LogFlow(("An error ocurred\n")); 3208 3209 /* Close connection. */ 3210 iscsiTransportClose(pImage); 3211 pImage->state = ISCSISTATE_FREE; 3212 3213 /* Reset PDU we are receiving. */ 3214 iscsiRecvPDUReset(pImage); 3215 3216 /* 3217 * Abort all PDUs we are about to transmit, 3218 * the command need a new Itt if the relogin is successful. 3133 3219 */ 3134 LogFlow(("An error ocurred\n")); 3220 while (pImage->pIScsiPDUTxHead) 3221 { 3222 pIScsiPDUTx = pImage->pIScsiPDUTxHead; 3223 pImage->pIScsiPDUTxHead = pIScsiPDUTx->pNext; 3224 3225 pIScsiCmd = pIScsiPDUTx->pIScsiCmd; 3226 3227 if (pIScsiCmd) 3228 { 3229 /* Place on command list. */ 3230 pIScsiCmd->pNext = pIScsiCmdHead; 3231 pIScsiCmdHead = pIScsiCmd; 3232 } 3233 RTMemFree(pIScsiPDUTx); 3234 } 3235 3236 /* Clear the current PDU too. */ 3237 if (pImage->pIScsiPDUTxCur) 3238 { 3239 pIScsiPDUTx = pImage->pIScsiPDUTxCur; 3240 3241 pImage->pIScsiPDUTxCur = NULL; 3242 pIScsiCmd = pIScsiPDUTx->pIScsiCmd; 3243 3244 if (pIScsiCmd) 3245 { 3246 pIScsiCmd->pNext = pIScsiCmdHead; 3247 pIScsiCmdHead = pIScsiCmd; 3248 } 3249 RTMemFree(pIScsiPDUTx); 3250 } 3251 3252 /* 3253 * Get all commands which are waiting for a response 3254 * They need to be resend too after a successful reconnect. 3255 */ 3256 pIScsiCmd = iscsiCmdRemoveAll(pImage); 3257 3258 pIScsiCmdCur = pIScsiCmd; 3259 while (pIScsiCmdCur->pNext) 3260 pIScsiCmdCur = pIScsiCmdCur->pNext; 3261 3262 /* 3263 * Place them in front of the list because they are the oldest requests 3264 * and need to be processed first to minimize the risk to time out. 3265 */ 3266 pIScsiCmdCur->pNext = pIScsiCmdHead; 3267 pIScsiCmdHead = pIScsiCmd; 3268 3269 /* Try to attach. */ 3270 rc = iscsiAttach(pImage); 3271 if (RT_SUCCESS(rc)) 3272 { 3273 /* Phew, we have a connection again. 3274 * Prepare new PDUs for the aborted commands. 3275 */ 3276 while (pIScsiCmdHead) 3277 { 3278 pIScsiCmd = pIScsiCmdHead; 3279 pIScsiCmdHead = pIScsiCmdHead->pNext; 3280 3281 rc = iscsiPDUTxPrepare(pImage, pIScsiCmd); 3282 AssertRC(rc); 3283 } 3284 } 3285 else 3286 { 3287 /* 3288 * Still no luck, complete commands with error so the caller 3289 * has a chance to inform the user and maybe resend the command. 3290 */ 3291 while (pIScsiCmdHead) 3292 { 3293 pIScsiCmd = pIScsiCmdHead; 3294 pIScsiCmdHead = pIScsiCmdHead->pNext; 3295 3296 iscsiCmdComplete(pImage, pIScsiCmd, VERR_BROKEN_PIPE); 3297 } 3298 } 3135 3299 } 3136 3300 else … … 3144 3308 3145 3309 return VINF_SUCCESS; 3146 }3147 3148 static void iscsiCommandAsyncComplete(PISCSIIMAGE pImage, int rcReq, void *pvUser)3149 {3150 size_t cbTransfered = 0;3151 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)pvUser;3152 PSCSIREQ pScsiReq = pReqAsync->pScsiReq;3153 3154 /** @todo Retry and sense buffer handling. */3155 3156 if (pScsiReq->enmXfer == SCSIXFER_FROM_TARGET)3157 cbTransfered = pScsiReq->cbT2IData;3158 else if (pScsiReq->enmXfer == SCSIXFER_TO_TARGET)3159 cbTransfered = pScsiReq->cbI2TData;3160 else3161 AssertMsg(pScsiReq->enmXfer == SCSIXFER_NONE, ("To/From transfers are not supported yet\n"));3162 3163 /* Continue I/O context. */3164 pImage->pInterfaceIoCallbacks->pfnIoCtxCompleted(pImage->pInterfaceIo->pvUser,3165 pReqAsync->pIoCtx, rcReq,3166 cbTransfered);3167 3168 RTMemFree(pScsiReq);3169 RTMemFree(pReqAsync);3170 }3171 3172 static void iscsiCommandCompleteSync(PISCSIIMAGE pImage, int rcReq, void *pvUser)3173 {3174 PISCSICMDSYNC pIScsiCmdSync = (PISCSICMDSYNC)pvUser;3175 3176 pIScsiCmdSync->rcCmd = rcReq;3177 int rc = RTSemEventSignal(pIScsiCmdSync->EventSem);3178 AssertRC(rc);3179 3310 } 3180 3311 … … 3208 3339 3209 3340 return rc; 3341 } 3342 3343 static void iscsiCommandCompleteSync(PISCSIIMAGE pImage, int rcReq, void *pvUser) 3344 { 3345 PISCSICMDSYNC pIScsiCmdSync = (PISCSICMDSYNC)pvUser; 3346 3347 pIScsiCmdSync->rcCmd = rcReq; 3348 int rc = RTSemEventSignal(pIScsiCmdSync->EventSem); 3349 AssertRC(rc); 3210 3350 } 3211 3351 … … 3337 3477 return rc; 3338 3478 } 3479 3480 3481 static void iscsiCommandAsyncComplete(PISCSIIMAGE pImage, int rcReq, void *pvUser) 3482 { 3483 bool fComplete = true; 3484 size_t cbTransfered = 0; 3485 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)pvUser; 3486 PSCSIREQ pScsiReq = pReqAsync->pScsiReq; 3487 3488 if ( RT_SUCCESS(rcReq) 3489 && pScsiReq->cbSense > 0) 3490 { 3491 /* Try again if possible. */ 3492 if (pReqAsync->cSenseRetries > 0) 3493 { 3494 pReqAsync->cSenseRetries--; 3495 pScsiReq->cbSense = sizeof(pReqAsync->abSense); 3496 int rc = iscsiCommandAsync(pImage, pScsiReq, iscsiCommandAsyncComplete, pReqAsync); 3497 if (RT_SUCCESS(rc)) 3498 fComplete = false; 3499 else 3500 rcReq = pReqAsync->rcSense; 3501 } 3502 else 3503 rcReq = pReqAsync->rcSense; 3504 } 3505 3506 if (fComplete) 3507 { 3508 if (pScsiReq->enmXfer == SCSIXFER_FROM_TARGET) 3509 cbTransfered = pScsiReq->cbT2IData; 3510 else if (pScsiReq->enmXfer == SCSIXFER_TO_TARGET) 3511 cbTransfered = pScsiReq->cbI2TData; 3512 else 3513 AssertMsg(pScsiReq->enmXfer == SCSIXFER_NONE, ("To/From transfers are not supported yet\n")); 3514 3515 /* Continue I/O context. */ 3516 pImage->pInterfaceIoCallbacks->pfnIoCtxCompleted(pImage->pInterfaceIo->pvUser, 3517 pReqAsync->pIoCtx, rcReq, 3518 cbTransfered); 3519 3520 RTMemFree(pScsiReq); 3521 RTMemFree(pReqAsync); 3522 } 3523 } 3524 3339 3525 3340 3526 /** … … 5018 5204 pReqAsync->pIoCtx = pIoCtx; 5019 5205 pReqAsync->pScsiReq = pReq; 5206 pReqAsync->cSenseRetries = 10; 5207 pReqAsync->rcSense = VERR_READ_ERROR; 5020 5208 5021 5209 pbCDB[0] = SCSI_READ_10; … … 5116 5304 pReqAsync->pIoCtx = pIoCtx; 5117 5305 pReqAsync->pScsiReq = pReq; 5306 pReqAsync->cSenseRetries = 10; 5307 pReqAsync->rcSense = VERR_WRITE_ERROR; 5118 5308 5119 5309 pbCDB[0] = SCSI_WRITE_10; … … 5178 5368 uint8_t *pbCDB = &pReqAsync->abCDB[0]; 5179 5369 5180 pReqAsync->pIoCtx = pIoCtx; 5181 pReqAsync->pScsiReq = pReq; 5370 pReqAsync->pIoCtx = pIoCtx; 5371 pReqAsync->pScsiReq = pReq; 5372 pReqAsync->cSenseRetries = 0; 5373 pReqAsync->rcSense = VINF_SUCCESS; 5182 5374 5183 5375 pbCDB[0] = SCSI_SYNCHRONIZE_CACHE;
Note:
See TracChangeset
for help on using the changeset viewer.