Changeset 31587 in vbox for trunk/src/VBox
- Timestamp:
- Aug 11, 2010 10:20:50 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp
r31456 r31587 21 21 *******************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_VD_ISCSI 23 #define RTMEM_NO_WRAP_TO_EF_APIS 23 24 #include <VBox/VBoxHDD-Plugin.h> 24 25 #define VBOX_VDICORE_VD /* Signal that the header is included from here. */ … … 222 223 #define ISCSI_SG_SEGMENTS_MAX 4 223 224 225 /** Number of entries in the command table. */ 226 #define ISCSI_CMD_WAITING_ENTRIES 32 224 227 225 228 /** … … 324 327 } SCSIXFER, *PSCSIXFER; 325 328 329 /** Forward declaration. */ 330 typedef struct ISCSIIMAGE *PISCSIIMAGE; 326 331 327 332 /** … … 344 349 /** Pointer to command block. */ 345 350 void *pvCmd; 346 /** Pointer to Initiator2Target data buffer. */347 const void *pcvI2TData;348 /** Pointer to Target2Initiator data buffer. */349 void *pvT2IData;350 351 /** Pointer to sense buffer. */ 351 352 void *pvSense; 353 /** Pointer to the Initiator2Target S/G list. */ 354 PRTSGSEG paI2TSegs; 355 /** Number of entries in the I2T S/G list. */ 356 unsigned cI2TSegs; 357 /** Pointer to the Target2Initiator S/G list. */ 358 PRTSGSEG paT2ISegs; 359 /** Number of entries in the T2I S/G list. */ 360 unsigned cT2ISegs; 361 /** S/G buffer for the target to initiator bits. */ 362 RTSGBUF SgBufT2I; 352 363 } SCSIREQ, *PSCSIREQ; 353 364 365 /** 366 * Async request structure holding all necessary data for 367 * request processing. 368 */ 369 typedef struct SCSIREQASYNC 370 { 371 /** I/O context associated with this request. */ 372 PVDIOCTX pIoCtx; 373 /** Pointer to the SCSI request structure. */ 374 PSCSIREQ pScsiReq; 375 /** The CDB. */ 376 uint8_t abCDB[10]; 377 /** The sense buffer. */ 378 uint8_t abSense[96]; 379 /** The number of entries in the I2T S/G list. */ 380 unsigned cI2TSegs; 381 /** The number of entries in the T2I S/G list. */ 382 unsigned cT2ISegs; 383 /** The S/G list - variable in size. 384 * This array holds both the I2T and T2I segments. 385 * The I2T segments are first and the T2I are second. 386 */ 387 RTSGSEG aSegs[1]; 388 } SCSIREQASYNC, *PSCSIREQASYNC; 354 389 355 390 typedef enum ISCSICMDTYPE … … 365 400 366 401 /** The command completion function. */ 367 typedef DECLCALLBACK(void) FNISCSICMDCOMPLETED( void *pvUser);402 typedef DECLCALLBACK(void) FNISCSICMDCOMPLETED(PISCSIIMAGE pImage, int rcReq, void *pvUser); 368 403 /** Pointer to a command completion function. */ 369 404 typedef FNISCSICMDCOMPLETED *PFNISCSICMDCOMPLETED; … … 373 408 /** Pointer to a command execution function. */ 374 409 typedef FNISCSIEXEC *PFNISCSIEXEC; 410 411 /** 412 * Structure used to complete a synchronous request. 413 */ 414 typedef struct ISCSICMDSYNC 415 { 416 /** Event sempahore to wakeup the waiting thread. */ 417 RTSEMEVENT EventSem; 418 /** Status code of the command. */ 419 int rcCmd; 420 } ISCSICMDSYNC, *PISCSICMDSYNC; 375 421 376 422 /** … … 382 428 { 383 429 /** Next one in the list. */ 384 struct ISCSICMD *pNext; 430 struct ISCSICMD *pNext; 431 /** Assigned ITT. */ 432 uint32_t Itt; 433 /** Completion callback. */ 434 PFNISCSICMDCOMPLETED pfnComplete; 435 /** Opaque user data. */ 436 void *pvUser; 385 437 /** Command to execute. */ 386 ISCSICMDTYPE enmCmdType; 387 /** Flag whether this is a synchronous request. */ 388 bool fSync; 389 /** Type dependent data - based on fSync. */ 390 union 391 { 392 /** Synchronous request. */ 393 struct 394 { 395 /** Event semaphore to signal if this is a synchronous request. */ 396 RTSEMEVENT EventSem; 397 /** Completion status code. */ 398 int rcCmd; 399 } Sync; 400 /** Asynchronous request. */ 401 struct 402 { 403 /** Completion callback. */ 404 PFNISCSICMDCOMPLETED pfnComplete; 405 /** Opaque user data. */ 406 void *pvUser; 407 } Async; 408 } Type; 438 ISCSICMDTYPE enmCmdType; 409 439 /** Command type dependent data. */ 410 440 union … … 426 456 } CmdType; 427 457 } ISCSICMD, *PISCSICMD; 458 459 /** 460 * Send iSCSI PDU. 461 * Contains all necessary data to send a PDU. 462 */ 463 typedef struct ISCSIPDUTX 464 { 465 /** Pointer to the next PDu to send. */ 466 struct ISCSIPDUTX *pNext; 467 /** The BHS. */ 468 uint32_t aBHS[12]; 469 /** The S/G buffer used for sending. */ 470 RTSGBUF SgBuf; 471 /** Number of bytes to send until the PDU completed. */ 472 size_t cbSgLeft; 473 /** The iSCSI command this PDU belongs to. */ 474 PISCSICMD pIScsiCmd; 475 /** Number of segments in the request segments array. */ 476 unsigned cISCSIReq; 477 /** The request segments - variable in size. */ 478 RTSGSEG aISCSIReq[1]; 479 } ISCSIPDUTX, *PISCSIPDUTX; 428 480 429 481 /** … … 548 600 /** Socket events to poll for. */ 549 601 uint32_t fPollEvents; 550 } ISCSIIMAGE, *PISCSIIMAGE; 602 /** Number of bytes to read to complete the current PDU. */ 603 size_t cbRecvPDUResidual; 604 /** Current position in the PDU buffer. */ 605 uint8_t *pbRecvPDUBufCur; 606 /** Flag whether we are currently reading the BHS. */ 607 bool fRecvPDUBHS; 608 /** List of PDUs waiting to get transmitted. */ 609 PISCSIPDUTX pIScsiPDUTxHead; 610 /** Tail of PDUs waiting to get transmitted. */ 611 PISCSIPDUTX pIScsiPDUTxTail; 612 /** PDU we are currently transmitting. */ 613 PISCSIPDUTX pIScsiPDUTxCur; 614 615 /** Table of commands waiting for a response from the target. */ 616 PISCSICMD aCmdsWaiting[ISCSI_CMD_WAITING_ENTRIES]; 617 } ISCSIIMAGE; 551 618 552 619 … … 596 663 static int iscsiSendPDU(PISCSIIMAGE pImage, PISCSIREQ paReq, uint32_t cnReq, uint32_t uFlags); 597 664 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes, bool fSelect); 665 static int iscsiRecvPDUAsync(PISCSIIMAGE pImage); 666 static int iscsiSendPDUAsync(PISCSIIMAGE pImage); 598 667 static int iscsiValidatePDU(PISCSIRES paRes, uint32_t cnRes); 668 static int iscsiRecvPDUProcess(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes); 669 static int iscsiPDUTxPrepare(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd); 670 static int iscsiRecvPDUUpdateRequest(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes); 671 static void iscsiCmdComplete(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd, int rcCmd); 599 672 static int iscsiTextAddKeyValue(uint8_t *pbBuf, size_t cbBuf, size_t *pcbBufCurr, const char *pcszKey, const char *pcszValue, size_t cbValue); 600 673 static int iscsiTextGetKeyValue(const uint8_t *pbBuf, size_t cbBuf, const char *pcszKey, const char **ppcszValue); … … 638 711 return pImage->Socket != NIL_VDSOCKET 639 712 && pImage->pInterfaceNetCallbacks->pfnIsClientConnected(pImage->Socket); 713 } 714 715 /** 716 * Calculates the hash for the given ITT used 717 * to look up the command in the table. 718 */ 719 DECLINLINE(uint32_t) iscsiIttHash(uint32_t Itt) 720 { 721 return Itt % ISCSI_CMD_WAITING_ENTRIES; 722 } 723 724 static PISCSICMD iscsiCmdGetFromItt(PISCSIIMAGE pImage, uint32_t Itt) 725 { 726 PISCSICMD pIScsiCmd = NULL; 727 728 pIScsiCmd = pImage->aCmdsWaiting[iscsiIttHash(Itt)]; 729 730 while ( pIScsiCmd 731 && pIScsiCmd->Itt != Itt) 732 pIScsiCmd = pIScsiCmd->pNext; 733 734 return pIScsiCmd; 735 } 736 737 static void iscsiCmdInsert(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd) 738 { 739 PISCSICMD pIScsiCmdOld; 740 uint32_t idx = iscsiIttHash(pIScsiCmd->Itt); 741 742 Assert(!pIScsiCmd->pNext); 743 744 pIScsiCmdOld = pImage->aCmdsWaiting[idx]; 745 pIScsiCmd->pNext = pIScsiCmdOld; 746 pImage->aCmdsWaiting[idx] = pIScsiCmd; 747 } 748 749 static PISCSICMD iscsiCmdRemove(PISCSIIMAGE pImage, uint32_t Itt) 750 { 751 PISCSICMD pIScsiCmd = NULL; 752 PISCSICMD pIScsiCmdPrev = NULL; 753 uint32_t idx = iscsiIttHash(Itt); 754 755 pIScsiCmd = pImage->aCmdsWaiting[idx]; 756 757 while ( pIScsiCmd 758 && pIScsiCmd->Itt != Itt) 759 { 760 pIScsiCmdPrev = pIScsiCmd; 761 pIScsiCmd = pIScsiCmd->pNext; 762 } 763 764 if (pIScsiCmd) 765 { 766 if (pIScsiCmdPrev) 767 { 768 Assert(!pIScsiCmd->pNext || VALID_PTR(pIScsiCmd->pNext)); 769 pIScsiCmdPrev->pNext = pIScsiCmd->pNext; 770 } 771 else 772 { 773 pImage->aCmdsWaiting[idx] = pIScsiCmd->pNext; 774 Assert(!pImage->aCmdsWaiting[idx] || VALID_PTR(pImage->aCmdsWaiting[idx])); 775 } 776 777 } 778 779 return pIScsiCmd; 640 780 } 641 781 … … 705 845 } 706 846 707 if (RT_SUCCESS(rc) && paResponse[0].cbSeg >= 48)847 if (RT_SUCCESS(rc) && paResponse[0].cbSeg >= ISCSI_BHS_SIZE) 708 848 { 709 849 cbToRead = 0; 710 residual = 48; /* Do not read more than the BHS length before the true PDU length is known. */850 residual = ISCSI_BHS_SIZE; /* Do not read more than the BHS length before the true PDU length is known. */ 711 851 cbSegActual = residual; 712 852 pDst = (char *)paResponse[i].pvSeg; … … 755 895 cbDataLength = ((cbDataLength - 1) | 3) + 1; /* Add padding. */ 756 896 cbToRead = residual + cbAHSLength + cbDataLength; 757 residual += paResponse[0].cbSeg - 48;897 residual += paResponse[0].cbSeg - ISCSI_BHS_SIZE; 758 898 if (residual > cbToRead) 759 899 residual = cbToRead; 760 cbSegActual = 48+ cbAHSLength + cbDataLength;900 cbSegActual = ISCSI_BHS_SIZE + cbAHSLength + cbDataLength; 761 901 /* Check whether we are already done with this PDU (no payload). */ 762 902 if (cbToRead == 0) … … 1614 1754 || pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET) 1615 1755 { 1616 aISCSIReq[cnISCSIReq].pcvSeg = pRequest->pcvI2TData; 1617 aISCSIReq[cnISCSIReq].cbSeg = pRequest->cbI2TData; /* Padding done by transport. */ 1756 Assert(pRequest->cI2TSegs == 1); 1757 aISCSIReq[cnISCSIReq].pcvSeg = pRequest->paI2TSegs[0].pvSeg; 1758 aISCSIReq[cnISCSIReq].cbSeg = pRequest->paI2TSegs[0].cbSeg; /* Padding done by transport. */ 1618 1759 cnISCSIReq++; 1619 1760 } … … 1633 1774 || pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET) 1634 1775 { 1635 pDst = (uint32_t *)pRequest->pvT2IData; 1636 cbBufLength = pRequest->cbT2IData; 1776 Assert(pRequest->cT2ISegs == 1); 1777 pDst = (uint32_t *)pRequest->paT2ISegs[0].pvSeg; 1778 cbBufLength = pRequest->paT2ISegs[0].cbSeg; 1637 1779 } 1638 1780 else … … 2004 2146 2005 2147 /** 2148 * Receives a PDU in a non blocking way. 2149 * 2150 * @returns VBOX status code. 2151 * @param pImage The iSCSI connection state to be used. 2152 */ 2153 static int iscsiRecvPDUAsync(PISCSIIMAGE pImage) 2154 { 2155 size_t cbActuallyRead = 0; 2156 int rc = VINF_SUCCESS; 2157 2158 LogFlowFunc(("pImage=%#p\n", pImage)); 2159 2160 /* Check if we are in the middle of a PDU receive. */ 2161 if (pImage->cbRecvPDUResidual == 0) 2162 { 2163 /* 2164 * We are receiving a new PDU, don't read more than the BHS initially 2165 * until we now the real size of the PDU. 2166 */ 2167 pImage->cbRecvPDUResidual = ISCSI_BHS_SIZE; 2168 pImage->fRecvPDUBHS = true; 2169 pImage->pbRecvPDUBufCur = (uint8_t *)pImage->pvRecvPDUBuf; 2170 LogFlow(("Receiving new PDU\n")); 2171 } 2172 2173 rc = pImage->pInterfaceNetCallbacks->pfnReadNB(pImage->Socket, pImage->pbRecvPDUBufCur, 2174 pImage->cbRecvPDUResidual, &cbActuallyRead); 2175 if (RT_SUCCESS(rc)) 2176 { 2177 LogFlow(("Received %zu bytes\n", cbActuallyRead)); 2178 pImage->cbRecvPDUResidual -= cbActuallyRead; 2179 pImage->pbRecvPDUBufCur += cbActuallyRead; 2180 2181 /* Check if we received everything we wanted. */ 2182 if ( !pImage->cbRecvPDUResidual 2183 && pImage->fRecvPDUBHS) 2184 { 2185 size_t cbAHSLength, cbDataLength; 2186 2187 /* If we were reading the BHS first get the actual PDU size now. */ 2188 uint32_t word1 = RT_N2H_U32(((uint32_t *)(pImage->pvRecvPDUBuf))[1]); 2189 cbAHSLength = (word1 & 0xff000000) >> 24; 2190 cbAHSLength = ((cbAHSLength - 1) | 3) + 1; /* Add padding. */ 2191 cbDataLength = word1 & 0x00ffffff; 2192 cbDataLength = ((cbDataLength - 1) | 3) + 1; /* Add padding. */ 2193 pImage->cbRecvPDUResidual = cbAHSLength + cbDataLength; 2194 pImage->fRecvPDUBHS = false; /* Start receiving the rest of the PDU. */ 2195 } 2196 2197 if (!pImage->cbRecvPDUResidual) 2198 { 2199 /* We received the complete PDU with or without any payload now. */ 2200 LogFlow(("Received complete PDU\n")); 2201 ISCSIRES aResBuf; 2202 aResBuf.pvSeg = pImage->pvRecvPDUBuf; 2203 aResBuf.cbSeg = pImage->cbRecvPDUBuf; 2204 rc = iscsiRecvPDUProcess(pImage, &aResBuf, 1); 2205 } 2206 } 2207 else 2208 LogFlowFunc(("Reading from the socket returned with rc=%Rrc\n", rc)); 2209 2210 return rc; 2211 } 2212 2213 static int iscsiSendPDUAsync(PISCSIIMAGE pImage) 2214 { 2215 size_t cbSent = 0; 2216 int rc = VINF_SUCCESS; 2217 2218 LogFlowFunc(("pImage=%#p\n", pImage)); 2219 2220 do 2221 { 2222 /* If there is no PDU active, get the first one from the list. */ 2223 if (!pImage->pIScsiPDUTxCur) 2224 { 2225 if (!pImage->pIScsiPDUTxHead) 2226 break; 2227 2228 pImage->pIScsiPDUTxCur = pImage->pIScsiPDUTxHead; 2229 pImage->pIScsiPDUTxHead = pImage->pIScsiPDUTxCur->pNext; 2230 if (!pImage->pIScsiPDUTxHead) 2231 pImage->pIScsiPDUTxTail = NULL; 2232 } 2233 2234 /* Send as much as we can. */ 2235 rc = pImage->pInterfaceNetCallbacks->pfnSgWriteNB(pImage->Socket, &pImage->pIScsiPDUTxCur->SgBuf, &cbSent); 2236 if (RT_SUCCESS(rc)) 2237 { 2238 LogFlow(("Sent %zu bytes for PDU %#p\n", cbSent, pImage->pIScsiPDUTxCur)); 2239 pImage->pIScsiPDUTxCur->cbSgLeft -= cbSent; 2240 RTSgBufAdvance(&pImage->pIScsiPDUTxCur->SgBuf, cbSent); 2241 if (!pImage->pIScsiPDUTxCur->cbSgLeft) 2242 { 2243 /* PDU completed, free it and place the command on the waiting for response list. */ 2244 if (pImage->pIScsiPDUTxCur->pIScsiCmd) 2245 { 2246 LogFlow(("Sent complete PDU, placing on waiting list\n")); 2247 iscsiCmdInsert(pImage, pImage->pIScsiPDUTxCur->pIScsiCmd); 2248 } 2249 RTMemFree(pImage->pIScsiPDUTxCur); 2250 pImage->pIScsiPDUTxCur = NULL; 2251 } 2252 } 2253 } while ( RT_SUCCESS(rc) 2254 && !pImage->pIScsiPDUTxCur); 2255 2256 /* Add the write poll flag if we still have something to send, clear it otherwise. */ 2257 if (pImage->pIScsiPDUTxCur) 2258 pImage->fPollEvents |= VD_INTERFACETCPNET_EVT_WRITE; 2259 else 2260 pImage->fPollEvents &= ~VD_INTERFACETCPNET_EVT_WRITE; 2261 2262 return rc; 2263 } 2264 2265 /** 2266 * Process a received PDU. 2267 * 2268 * @return VBOX status code. 2269 * @param pImage The iSCSI connection state to be used. 2270 * @param paRes Pointer to the array of iSCSI repsonse sections. 2271 * @param cnRes Number of valid iSCSI response sections in the array. 2272 */ 2273 static int iscsiRecvPDUProcess(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes) 2274 { 2275 int rc = VINF_SUCCESS; 2276 2277 LogFlowFunc(("pImage=%#p paRes=%#p cnRes=%u\n", pImage, paRes, cnRes)); 2278 2279 /* Validate the PDU first. */ 2280 rc = iscsiValidatePDU(paRes, cnRes); 2281 if (RT_SUCCESS(rc)) 2282 { 2283 ISCSIOPCODE cmd; 2284 const uint32_t *pcvResSeg = (const uint32_t *)paRes[0].pvSeg; 2285 2286 Assert(paRes[0].cbSeg > 9 * sizeof(uint32_t)); 2287 2288 do 2289 { 2290 cmd = (ISCSIOPCODE)(RT_N2H_U32(pcvResSeg[0]) & ISCSIOP_MASK); 2291 switch (cmd) 2292 { 2293 case ISCSIOP_SCSI_RES: 2294 case ISCSIOP_SCSI_TASKMGMT_RES: 2295 case ISCSIOP_SCSI_DATA_IN: 2296 case ISCSIOP_R2T: 2297 case ISCSIOP_ASYN_MSG: 2298 case ISCSIOP_TEXT_RES: 2299 case ISCSIOP_LOGIN_RES: 2300 case ISCSIOP_LOGOUT_RES: 2301 case ISCSIOP_REJECT: 2302 case ISCSIOP_NOP_IN: 2303 if (serial_number_less(pImage->MaxCmdSN, RT_N2H_U32(pcvResSeg[8]))) 2304 pImage->MaxCmdSN = RT_N2H_U32(pcvResSeg[8]); 2305 if (serial_number_less(pImage->ExpCmdSN, RT_N2H_U32(pcvResSeg[7]))) 2306 pImage->ExpCmdSN = RT_N2H_U32(pcvResSeg[7]); 2307 break; 2308 default: 2309 rc = VERR_PARSE_ERROR; 2310 } 2311 2312 if (RT_FAILURE(rc)) 2313 break; 2314 2315 if ( !pImage->FirstRecvPDU 2316 && (cmd != ISCSIOP_SCSI_DATA_IN || (RT_N2H_U32(pcvResSeg[0]) & ISCSI_STATUS_BIT))) 2317 { 2318 if (pImage->ExpStatSN == RT_N2H_U32(pcvResSeg[6])) 2319 { 2320 /* StatSN counter is not advanced on R2T and on a target SN update NOP-In. */ 2321 if ( (cmd != ISCSIOP_R2T) 2322 && ((cmd != ISCSIOP_NOP_IN) || (RT_N2H_U32(pcvResSeg[4]) != ISCSI_TASK_TAG_RSVD))) 2323 pImage->ExpStatSN++; 2324 } 2325 else 2326 { 2327 rc = VERR_PARSE_ERROR; 2328 break; 2329 } 2330 } 2331 2332 if (pcvResSeg[4] != ISCSI_TASK_TAG_RSVD) 2333 { 2334 /* 2335 * This is a response from the target for a request from the initiator. 2336 * Get the request and update its state. 2337 */ 2338 rc = iscsiRecvPDUUpdateRequest(pImage, paRes, cnRes); 2339 } 2340 else 2341 { 2342 /* This is a target initiated request (we handle only NOP-In request at the moment). */ 2343 if ( cmd == ISCSIOP_NOP_IN 2344 && RT_N2H_U32(pcvResSeg[5]) != ISCSI_TASK_TAG_RSVD) 2345 { 2346 PISCSIPDUTX pIScsiPDUTx; 2347 uint32_t cnISCSIReq; 2348 uint32_t *paReqBHS; 2349 2350 LogFlowFunc(("Sending NOP-Out\n")); 2351 2352 /* Allocate a new PDU initialize it and put onto the waiting list. */ 2353 pIScsiPDUTx = (PISCSIPDUTX)RTMemAllocZ(sizeof(ISCSIPDUTX)); 2354 if (!pIScsiPDUTx) 2355 { 2356 rc = VERR_NO_MEMORY; 2357 break; 2358 } 2359 paReqBHS = &pIScsiPDUTx->aBHS[0]; 2360 paReqBHS[0] = RT_H2N_U32(ISCSI_IMMEDIATE_DELIVERY_BIT | ISCSI_FINAL_BIT | ISCSIOP_NOP_OUT); 2361 paReqBHS[1] = RT_H2N_U32(0); /* TotalAHSLength=0,DataSementLength=0 */ 2362 paReqBHS[2] = pcvResSeg[2]; /* copy LUN from NOP-In */ 2363 paReqBHS[3] = pcvResSeg[3]; /* copy LUN from NOP-In */ 2364 paReqBHS[4] = RT_H2N_U32(ISCSI_TASK_TAG_RSVD); /* ITT, reply */ 2365 paReqBHS[5] = pcvResSeg[5]; /* copy TTT from NOP-In */ 2366 paReqBHS[6] = RT_H2N_U32(pImage->CmdSN); 2367 paReqBHS[7] = RT_H2N_U32(pImage->ExpStatSN); 2368 paReqBHS[8] = 0; /* reserved */ 2369 paReqBHS[9] = 0; /* reserved */ 2370 paReqBHS[10] = 0; /* reserved */ 2371 paReqBHS[11] = 0; /* reserved */ 2372 2373 cnISCSIReq = 0; 2374 pIScsiPDUTx->aISCSIReq[cnISCSIReq].pvSeg = paReqBHS; 2375 pIScsiPDUTx->aISCSIReq[cnISCSIReq].cbSeg = sizeof(pIScsiPDUTx->aBHS); 2376 cnISCSIReq++; 2377 pIScsiPDUTx->cbSgLeft = sizeof(pIScsiPDUTx->aBHS); 2378 RTSgBufInit(&pIScsiPDUTx->SgBuf, pIScsiPDUTx->aISCSIReq, cnISCSIReq); 2379 2380 /* Link the PDU to the list. */ 2381 if (!pImage->pIScsiPDUTxHead) 2382 pImage->pIScsiPDUTxHead = pIScsiPDUTx; 2383 else 2384 pImage->pIScsiPDUTxTail->pNext = pIScsiPDUTx; 2385 pImage->pIScsiPDUTxTail = pIScsiPDUTx; 2386 2387 /* Start transfer of a PDU if there is no one active at the moment. */ 2388 if (!pImage->pIScsiPDUTxCur) 2389 rc = iscsiSendPDUAsync(pImage); 2390 } 2391 } 2392 } while (0); 2393 } 2394 2395 return rc; 2396 } 2397 2398 /** 2006 2399 * Check the static (not dependent on the connection/session state) validity of an iSCSI response PDU. 2007 2400 * … … 2016 2409 Assert(cnRes >= 1); 2017 2410 Assert(paRes[0].cbSeg >= ISCSI_BHS_SIZE); 2411 2412 LogFlowFunc(("paRes=%#p cnRes=%u\n", paRes, cnRes)); 2018 2413 2019 2414 pcrgResBHS = (const uint32_t *)(paRes[0].pvSeg); … … 2094 2489 2095 2490 return VINF_SUCCESS; 2491 } 2492 2493 /** 2494 * Prepares a PDU to transfer for the given command and adds it to the list. 2495 */ 2496 static int iscsiPDUTxPrepare(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd) 2497 { 2498 int rc = VINF_SUCCESS; 2499 uint32_t *paReqBHS; 2500 size_t cbData = 0; 2501 PSCSIREQ pScsiReq; 2502 PISCSIPDUTX pIScsiPDU = NULL; 2503 2504 LogFlowFunc(("pImage=%#p pIScsiCmd=%#p\n", pImage, pIScsiCmd)); 2505 2506 Assert(pIScsiCmd->enmCmdType == ISCSICMDTYPE_REQ); 2507 2508 pIScsiCmd->Itt = iscsiNewITT(pImage); 2509 pScsiReq = pIScsiCmd->CmdType.ScsiReq.pScsiReq; 2510 2511 if (pScsiReq->cT2ISegs) 2512 RTSgBufInit(&pScsiReq->SgBufT2I, pScsiReq->paT2ISegs, pScsiReq->cT2ISegs); 2513 2514 /* 2515 * Allocate twice as much entries as required for padding (worst case). 2516 * The additional segment is for the BHS. 2517 */ 2518 size_t cI2TSegs = 2*(pScsiReq->cI2TSegs + 1); 2519 pIScsiPDU = (PISCSIPDUTX)RTMemAllocZ(RT_OFFSETOF(ISCSIPDUTX, aISCSIReq[cI2TSegs])); 2520 if (!pIScsiPDU) 2521 return VERR_NO_MEMORY; 2522 2523 pIScsiPDU->pIScsiCmd = pIScsiCmd; 2524 2525 if (pScsiReq->enmXfer == SCSIXFER_FROM_TARGET) 2526 cbData = (uint32_t)pScsiReq->cbT2IData; 2527 else 2528 cbData = (uint32_t)pScsiReq->cbI2TData; 2529 2530 paReqBHS = pIScsiPDU->aBHS; 2531 2532 /* Setup the BHS. */ 2533 paReqBHS[0] = RT_H2N_U32( ISCSI_FINAL_BIT | ISCSI_TASK_ATTR_ORDERED | ISCSIOP_SCSI_CMD 2534 | (pScsiReq->enmXfer << 21)); /* I=0,F=1,Attr=Ordered */ 2535 paReqBHS[1] = RT_H2N_U32(0x00000000 | ((uint32_t)pScsiReq->cbI2TData & 0xffffff)); /* TotalAHSLength=0 */ 2536 paReqBHS[2] = RT_H2N_U32(pImage->LUN >> 32); 2537 paReqBHS[3] = RT_H2N_U32(pImage->LUN & 0xffffffff); 2538 paReqBHS[4] = pIScsiCmd->Itt; 2539 paReqBHS[5] = RT_H2N_U32(cbData); 2540 paReqBHS[6] = RT_H2N_U32(pImage->CmdSN); 2541 paReqBHS[7] = RT_H2N_U32(pImage->ExpStatSN); 2542 memcpy(paReqBHS + 8, pScsiReq->pvCmd, pScsiReq->cbCmd); 2543 pImage->CmdSN++; 2544 2545 /* Setup the S/G buffers. */ 2546 uint32_t cnISCSIReq = 0; 2547 pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg = sizeof(pIScsiPDU->aBHS); 2548 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = pIScsiPDU->aBHS; 2549 cnISCSIReq++; 2550 /* Padding is not necessary for the BHS. */ 2551 2552 if (pScsiReq->cbI2TData) 2553 { 2554 for (unsigned cSeg = 0; cSeg < pScsiReq->cI2TSegs; cSeg++) 2555 { 2556 Assert(cnISCSIReq < cI2TSegs); 2557 pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg = pScsiReq->paI2TSegs[cSeg].cbSeg; 2558 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = pScsiReq->paI2TSegs[cSeg].pvSeg; 2559 cnISCSIReq++; 2560 2561 /* Add padding if necessary. */ 2562 if (pScsiReq->paI2TSegs[cSeg].cbSeg & 3) 2563 { 2564 Assert(cnISCSIReq < cI2TSegs); 2565 pIScsiPDU->aISCSIReq[cnISCSIReq].pvSeg = &pImage->aPadding[0]; 2566 pIScsiPDU->aISCSIReq[cnISCSIReq].cbSeg = 4 - (pScsiReq->paI2TSegs[cSeg].cbSeg & 3); 2567 cnISCSIReq++; 2568 } 2569 } 2570 } 2571 2572 pIScsiPDU->cISCSIReq = cnISCSIReq; 2573 pIScsiPDU->cbSgLeft = pScsiReq->cbI2TData + sizeof(pIScsiPDU->aBHS); 2574 RTSgBufInit(&pIScsiPDU->SgBuf, pIScsiPDU->aISCSIReq, cnISCSIReq); 2575 2576 /* Link the PDU to the list. */ 2577 if (!pImage->pIScsiPDUTxHead) 2578 pImage->pIScsiPDUTxHead = pIScsiPDU; 2579 else 2580 pImage->pIScsiPDUTxTail->pNext = pIScsiPDU; 2581 pImage->pIScsiPDUTxTail = pIScsiPDU; 2582 2583 /* Start transfer of a PDU if there is no one active at the moment. */ 2584 if (!pImage->pIScsiPDUTxCur) 2585 rc = iscsiSendPDUAsync(pImage); 2586 2587 return rc; 2588 } 2589 2590 2591 /** 2592 * Updates the state of a request from the PDU we received. 2593 * 2594 * @return VBox status code. 2595 * @param pImage iSCSI connection state to use. 2596 * @param paRes Pointer to array of iSCSI response sections. 2597 * @param cnRes Number of valid iSCSI response sections in the array. 2598 */ 2599 static int iscsiRecvPDUUpdateRequest(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes) 2600 { 2601 int rc = VINF_SUCCESS; 2602 PISCSICMD pIScsiCmd; 2603 uint32_t *paResBHS; 2604 2605 LogFlowFunc(("pImage=%#p paRes=%#p cnRes=%u\n", pImage, paRes, cnRes)); 2606 2607 Assert(cnRes == 1); 2608 Assert(paRes[0].cbSeg >= ISCSI_BHS_SIZE); 2609 2610 paResBHS = (uint32_t *)paRes[0].pvSeg; 2611 2612 pIScsiCmd = iscsiCmdGetFromItt(pImage, paResBHS[4]); 2613 2614 if (pIScsiCmd) 2615 { 2616 bool final = false; 2617 PSCSIREQ pScsiReq; 2618 2619 LogFlow(("Found SCSI command %#p for Itt=%#u\n", pIScsiCmd, paResBHS[4])); 2620 2621 Assert(pIScsiCmd->enmCmdType == ISCSICMDTYPE_REQ); 2622 pScsiReq = pIScsiCmd->CmdType.ScsiReq.pScsiReq; 2623 2624 final = !!(RT_N2H_U32(paResBHS[0]) & ISCSI_FINAL_BIT); 2625 ISCSIOPCODE cmd = (ISCSIOPCODE)(RT_N2H_U32(paResBHS[0]) & ISCSIOP_MASK); 2626 if (cmd == ISCSIOP_SCSI_RES) 2627 { 2628 /* This is the final PDU which delivers the status (and may be omitted if 2629 * the last Data-In PDU included successful completion status). Note 2630 * that ExpStatSN has been bumped already in iscsiRecvPDU. */ 2631 if (!final || ((RT_N2H_U32(paResBHS[0]) & 0x0000ff00) != 0) || (RT_N2H_U32(paResBHS[6]) != pImage->ExpStatSN - 1)) 2632 { 2633 /* SCSI Response in the wrong place or with a (target) failure. */ 2634 LogFlow(("Wrong ExpStatSN value in PDU\n")); 2635 rc = VERR_PARSE_ERROR; 2636 } 2637 else 2638 { 2639 pScsiReq->status = RT_N2H_U32(paResBHS[0]) & 0x000000ff; 2640 size_t cbData = RT_N2H_U32(paResBHS[1]) & 0x00ffffff; 2641 void *pvSense = (uint8_t *)paRes[0].pvSeg + ISCSI_BHS_SIZE; 2642 2643 if (cbData >= 2) 2644 { 2645 uint32_t cbStat = RT_N2H_U32(((uint32_t *)pvSense)[0]) >> 16; 2646 if (cbStat + 2 > cbData) 2647 { 2648 rc = VERR_BUFFER_OVERFLOW; 2649 } 2650 else 2651 { 2652 /* Truncate sense data if it doesn't fit into the buffer. */ 2653 pScsiReq->cbSense = RT_MIN(cbStat, pScsiReq->cbSense); 2654 memcpy(pScsiReq->pvSense, (uint8_t *)pvSense + 2, 2655 RT_MIN(paRes[0].cbSeg - ISCSI_BHS_SIZE - 2, pScsiReq->cbSense)); 2656 } 2657 } 2658 else if (cbData == 1) 2659 rc = VERR_PARSE_ERROR; 2660 else 2661 pScsiReq->cbSense = 0; 2662 } 2663 iscsiCmdComplete(pImage, pIScsiCmd, rc); 2664 } 2665 else if (cmd == ISCSIOP_SCSI_DATA_IN) 2666 { 2667 /* A Data-In PDU carries some data that needs to be added to the received 2668 * data in response to the command. There may be both partial and complete 2669 * Data-In PDUs, so collect data until the status is included or the status 2670 * is sent in a separate SCSI Result frame (see above). */ 2671 size_t cbData = RT_N2H_U32(paResBHS[1]) & 0x00ffffff; 2672 void *pvData = (uint8_t *)paRes[0].pvSeg + ISCSI_BHS_SIZE; 2673 2674 if (final && cbData > pScsiReq->cbT2IData) 2675 { 2676 /* The received PDU is partially stored in the buffer for status. 2677 * Must not happen under normal circumstances and is a target error. */ 2678 rc = VERR_BUFFER_OVERFLOW; 2679 } 2680 else 2681 { 2682 /* Copy data from the received PDU into the T2I segments. */ 2683 size_t cbCopied = RTSgBufCopyFromBuf(&pScsiReq->SgBufT2I, pvData, cbData); 2684 Assert(cbCopied == cbData); 2685 2686 if (final && (RT_N2H_U32(paResBHS[0]) & ISCSI_STATUS_BIT) != 0) 2687 { 2688 pScsiReq->status = RT_N2H_U32(paResBHS[0]) & 0x000000ff; 2689 pScsiReq->cbSense = 0; 2690 iscsiCmdComplete(pImage, pIScsiCmd, VINF_SUCCESS); 2691 } 2692 } 2693 } 2694 else 2695 rc = VERR_PARSE_ERROR; 2696 } 2697 2698 return rc; 2096 2699 } 2097 2700 … … 2435 3038 iscsiIoThreadPoke(pImage); 2436 3039 2437 /* Wait if the request is synchronous. */2438 if (pIScsiCmd->fSync)2439 {2440 rc = RTSemEventWait(pIScsiCmd->Type.Sync.EventSem, RT_INDEFINITE_WAIT);2441 AssertRC(rc);2442 rc = pIScsiCmd->Type.Sync.rcCmd;2443 }2444 else2445 rc = VINF_SUCCESS;2446 2447 3040 return rc; 2448 3041 } … … 2453 3046 * and asynchronous ones by continuing the associated I/O context. 2454 3047 */ 2455 static void iscsiCmdComplete(PISCSICMD pIScsiCmd, int rcCmd) 2456 { 2457 if (pIScsiCmd->fSync) 2458 { 2459 int rc; 2460 2461 /* Store completion code */ 2462 pIScsiCmd->Type.Sync.rcCmd = rcCmd; 2463 2464 /* 2465 * Wakeup the waiting thread. We are NOT allowed to touch the request 2466 * beyond this call. 2467 */ 2468 rc = RTSemEventSignal(pIScsiCmd->Type.Sync.EventSem); 2469 AssertRC(rc); 2470 } 2471 else 2472 AssertMsgFailed(("Not implemented yet\n")); 3048 static void iscsiCmdComplete(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd, int rcCmd) 3049 { 3050 LogFlowFunc(("pImage=%#p pIScsiCmd=%#p rcCmd=%Rrc\n", pImage, pIScsiCmd, rcCmd)); 3051 3052 /* Remove from the table first. */ 3053 iscsiCmdRemove(pImage, pIScsiCmd->Itt); 3054 3055 /* Call completion callback. */ 3056 pIScsiCmd->pfnComplete(pImage, rcCmd, pIScsiCmd->pvUser); 3057 3058 /* Free command structure. */ 3059 #ifdef DEBUG 3060 memset(pIScsiCmd, 0xff, sizeof(ISCSICMD)); 3061 #endif 3062 RTMemFree(pIScsiCmd); 2473 3063 } 2474 3064 … … 2485 3075 while (pImage->fRunning) 2486 3076 { 2487 uint32_t fEvents = 0;3077 uint32_t fEvents; 2488 3078 int rc; 3079 3080 fEvents = 0; 2489 3081 2490 3082 /* Wait for work or for data from the target. */ … … 2501 3093 case ISCSICMDTYPE_REQ: 2502 3094 { 2503 rc = iscsi Command(pImage, pIScsiCmd->CmdType.ScsiReq.pScsiReq);3095 rc = iscsiPDUTxPrepare(pImage, pIScsiCmd); 2504 3096 break; 2505 3097 } … … 2507 3099 { 2508 3100 rc = pIScsiCmd->CmdType.Exec.pfnExec(pIScsiCmd->CmdType.Exec.pvUser); 3101 iscsiCmdComplete(pImage, pIScsiCmd, rc); 2509 3102 break; 2510 3103 } … … 2513 3106 } 2514 3107 2515 iscsiCmdComplete(pIScsiCmd, rc);2516 3108 pIScsiCmd = iscsiCmdGet(pImage); 2517 3109 } … … 2519 3111 else if (RT_SUCCESS(rc)) 2520 3112 { 2521 /* 2522 * There is data on the socket. 2523 * 2524 * @todo: This will only handle NOP-IN requests. Check other requests. 2525 */ 3113 LogFlow(("Got socket events %#x\n", fEvents)); 3114 2526 3115 if (fEvents & VD_INTERFACETCPNET_EVT_READ) 2527 3116 { 2528 rc = iscsiRecvPDU(pImage, ISCSI_TASK_TAG_RSVD, NULL, 0, false); 3117 /* Continue or start a new PDU receive task */ 3118 LogFlow(("There is data on the socket\n")); 3119 rc = iscsiRecvPDUAsync(pImage); 2529 3120 if (RT_FAILURE(rc)) 2530 3121 LogRel(("iSCSI: Handling incoming request failed %Rrc\n", rc)); 2531 3122 } 3123 else if (fEvents & VD_INTERFACETCPNET_EVT_WRITE) 3124 { 3125 LogFlow(("The socket is writable\n")); 3126 rc = iscsiSendPDUAsync(pImage); 3127 if (RT_FAILURE(rc)) 3128 LogRel(("iSCSI: Sending PDU failed %Rrc\n", rc)); 3129 } 3130 else if (fEvents & VD_INTERFACETCPNET_EVT_ERROR) 3131 { 3132 /** @todo: Determine type of error, reset states, reconnect 3133 * and resend all active PDUs. 3134 */ 3135 LogFlow(("An error ocurred\n")); 3136 } 2532 3137 else 2533 3138 LogRel(("iSCSI: Received unexpected event %#x\n", fEvents)); … … 2540 3145 2541 3146 return VINF_SUCCESS; 3147 } 3148 3149 static void iscsiCommandAsyncComplete(PISCSIIMAGE pImage, int rcReq, void *pvUser) 3150 { 3151 size_t cbTransfered = 0; 3152 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)pvUser; 3153 PSCSIREQ pScsiReq = pReqAsync->pScsiReq; 3154 3155 /** @todo Retry and sense buffer handling. */ 3156 3157 if (pScsiReq->enmXfer == SCSIXFER_FROM_TARGET) 3158 cbTransfered = pScsiReq->cbT2IData; 3159 else if (pScsiReq->enmXfer == SCSIXFER_TO_TARGET) 3160 cbTransfered = pScsiReq->cbI2TData; 3161 else 3162 AssertMsg(pScsiReq->enmXfer == SCSIXFER_NONE, ("To/From transfers are not supported yet\n")); 3163 3164 /* Continue I/O context. */ 3165 pImage->pInterfaceIoCallbacks->pfnIoCtxCompleted(pImage->pInterfaceIo->pvUser, 3166 pReqAsync->pIoCtx, rcReq, 3167 cbTransfered); 3168 3169 RTMemFree(pScsiReq); 3170 RTMemFree(pReqAsync); 3171 } 3172 3173 static void iscsiCommandCompleteSync(PISCSIIMAGE pImage, int rcReq, void *pvUser) 3174 { 3175 PISCSICMDSYNC pIScsiCmdSync = (PISCSICMDSYNC)pvUser; 3176 3177 pIScsiCmdSync->rcCmd = rcReq; 3178 int rc = RTSemEventSignal(pIScsiCmdSync->EventSem); 3179 AssertRC(rc); 3180 } 3181 3182 /** 3183 * Internal. - Enqueues a request asynchronously. 3184 */ 3185 static int iscsiCommandAsync(PISCSIIMAGE pImage, PSCSIREQ pScsiReq, 3186 PFNISCSICMDCOMPLETED pfnComplete, void *pvUser) 3187 { 3188 int rc; 3189 3190 if (pImage->fExtendedSelectSupported) 3191 { 3192 PISCSICMD pIScsiCmd = (PISCSICMD)RTMemAllocZ(sizeof(ISCSICMD)); 3193 if (!pIScsiCmd) 3194 return VERR_NO_MEMORY; 3195 3196 /* Init the command structure. */ 3197 pIScsiCmd->pNext = NULL; 3198 pIScsiCmd->enmCmdType = ISCSICMDTYPE_REQ; 3199 pIScsiCmd->pfnComplete = pfnComplete; 3200 pIScsiCmd->pvUser = pvUser; 3201 pIScsiCmd->CmdType.ScsiReq.pScsiReq = pScsiReq; 3202 3203 rc = iscsiCmdPut(pImage, pIScsiCmd); 3204 if (RT_FAILURE(rc)) 3205 RTMemFree(pIScsiCmd); 3206 } 3207 else 3208 rc = VERR_NOT_SUPPORTED; 3209 3210 return rc; 2542 3211 } 2543 3212 … … 2552 3221 if (pImage->fExtendedSelectSupported) 2553 3222 { 2554 ISCSICMD IScsiCmd; 2555 2556 /* Init the command structure. */ 2557 IScsiCmd.pNext = NULL; 2558 IScsiCmd.enmCmdType = ISCSICMDTYPE_REQ; 2559 IScsiCmd.fSync = true; 2560 IScsiCmd.Type.Sync.rcCmd = VINF_SUCCESS; 2561 IScsiCmd.CmdType.ScsiReq.pScsiReq = pScsiReq; 3223 ISCSICMDSYNC IScsiCmdSync; 2562 3224 2563 3225 /* Create event semaphore. */ 2564 rc = RTSemEventCreate(&IScsiCmd .Type.Sync.EventSem);3226 rc = RTSemEventCreate(&IScsiCmdSync.EventSem); 2565 3227 if (RT_FAILURE(rc)) 2566 3228 return rc; … … 2570 3232 for (unsigned i = 0; i < 10; i++) 2571 3233 { 2572 rc = iscsiCmdPut(pImage, &IScsiCmd); 3234 rc = iscsiCommandAsync(pImage, pScsiReq, iscsiCommandCompleteSync, &IScsiCmdSync); 3235 if (RT_FAILURE(rc)) 3236 break; 3237 3238 rc = RTSemEventWait(IScsiCmdSync.EventSem, RT_INDEFINITE_WAIT); 3239 AssertRC(rc); 3240 rc = IScsiCmdSync.rcCmd; 3241 2573 3242 if ( (RT_SUCCESS(rc) && !pScsiReq->cbSense) 2574 3243 || RT_FAILURE(rc)) … … 2579 3248 else 2580 3249 { 2581 rc = iscsiCmdPut(pImage, &IScsiCmd); 2582 if (RT_SUCCESS(rc) && pScsiReq->cbSense > 0) 2583 rc = rcSense; 2584 } 2585 2586 RTSemEventDestroy(IScsiCmd.Type.Sync.EventSem); 3250 rc = iscsiCommandAsync(pImage, pScsiReq, iscsiCommandCompleteSync, &IScsiCmdSync); 3251 if (RT_SUCCESS(rc)) 3252 { 3253 rc = RTSemEventWait(IScsiCmdSync.EventSem, RT_INDEFINITE_WAIT); 3254 AssertRC(rc); 3255 rc = IScsiCmdSync.rcCmd; 3256 3257 if (RT_FAILURE(rc) || pScsiReq->cbSense > 0) 3258 rc = rcSense; 3259 } 3260 } 3261 3262 RTSemEventDestroy(IScsiCmdSync.EventSem); 2587 3263 } 2588 3264 else … … 2610 3286 } 2611 3287 3288 2612 3289 /** 2613 3290 * Internal. - Executes a given function in a synchronous fashion … … 2620 3297 if (pImage->fExtendedSelectSupported) 2621 3298 { 2622 ISCSICMD IScsiCmd; 3299 ISCSICMDSYNC IScsiCmdSync; 3300 PISCSICMD pIScsiCmd = (PISCSICMD)RTMemAllocZ(sizeof(ISCSICMD)); 3301 if (!pIScsiCmd) 3302 return VERR_NO_MEMORY; 3303 3304 /* Create event semaphore. */ 3305 rc = RTSemEventCreate(&IScsiCmdSync.EventSem); 3306 if (RT_FAILURE(rc)) 3307 { 3308 RTMemFree(pIScsiCmd); 3309 return rc; 3310 } 2623 3311 2624 3312 /* Init the command structure. */ 2625 IScsiCmd.pNext = NULL; 2626 IScsiCmd.enmCmdType = ISCSICMDTYPE_EXEC; 2627 IScsiCmd.fSync = true; 2628 IScsiCmd.Type.Sync.rcCmd = VINF_SUCCESS; 2629 IScsiCmd.CmdType.Exec.pfnExec = pfnExec; 2630 IScsiCmd.CmdType.Exec.pvUser = pvUser; 2631 2632 /* Create event semaphore. */ 2633 rc = RTSemEventCreate(&IScsiCmd.Type.Sync.EventSem); 3313 pIScsiCmd->pNext = NULL; 3314 pIScsiCmd->enmCmdType = ISCSICMDTYPE_EXEC; 3315 pIScsiCmd->pfnComplete = iscsiCommandCompleteSync; 3316 pIScsiCmd->pvUser = &IScsiCmdSync; 3317 pIScsiCmd->CmdType.Exec.pfnExec = pfnExec; 3318 pIScsiCmd->CmdType.Exec.pvUser = pvUser; 3319 3320 rc = iscsiCmdPut(pImage, pIScsiCmd); 2634 3321 if (RT_FAILURE(rc)) 2635 return rc; 2636 2637 rc = iscsiCmdPut(pImage, &IScsiCmd); 2638 RTSemEventDestroy(IScsiCmd.Type.Sync.EventSem); 3322 RTMemFree(pIScsiCmd); 3323 else 3324 { 3325 rc = RTSemEventWait(IScsiCmdSync.EventSem, RT_INDEFINITE_WAIT); 3326 AssertRC(rc); 3327 rc = IScsiCmdSync.rcCmd; 3328 } 3329 3330 RTSemEventDestroy(IScsiCmdSync.EventSem); 2639 3331 } 2640 3332 else … … 2746 3438 fHostIPDef = !!uHostIPTmp; 2747 3439 3440 #if 0 2748 3441 if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) 2749 3442 return VERR_NOT_SUPPORTED; 3443 #endif 2750 3444 2751 3445 pImage->uOpenFlags = uOpenFlags; … … 2980 3674 } 2981 3675 3676 memset(pImage->aCmdsWaiting, 0, sizeof(pImage->aCmdsWaiting)); 3677 2982 3678 /* Create the socket structure. */ 2983 3679 rc = pImage->pInterfaceNetCallbacks->pfnSocketCreate(VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT, … … 3033 3729 3034 3730 SCSIREQ sr; 3731 RTSGSEG DataSeg; 3035 3732 uint8_t sense[96]; 3036 3733 uint8_t data8[8]; … … 3055 3752 cdb_rlun[11] = 0; /* control */ 3056 3753 3754 DataSeg.pvSeg = rlundata; 3755 DataSeg.cbSeg = sizeof(rlundata); 3756 3057 3757 sr.enmXfer = SCSIXFER_FROM_TARGET; 3058 3758 sr.cbCmd = sizeof(cdb_rlun); 3059 3759 sr.pvCmd = cdb_rlun; 3060 3760 sr.cbI2TData = 0; 3061 sr.pcvI2TData = NULL; 3062 sr.cbT2IData = sizeof(rlundata); 3063 sr.pvT2IData = rlundata; 3064 sr.cbSense = sizeof(sense); 3065 sr.pvSense = sense; 3761 sr.paI2TSegs = NULL; 3762 sr.cI2TSegs = 0; 3763 sr.cbT2IData = DataSeg.cbSeg; 3764 sr.paT2ISegs = &DataSeg; 3765 sr.cT2ISegs = 1; 3766 sr.cbSense = sizeof(sense); 3767 sr.pvSense = sense; 3066 3768 3067 3769 rc = iscsiCommandSync(pImage, &sr, false, VERR_INVALID_STATE); … … 3083 3785 cdb_inq[5] = 0; /* control */ 3084 3786 3787 DataSeg.pvSeg = data8; 3788 DataSeg.cbSeg = sizeof(data8); 3789 3085 3790 sr.enmXfer = SCSIXFER_FROM_TARGET; 3086 3791 sr.cbCmd = sizeof(cdb_inq); 3087 3792 sr.pvCmd = cdb_inq; 3088 3793 sr.cbI2TData = 0; 3089 sr.pcvI2TData = NULL; 3090 sr.cbT2IData = sizeof(data8); 3091 sr.pvT2IData = data8; 3794 sr.paI2TSegs = NULL; 3795 sr.cI2TSegs = 0; 3796 sr.cbT2IData = DataSeg.cbSeg; 3797 sr.paT2ISegs = &DataSeg; 3798 sr.cT2ISegs = 1; 3092 3799 sr.cbSense = sizeof(sense); 3093 3800 sr.pvSense = sense; … … 3127 3834 cdb_ms[5] = 0; /* control */ 3128 3835 3836 DataSeg.pvSeg = data4; 3837 DataSeg.cbSeg = sizeof(data4); 3838 3129 3839 sr.enmXfer = SCSIXFER_FROM_TARGET; 3130 3840 sr.cbCmd = sizeof(cdb_ms); 3131 3841 sr.pvCmd = cdb_ms; 3132 3842 sr.cbI2TData = 0; 3133 sr.pcvI2TData = NULL; 3134 sr.cbT2IData = sizeof(data4); 3135 sr.pvT2IData = data4; 3843 sr.paI2TSegs = NULL; 3844 sr.cI2TSegs = 0; 3845 sr.cbT2IData = DataSeg.cbSeg; 3846 sr.paT2ISegs = &DataSeg; 3847 sr.cT2ISegs = 1; 3136 3848 sr.cbSense = sizeof(sense); 3137 3849 sr.pvSense = sense; … … 3163 3875 cdb_cap[10+3] = sizeof(data12); /* allocation length (dword) */ 3164 3876 3877 DataSeg.pvSeg = data12; 3878 DataSeg.cbSeg = sizeof(data12); 3879 3165 3880 sr.enmXfer = SCSIXFER_FROM_TARGET; 3166 3881 sr.cbCmd = sizeof(cdb_cap); 3167 3882 sr.pvCmd = cdb_cap; 3168 3883 sr.cbI2TData = 0; 3169 sr.pcvI2TData = NULL; 3170 sr.cbT2IData = sizeof(data12); 3171 sr.pvT2IData = data12; 3884 sr.paI2TSegs = NULL; 3885 sr.cI2TSegs = 0; 3886 sr.cbT2IData = DataSeg.cbSeg; 3887 sr.paT2ISegs = &DataSeg; 3888 sr.cT2ISegs = 1; 3172 3889 sr.cbSense = sizeof(sense); 3173 3890 sr.pvSense = sense; … … 3205 3922 cdb_capfb[9] = 0; /* control */ 3206 3923 3924 DataSeg.pvSeg = data8; 3925 DataSeg.cbSeg = sizeof(data8); 3926 3207 3927 sr.enmXfer = SCSIXFER_FROM_TARGET; 3208 3928 sr.cbCmd = sizeof(cdb_capfb); 3209 3929 sr.pvCmd = cdb_capfb; 3210 3930 sr.cbI2TData = 0; 3211 sr.pcvI2TData = NULL; 3212 sr.cbT2IData = sizeof(data8); 3213 sr.pvT2IData = data8; 3931 sr.paI2TSegs = NULL; 3932 sr.cI2TSegs = 0; 3933 sr.cbT2IData = DataSeg.cbSeg; 3934 sr.paT2ISegs = &DataSeg; 3935 sr.cT2ISegs = 1; 3214 3936 sr.cbSense = sizeof(sense); 3215 3937 sr.pvSense = sense; … … 3254 3976 aCDBModeSense6[4] = sizeof(aCachingModePage) & 0xff; 3255 3977 aCDBModeSense6[5] = 0; 3978 3979 DataSeg.pvSeg = aCachingModePage; 3980 DataSeg.cbSeg = sizeof(aCachingModePage); 3981 3256 3982 sr.enmXfer = SCSIXFER_FROM_TARGET; 3257 3983 sr.cbCmd = sizeof(aCDBModeSense6); 3258 3984 sr.pvCmd = aCDBModeSense6; 3259 3985 sr.cbI2TData = 0; 3260 sr.pcvI2TData = NULL; 3261 sr.cbT2IData = sizeof(aCachingModePage); 3262 sr.pvT2IData = aCachingModePage; 3986 sr.paI2TSegs = NULL; 3987 sr.cI2TSegs = 0; 3988 sr.cbT2IData = DataSeg.cbSeg; 3989 sr.paT2ISegs = &DataSeg; 3990 sr.cT2ISegs = 1; 3263 3991 sr.cbSense = sizeof(sense); 3264 3992 sr.pvSense = sense; … … 3293 4021 aCDBCaching[4] = sizeof(aCachingModePage) & 0xff; 3294 4022 aCDBCaching[5] = 0; 4023 4024 DataSeg.pvSeg = aCachingModePage; 4025 DataSeg.cbSeg = sizeof(aCachingModePage); 4026 3295 4027 sr.enmXfer = SCSIXFER_TO_TARGET; 3296 4028 sr.cbCmd = sizeof(aCDBCaching); 3297 4029 sr.pvCmd = aCDBCaching; 3298 sr.cbI2TData = sizeof(aCachingModePage); 3299 sr.pcvI2TData = aCachingModePage; 4030 sr.cbI2TData = DataSeg.cbSeg; 4031 sr.paI2TSegs = &DataSeg; 4032 sr.cI2TSegs = 1; 3300 4033 sr.cbT2IData = 0; 3301 sr.pvT2IData = NULL; 4034 sr.paT2ISegs = NULL; 4035 sr.cT2ISegs = 0; 3302 4036 sr.cbSense = sizeof(sense); 3303 4037 sr.pvSense = sense; … … 3489 4223 tls = (uint16_t)(cbToRead / pImage->cbSector); 3490 4224 SCSIREQ sr; 4225 RTSGSEG T2ISeg; 3491 4226 uint8_t cdb[10]; 3492 4227 uint8_t sense[96]; … … 3503 4238 cdb[9] = 0; /* control */ 3504 4239 3505 sr.enmXfer = SCSIXFER_FROM_TARGET; 3506 sr.cbCmd = sizeof(cdb); 3507 sr.pvCmd = cdb; 4240 T2ISeg.pvSeg = pvBuf; 4241 T2ISeg.cbSeg = cbToRead; 4242 4243 sr.enmXfer = SCSIXFER_FROM_TARGET; 4244 sr.cbCmd = sizeof(cdb); 4245 sr.pvCmd = cdb; 3508 4246 sr.cbI2TData = 0; 3509 sr.pcvI2TData = NULL; 4247 sr.paI2TSegs = NULL; 4248 sr.cI2TSegs = 0; 3510 4249 sr.cbT2IData = cbToRead; 3511 sr.pvT2IData = pvBuf; 3512 sr.cbSense = sizeof(sense); 3513 sr.pvSense = sense; 4250 sr.paT2ISegs = &T2ISeg; 4251 sr.cT2ISegs = 1; 4252 sr.cbSense = sizeof(sense); 4253 sr.pvSense = sense; 3514 4254 3515 4255 rc = iscsiCommandSync(pImage, &sr, true, VERR_READ_ERROR); … … 3563 4303 tls = (uint16_t)(cbToWrite / pImage->cbSector); 3564 4304 SCSIREQ sr; 4305 RTSGSEG I2TSeg; 3565 4306 uint8_t cdb[10]; 3566 4307 uint8_t sense[96]; … … 3577 4318 cdb[9] = 0; /* control */ 3578 4319 3579 sr.enmXfer = SCSIXFER_TO_TARGET; 3580 sr.cbCmd = sizeof(cdb); 3581 sr.pvCmd = cdb; 3582 sr.cbI2TData = cbToWrite; 3583 sr.pcvI2TData = pvBuf; 3584 sr.cbT2IData = 0; 3585 sr.pvT2IData = NULL; 3586 sr.cbSense = sizeof(sense); 3587 sr.pvSense = sense; 4320 I2TSeg.pvSeg = (void *)pvBuf; 4321 I2TSeg.cbSeg = cbToWrite; 4322 4323 sr.enmXfer = SCSIXFER_TO_TARGET; 4324 sr.cbCmd = sizeof(cdb); 4325 sr.pvCmd = cdb; 4326 sr.cbI2TData = cbToWrite; 4327 sr.paI2TSegs = &I2TSeg; 4328 sr.cI2TSegs = 1; 4329 sr.cbT2IData = 0; 4330 sr.paT2ISegs = NULL; 4331 sr.cT2ISegs = 0; 4332 sr.cbSense = sizeof(sense); 4333 sr.pvSense = sense; 3588 4334 3589 4335 rc = iscsiCommandSync(pImage, &sr, true, VERR_WRITE_ERROR); … … 3626 4372 cdb[9] = 0; /* control */ 3627 4373 3628 sr.enmXfer = SCSIXFER_TO_TARGET;3629 sr.cbCmd = sizeof(cdb);3630 sr.pvCmd = cdb;4374 sr.enmXfer = SCSIXFER_TO_TARGET; 4375 sr.cbCmd = sizeof(cdb); 4376 sr.pvCmd = cdb; 3631 4377 sr.cbI2TData = 0; 3632 sr.pcvI2TData = NULL; 4378 sr.paI2TSegs = NULL; 4379 sr.cI2TSegs = 0; 3633 4380 sr.cbT2IData = 0; 3634 sr.pvT2IData = NULL; 3635 sr.cbSense = sizeof(sense); 3636 sr.pvSense = sense; 4381 sr.paT2ISegs = NULL; 4382 sr.cT2ISegs = 0; 4383 sr.cbSense = sizeof(sense); 4384 sr.pvSense = sense; 3637 4385 3638 4386 rc = iscsiCommandSync(pImage, &sr, false, VINF_SUCCESS); … … 3801 4549 /* Image must be opened and the new flags must be valid. Just readonly and 3802 4550 * info flags are supported. */ 3803 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO )))4551 if (!pImage || (uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO))) 3804 4552 { 3805 4553 rc = VERR_INVALID_PARAMETER; … … 4223 4971 static bool iscsiIsAsyncIOSupported(void *pvBackendData) 4224 4972 { 4225 return false;4226 } 4227 4228 static int iscsiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cb Read,4973 return true; 4974 } 4975 4976 static int iscsiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbToRead, 4229 4977 PVDIOCTX pIoCtx, size_t *pcbActuallyRead) 4230 4978 { 4231 4979 PISCSIIMAGE pImage = (PISCSIIMAGE)pvBackendData; 4232 int rc = V ERR_NOT_SUPPORTED;4233 4234 LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cb Read=%u pcbActuallyRead=%p\n",4235 pvBackendData, uOffset, pIoCtx, cb Read, pcbActuallyRead));4236 4237 if (uOffset + cb Read > pImage->cbSize)4980 int rc = VINF_SUCCESS; 4981 4982 LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbToRead=%u pcbActuallyRead=%p\n", 4983 pvBackendData, uOffset, pIoCtx, cbToRead, pcbActuallyRead)); 4984 4985 if (uOffset + cbToRead > pImage->cbSize) 4238 4986 return VERR_INVALID_PARAMETER; 4987 4988 /* 4989 * Clip read size to a value which is supported by the target. 4990 */ 4991 cbToRead = RT_MIN(cbToRead, pImage->cbRecvDataLength); 4992 4993 unsigned cT2ISegs = 0; 4994 size_t cbSegs = 0; 4995 4996 /* Get the number of segments. */ 4997 cbSegs = pImage->pInterfaceIoCallbacks->pfnIoCtxSegArrayCreate(pImage->pInterfaceIo->pvUser, pIoCtx, 4998 NULL, &cT2ISegs, cbToRead); 4999 Assert(cbSegs == cbToRead); 5000 5001 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)RTMemAllocZ(RT_OFFSETOF(SCSIREQASYNC, aSegs[cT2ISegs])); 5002 if (RT_LIKELY(pReqAsync)) 5003 { 5004 PSCSIREQ pReq = (PSCSIREQ)RTMemAllocZ(sizeof(SCSIREQ)); 5005 if (pReq) 5006 { 5007 uint64_t lba; 5008 uint16_t tls; 5009 uint8_t *pbCDB = &pReqAsync->abCDB[0]; 5010 5011 lba = uOffset / pImage->cbSector; 5012 tls = (uint16_t)(cbToRead / pImage->cbSector); 5013 5014 cbSegs = pImage->pInterfaceIoCallbacks->pfnIoCtxSegArrayCreate(pImage->pInterfaceIo->pvUser, pIoCtx, 5015 &pReqAsync->aSegs[0], 5016 &cT2ISegs, cbToRead); 5017 Assert(cbSegs == cbToRead); 5018 pReqAsync->cT2ISegs = cT2ISegs; 5019 pReqAsync->pIoCtx = pIoCtx; 5020 pReqAsync->pScsiReq = pReq; 5021 5022 pbCDB[0] = SCSI_READ_10; 5023 pbCDB[1] = 0; /* reserved */ 5024 pbCDB[2] = (lba >> 24) & 0xff; 5025 pbCDB[3] = (lba >> 16) & 0xff; 5026 pbCDB[4] = (lba >> 8) & 0xff; 5027 pbCDB[5] = lba & 0xff; 5028 pbCDB[6] = 0; /* reserved */ 5029 pbCDB[7] = (tls >> 8) & 0xff; 5030 pbCDB[8] = tls & 0xff; 5031 pbCDB[9] = 0; /* control */ 5032 5033 pReq->enmXfer = SCSIXFER_FROM_TARGET; 5034 pReq->cbCmd = sizeof(pReqAsync->abCDB); 5035 pReq->pvCmd = pReqAsync->abCDB; 5036 pReq->cbI2TData = 0; 5037 pReq->paI2TSegs = NULL; 5038 pReq->cI2TSegs = 0; 5039 pReq->cbT2IData = cbToRead; 5040 pReq->paT2ISegs = &pReqAsync->aSegs[pReqAsync->cI2TSegs]; 5041 pReq->cT2ISegs = pReqAsync->cT2ISegs; 5042 pReq->cbSense = sizeof(pReqAsync->abSense); 5043 pReq->pvSense = pReqAsync->abSense; 5044 5045 rc = iscsiCommandAsync(pImage, pReq, iscsiCommandAsyncComplete, pReqAsync); 5046 if (RT_FAILURE(rc)) 5047 AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc)); 5048 else 5049 { 5050 *pcbActuallyRead = cbToRead; 5051 return VERR_VD_IOCTX_HALT; /* Halt the I/O context until further notification from the I/O thread. */ 5052 } 5053 5054 RTMemFree(pReq); 5055 } 5056 else 5057 rc = VERR_NO_MEMORY; 5058 5059 RTMemFree(pReqAsync); 5060 } 5061 else 5062 rc = VERR_NO_MEMORY; 4239 5063 4240 5064 LogFlowFunc(("returns rc=%Rrc\n", rc)); … … 4242 5066 } 4243 5067 4244 static int iscsiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cb Write,5068 static int iscsiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbToWrite, 4245 5069 PVDIOCTX pIoCtx, 4246 5070 size_t *pcbWriteProcess, size_t *pcbPreRead, … … 4248 5072 { 4249 5073 PISCSIIMAGE pImage = (PISCSIIMAGE)pvBackendData; 4250 int rc = V ERR_NOT_SUPPORTED;4251 4252 LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cb Write=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",4253 pvBackendData, uOffset, pIoCtx, cb Write, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite));5074 int rc = VINF_SUCCESS; 5075 5076 LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbToWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n", 5077 pvBackendData, uOffset, pIoCtx, cbToWrite, pcbWriteProcess, pcbPreRead, pcbPostRead, fWrite)); 4254 5078 4255 5079 AssertPtr(pImage); 4256 5080 Assert(uOffset % 512 == 0); 4257 Assert(cb Write % 512 == 0);4258 4259 if (uOffset + cb Write > pImage->cbSize)5081 Assert(cbToWrite % 512 == 0); 5082 5083 if (uOffset + cbToWrite > pImage->cbSize) 4260 5084 return VERR_INVALID_PARAMETER; 4261 5085 5086 /* 5087 * Clip read size to a value which is supported by the target. 5088 */ 5089 cbToWrite = RT_MIN(cbToWrite, pImage->cbSendDataLength); 5090 5091 unsigned cI2TSegs = 0; 5092 size_t cbSegs = 0; 5093 5094 /* Get the number of segments. */ 5095 cbSegs = pImage->pInterfaceIoCallbacks->pfnIoCtxSegArrayCreate(pImage->pInterfaceIo->pvUser, pIoCtx, 5096 NULL, &cI2TSegs, cbToWrite); 5097 Assert(cbSegs == cbToWrite); 5098 5099 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)RTMemAllocZ(RT_OFFSETOF(SCSIREQASYNC, aSegs[cI2TSegs])); 5100 if (RT_LIKELY(pReqAsync)) 5101 { 5102 PSCSIREQ pReq = (PSCSIREQ)RTMemAllocZ(sizeof(SCSIREQ)); 5103 if (pReq) 5104 { 5105 uint64_t lba; 5106 uint16_t tls; 5107 uint8_t *pbCDB = &pReqAsync->abCDB[0]; 5108 5109 lba = uOffset / pImage->cbSector; 5110 tls = (uint16_t)(cbToWrite / pImage->cbSector); 5111 5112 cbSegs = pImage->pInterfaceIoCallbacks->pfnIoCtxSegArrayCreate(pImage->pInterfaceIo->pvUser, pIoCtx, 5113 &pReqAsync->aSegs[0], 5114 &cI2TSegs, cbToWrite); 5115 Assert(cbSegs == cbToWrite); 5116 pReqAsync->cI2TSegs = cI2TSegs; 5117 pReqAsync->pIoCtx = pIoCtx; 5118 pReqAsync->pScsiReq = pReq; 5119 5120 pbCDB[0] = SCSI_WRITE_10; 5121 pbCDB[1] = 0; /* reserved */ 5122 pbCDB[2] = (lba >> 24) & 0xff; 5123 pbCDB[3] = (lba >> 16) & 0xff; 5124 pbCDB[4] = (lba >> 8) & 0xff; 5125 pbCDB[5] = lba & 0xff; 5126 pbCDB[6] = 0; /* reserved */ 5127 pbCDB[7] = (tls >> 8) & 0xff; 5128 pbCDB[8] = tls & 0xff; 5129 pbCDB[9] = 0; /* control */ 5130 5131 pReq->enmXfer = SCSIXFER_TO_TARGET; 5132 pReq->cbCmd = sizeof(pReqAsync->abCDB); 5133 pReq->pvCmd = pReqAsync->abCDB; 5134 pReq->cbI2TData = cbToWrite; 5135 pReq->paI2TSegs = &pReqAsync->aSegs[0]; 5136 pReq->cI2TSegs = pReqAsync->cI2TSegs; 5137 pReq->cbT2IData = 0; 5138 pReq->paT2ISegs = NULL; 5139 pReq->cT2ISegs = 0; 5140 pReq->cbSense = sizeof(pReqAsync->abSense); 5141 pReq->pvSense = pReqAsync->abSense; 5142 5143 rc = iscsiCommandAsync(pImage, pReq, iscsiCommandAsyncComplete, pReqAsync); 5144 if (RT_FAILURE(rc)) 5145 AssertMsgFailed(("iscsiCommand(%s, %#llx) -> %Rrc\n", pImage->pszTargetName, uOffset, rc)); 5146 else 5147 { 5148 *pcbWriteProcess = cbToWrite; 5149 return VERR_VD_IOCTX_HALT; /* Halt the I/O context until further notification from the I/O thread. */ 5150 } 5151 5152 RTMemFree(pReq); 5153 } 5154 else 5155 rc = VERR_NO_MEMORY; 5156 5157 RTMemFree(pReqAsync); 5158 } 5159 else 5160 rc = VERR_NO_MEMORY; 5161 5162 LogFlowFunc(("returns rc=%Rrc\n", rc)); 4262 5163 return rc; 4263 5164 } … … 4266 5167 { 4267 5168 PISCSIIMAGE pImage = (PISCSIIMAGE)pvBackendData; 4268 4269 return VERR_NOT_SUPPORTED; 5169 int rc = VINF_SUCCESS; 5170 5171 LogFlowFunc(("pvBackendData=%p pIoCtx=%#p\n", pvBackendData, pIoCtx)); 5172 5173 PSCSIREQASYNC pReqAsync = (PSCSIREQASYNC)RTMemAllocZ(sizeof(SCSIREQASYNC)); 5174 if (RT_LIKELY(pReqAsync)) 5175 { 5176 PSCSIREQ pReq = (PSCSIREQ)RTMemAllocZ(sizeof(SCSIREQ)); 5177 if (pReq) 5178 { 5179 uint8_t *pbCDB = &pReqAsync->abCDB[0]; 5180 5181 pReqAsync->pIoCtx = pIoCtx; 5182 pReqAsync->pScsiReq = pReq; 5183 5184 pbCDB[0] = SCSI_SYNCHRONIZE_CACHE; 5185 pbCDB[1] = 0; /* reserved */ 5186 pbCDB[2] = 0; /* reserved */ 5187 pbCDB[3] = 0; /* reserved */ 5188 pbCDB[4] = 0; /* reserved */ 5189 pbCDB[5] = 0; /* reserved */ 5190 pbCDB[6] = 0; /* reserved */ 5191 pbCDB[7] = 0; /* reserved */ 5192 pbCDB[8] = 0; /* reserved */ 5193 pbCDB[9] = 0; /* control */ 5194 5195 pReq->enmXfer = SCSIXFER_TO_TARGET; 5196 pReq->cbCmd = sizeof(pReqAsync->abCDB); 5197 pReq->pvCmd = pReqAsync->abCDB; 5198 pReq->cbI2TData = 0; 5199 pReq->paI2TSegs = NULL; 5200 pReq->cI2TSegs = 0; 5201 pReq->cbT2IData = 0; 5202 pReq->paT2ISegs = NULL; 5203 pReq->cT2ISegs = 0; 5204 pReq->cbSense = sizeof(pReqAsync->abSense); 5205 pReq->pvSense = pReqAsync->abSense; 5206 5207 rc = iscsiCommandAsync(pImage, pReq, iscsiCommandAsyncComplete, pReqAsync); 5208 if (RT_FAILURE(rc)) 5209 AssertMsgFailed(("iscsiCommand(%s) -> %Rrc\n", pImage->pszTargetName, rc)); 5210 else 5211 return VERR_VD_IOCTX_HALT; /* Halt the I/O context until further notification from the I/O thread. */ 5212 5213 RTMemFree(pReq); 5214 } 5215 else 5216 rc = VERR_NO_MEMORY; 5217 5218 RTMemFree(pReqAsync); 5219 } 5220 else 5221 rc = VERR_NO_MEMORY; 5222 5223 LogFlowFunc(("returns rc=%Rrc\n", rc)); 5224 return rc; 4270 5225 } 4271 5226 … … 4278 5233 sizeof(VBOXHDDBACKEND), 4279 5234 /* uBackendCaps */ 4280 VD_CAP_CONFIG | VD_CAP_TCPNET ,5235 VD_CAP_CONFIG | VD_CAP_TCPNET | VD_CAP_ASYNC, 4281 5236 /* papszFileExtensions */ 4282 5237 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.