VirtualBox

Changeset 31587 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 11, 2010 10:20:50 PM (14 years ago)
Author:
vboxsync
Message:

iSCSI: First working version of async iSCSI

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp

    r31456 r31587  
    2121*******************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_VD_ISCSI
     23#define RTMEM_NO_WRAP_TO_EF_APIS
    2324#include <VBox/VBoxHDD-Plugin.h>
    2425#define VBOX_VDICORE_VD /* Signal that the header is included from here. */
     
    222223#define ISCSI_SG_SEGMENTS_MAX 4
    223224
     225/** Number of entries in the command table. */
     226#define ISCSI_CMD_WAITING_ENTRIES 32
    224227
    225228/**
     
    324327} SCSIXFER, *PSCSIXFER;
    325328
     329/** Forward declaration. */
     330typedef struct ISCSIIMAGE *PISCSIIMAGE;
    326331
    327332/**
     
    344349    /** Pointer to command block. */
    345350    void           *pvCmd;
    346     /** Pointer to Initiator2Target data buffer. */
    347     const void     *pcvI2TData;
    348     /** Pointer to Target2Initiator data buffer. */
    349     void           *pvT2IData;
    350351    /** Pointer to sense buffer. */
    351352    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;
    352363} SCSIREQ, *PSCSIREQ;
    353364
     365/**
     366 * Async request structure holding all necessary data for
     367 * request processing.
     368 */
     369typedef 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;
    354389
    355390typedef enum ISCSICMDTYPE
     
    365400
    366401/** The command completion function. */
    367 typedef DECLCALLBACK(void) FNISCSICMDCOMPLETED(void *pvUser);
     402typedef DECLCALLBACK(void) FNISCSICMDCOMPLETED(PISCSIIMAGE pImage, int rcReq, void *pvUser);
    368403/** Pointer to a command completion function. */
    369404typedef FNISCSICMDCOMPLETED *PFNISCSICMDCOMPLETED;
     
    373408/** Pointer to a command execution function. */
    374409typedef FNISCSIEXEC *PFNISCSIEXEC;
     410
     411/**
     412 * Structure used to complete a synchronous request.
     413 */
     414typedef 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;
    375421
    376422/**
     
    382428{
    383429    /** 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;
    385437    /** 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;
    409439    /** Command type dependent data. */
    410440    union
     
    426456    } CmdType;
    427457} ISCSICMD, *PISCSICMD;
     458
     459/**
     460 *  Send iSCSI PDU.
     461 *  Contains all necessary data to send a PDU.
     462 */
     463typedef 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;
    428480
    429481/**
     
    548600    /** Socket events to poll for. */
    549601    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;
    551618
    552619
     
    596663static int iscsiSendPDU(PISCSIIMAGE pImage, PISCSIREQ paReq, uint32_t cnReq, uint32_t uFlags);
    597664static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes, bool fSelect);
     665static int iscsiRecvPDUAsync(PISCSIIMAGE pImage);
     666static int iscsiSendPDUAsync(PISCSIIMAGE pImage);
    598667static int iscsiValidatePDU(PISCSIRES paRes, uint32_t cnRes);
     668static int iscsiRecvPDUProcess(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes);
     669static int iscsiPDUTxPrepare(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd);
     670static int iscsiRecvPDUUpdateRequest(PISCSIIMAGE pImage, PISCSIRES paRes, uint32_t cnRes);
     671static void iscsiCmdComplete(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd, int rcCmd);
    599672static int iscsiTextAddKeyValue(uint8_t *pbBuf, size_t cbBuf, size_t *pcbBufCurr, const char *pcszKey, const char *pcszValue, size_t cbValue);
    600673static int iscsiTextGetKeyValue(const uint8_t *pbBuf, size_t cbBuf, const char *pcszKey, const char **ppcszValue);
     
    638711    return    pImage->Socket != NIL_VDSOCKET
    639712           && 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 */
     719DECLINLINE(uint32_t) iscsiIttHash(uint32_t Itt)
     720{
     721    return Itt % ISCSI_CMD_WAITING_ENTRIES;
     722}
     723
     724static 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
     737static 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
     749static 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;
    640780}
    641781
     
    705845    }
    706846
    707     if (RT_SUCCESS(rc) && paResponse[0].cbSeg >= 48)
     847    if (RT_SUCCESS(rc) && paResponse[0].cbSeg >= ISCSI_BHS_SIZE)
    708848    {
    709849        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. */
    711851        cbSegActual = residual;
    712852        pDst = (char *)paResponse[i].pvSeg;
     
    755895                    cbDataLength = ((cbDataLength - 1) | 3) + 1;    /* Add padding. */
    756896                    cbToRead = residual + cbAHSLength + cbDataLength;
    757                     residual += paResponse[0].cbSeg - 48;
     897                    residual += paResponse[0].cbSeg - ISCSI_BHS_SIZE;
    758898                    if (residual > cbToRead)
    759899                        residual = cbToRead;
    760                     cbSegActual = 48 + cbAHSLength + cbDataLength;
     900                    cbSegActual = ISCSI_BHS_SIZE + cbAHSLength + cbDataLength;
    761901                    /* Check whether we are already done with this PDU (no payload). */
    762902                    if (cbToRead == 0)
     
    16141754        ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
    16151755    {
    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. */
    16181759        cnISCSIReq++;
    16191760    }
     
    16331774        ||  pRequest->enmXfer == SCSIXFER_TO_FROM_TARGET)
    16341775    {
    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;
    16371779    }
    16381780    else
     
    20042146
    20052147/**
     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 */
     2153static 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
     2213static 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 */
     2273static 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/**
    20062399 * Check the static (not dependent on the connection/session state) validity of an iSCSI response PDU.
    20072400 *
     
    20162409    Assert(cnRes >= 1);
    20172410    Assert(paRes[0].cbSeg >= ISCSI_BHS_SIZE);
     2411
     2412    LogFlowFunc(("paRes=%#p cnRes=%u\n", paRes, cnRes));
    20182413
    20192414    pcrgResBHS = (const uint32_t *)(paRes[0].pvSeg);
     
    20942489
    20952490    return VINF_SUCCESS;
     2491}
     2492
     2493/**
     2494 * Prepares a PDU to transfer for the given command and adds it to the list.
     2495 */
     2496static 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 */
     2599static 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;
    20962699}
    20972700
     
    24353038    iscsiIoThreadPoke(pImage);
    24363039
    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     else
    2445         rc = VINF_SUCCESS;
    2446 
    24473040    return rc;
    24483041}
     
    24533046 *             and asynchronous ones by continuing the associated I/O context.
    24543047 */
    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"));
     3048static 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);
    24733063}
    24743064
     
    24853075    while (pImage->fRunning)
    24863076    {
    2487         uint32_t fEvents = 0;
     3077        uint32_t fEvents;
    24883078        int rc;
     3079
     3080        fEvents = 0;
    24893081
    24903082        /* Wait for work or for data from the target. */
     
    25013093                    case ISCSICMDTYPE_REQ:
    25023094                    {
    2503                         rc = iscsiCommand(pImage, pIScsiCmd->CmdType.ScsiReq.pScsiReq);
     3095                        rc = iscsiPDUTxPrepare(pImage, pIScsiCmd);
    25043096                        break;
    25053097                    }
     
    25073099                    {
    25083100                        rc = pIScsiCmd->CmdType.Exec.pfnExec(pIScsiCmd->CmdType.Exec.pvUser);
     3101                        iscsiCmdComplete(pImage, pIScsiCmd, rc);
    25093102                        break;
    25103103                    }
     
    25133106                }
    25143107
    2515                 iscsiCmdComplete(pIScsiCmd, rc);
    25163108                pIScsiCmd = iscsiCmdGet(pImage);
    25173109            }
     
    25193111        else if (RT_SUCCESS(rc))
    25203112        {
    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
    25263115            if (fEvents & VD_INTERFACETCPNET_EVT_READ)
    25273116            {
    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);
    25293120                if (RT_FAILURE(rc))
    25303121                    LogRel(("iSCSI: Handling incoming request failed %Rrc\n", rc));
    25313122            }
     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            }
    25323137            else
    25333138                LogRel(("iSCSI: Received unexpected event %#x\n", fEvents));
     
    25403145
    25413146    return VINF_SUCCESS;
     3147}
     3148
     3149static 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
     3173static 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 */
     3185static 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;
    25423211}
    25433212
     
    25523221    if (pImage->fExtendedSelectSupported)
    25533222    {
    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;
    25623224
    25633225        /* Create event semaphore. */
    2564         rc = RTSemEventCreate(&IScsiCmd.Type.Sync.EventSem);
     3226        rc = RTSemEventCreate(&IScsiCmdSync.EventSem);
    25653227        if (RT_FAILURE(rc))
    25663228            return rc;
     
    25703232            for (unsigned i = 0; i < 10; i++)
    25713233            {
    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
    25733242                if (    (RT_SUCCESS(rc) && !pScsiReq->cbSense)
    25743243                    ||  RT_FAILURE(rc))
     
    25793248        else
    25803249        {
    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);
    25873263    }
    25883264    else
     
    26103286}
    26113287
     3288
    26123289/**
    26133290 * Internal. - Executes a given function in a synchronous fashion
     
    26203297    if (pImage->fExtendedSelectSupported)
    26213298    {
    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        }
    26233311
    26243312        /* 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);
    26343321        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);
    26393331    }
    26403332    else
     
    27463438    fHostIPDef = !!uHostIPTmp;
    27473439
     3440#if 0
    27483441    if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
    27493442        return VERR_NOT_SUPPORTED;
     3443#endif
    27503444
    27513445    pImage->uOpenFlags      = uOpenFlags;
     
    29803674    }
    29813675
     3676    memset(pImage->aCmdsWaiting, 0, sizeof(pImage->aCmdsWaiting));
     3677
    29823678    /* Create the socket structure. */
    29833679    rc = pImage->pInterfaceNetCallbacks->pfnSocketCreate(VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT,
     
    30333729
    30343730    SCSIREQ sr;
     3731    RTSGSEG DataSeg;
    30353732    uint8_t sense[96];
    30363733    uint8_t data8[8];
     
    30553752    cdb_rlun[11] = 0;       /* control */
    30563753
     3754    DataSeg.pvSeg = rlundata;
     3755    DataSeg.cbSeg = sizeof(rlundata);
     3756
    30573757    sr.enmXfer = SCSIXFER_FROM_TARGET;
    30583758    sr.cbCmd = sizeof(cdb_rlun);
    30593759    sr.pvCmd = cdb_rlun;
    30603760    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;
    30663768
    30673769    rc = iscsiCommandSync(pImage, &sr, false, VERR_INVALID_STATE);
     
    30833785    cdb_inq[5] = 0;         /* control */
    30843786
     3787    DataSeg.pvSeg = data8;
     3788    DataSeg.cbSeg = sizeof(data8);
     3789
    30853790    sr.enmXfer = SCSIXFER_FROM_TARGET;
    30863791    sr.cbCmd = sizeof(cdb_inq);
    30873792    sr.pvCmd = cdb_inq;
    30883793    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;
    30923799    sr.cbSense = sizeof(sense);
    30933800    sr.pvSense = sense;
     
    31273834    cdb_ms[5] = 0;          /* control */
    31283835
     3836    DataSeg.pvSeg = data4;
     3837    DataSeg.cbSeg = sizeof(data4);
     3838
    31293839    sr.enmXfer = SCSIXFER_FROM_TARGET;
    31303840    sr.cbCmd = sizeof(cdb_ms);
    31313841    sr.pvCmd = cdb_ms;
    31323842    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;
    31363848    sr.cbSense = sizeof(sense);
    31373849    sr.pvSense = sense;
     
    31633875    cdb_cap[10+3] = sizeof(data12);                     /* allocation length (dword) */
    31643876
     3877    DataSeg.pvSeg = data12;
     3878    DataSeg.cbSeg = sizeof(data12);
     3879
    31653880    sr.enmXfer = SCSIXFER_FROM_TARGET;
    31663881    sr.cbCmd = sizeof(cdb_cap);
    31673882    sr.pvCmd = cdb_cap;
    31683883    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;
    31723889    sr.cbSense = sizeof(sense);
    31733890    sr.pvSense = sense;
     
    32053922        cdb_capfb[9] = 0;   /* control */
    32063923
     3924        DataSeg.pvSeg = data8;
     3925        DataSeg.cbSeg = sizeof(data8);
     3926
    32073927        sr.enmXfer = SCSIXFER_FROM_TARGET;
    32083928        sr.cbCmd = sizeof(cdb_capfb);
    32093929        sr.pvCmd = cdb_capfb;
    32103930        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;
    32143936        sr.cbSense = sizeof(sense);
    32153937        sr.pvSense = sense;
     
    32543976    aCDBModeSense6[4] = sizeof(aCachingModePage) & 0xff;
    32553977    aCDBModeSense6[5] = 0;
     3978
     3979    DataSeg.pvSeg = aCachingModePage;
     3980    DataSeg.cbSeg = sizeof(aCachingModePage);
     3981
    32563982    sr.enmXfer = SCSIXFER_FROM_TARGET;
    32573983    sr.cbCmd = sizeof(aCDBModeSense6);
    32583984    sr.pvCmd = aCDBModeSense6;
    32593985    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;
    32633991    sr.cbSense = sizeof(sense);
    32643992    sr.pvSense = sense;
     
    32934021            aCDBCaching[4] = sizeof(aCachingModePage) & 0xff;
    32944022            aCDBCaching[5] = 0;
     4023
     4024            DataSeg.pvSeg = aCachingModePage;
     4025            DataSeg.cbSeg = sizeof(aCachingModePage);
     4026
    32954027            sr.enmXfer = SCSIXFER_TO_TARGET;
    32964028            sr.cbCmd = sizeof(aCDBCaching);
    32974029            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;
    33004033            sr.cbT2IData = 0;
    3301             sr.pvT2IData = NULL;
     4034            sr.paT2ISegs = NULL;
     4035            sr.cT2ISegs  = 0;
    33024036            sr.cbSense = sizeof(sense);
    33034037            sr.pvSense = sense;
     
    34894223    tls = (uint16_t)(cbToRead / pImage->cbSector);
    34904224    SCSIREQ sr;
     4225    RTSGSEG T2ISeg;
    34914226    uint8_t cdb[10];
    34924227    uint8_t sense[96];
     
    35034238    cdb[9] = 0;         /* control */
    35044239
    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;
    35084246    sr.cbI2TData = 0;
    3509     sr.pcvI2TData = NULL;
     4247    sr.paI2TSegs = NULL;
     4248    sr.cI2TSegs  = 0;
    35104249    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;
    35144254
    35154255    rc = iscsiCommandSync(pImage, &sr, true, VERR_READ_ERROR);
     
    35634303    tls = (uint16_t)(cbToWrite / pImage->cbSector);
    35644304    SCSIREQ sr;
     4305    RTSGSEG I2TSeg;
    35654306    uint8_t cdb[10];
    35664307    uint8_t sense[96];
     
    35774318    cdb[9] = 0;         /* control */
    35784319
    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;
    35884334
    35894335    rc = iscsiCommandSync(pImage, &sr, true, VERR_WRITE_ERROR);
     
    36264372    cdb[9] = 0;         /* control */
    36274373
    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;
    36314377    sr.cbI2TData = 0;
    3632     sr.pcvI2TData = NULL;
     4378    sr.paI2TSegs = NULL;
     4379    sr.cI2TSegs  = 0;
    36334380    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;
    36374385
    36384386    rc = iscsiCommandSync(pImage, &sr, false, VINF_SUCCESS);
     
    38014549    /* Image must be opened and the new flags must be valid. Just readonly and
    38024550     * 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)))
    38044552    {
    38054553        rc = VERR_INVALID_PARAMETER;
     
    42234971static bool iscsiIsAsyncIOSupported(void *pvBackendData)
    42244972{
    4225     return false;
    4226 }
    4227 
    4228 static int iscsiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
     4973    return true;
     4974}
     4975
     4976static int iscsiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbToRead,
    42294977                          PVDIOCTX pIoCtx, size_t *pcbActuallyRead)
    42304978{
    42314979    PISCSIIMAGE pImage = (PISCSIIMAGE)pvBackendData;
    4232     int rc = VERR_NOT_SUPPORTED;
    4233 
    4234     LogFlowFunc(("pBackendData=%p uOffset=%#llx pIoCtx=%#p cbRead=%u pcbActuallyRead=%p\n",
    4235                      pvBackendData, uOffset, pIoCtx, cbRead, pcbActuallyRead));
    4236 
    4237     if (uOffset + cbRead > 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)
    42384986        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;
    42395063
    42405064    LogFlowFunc(("returns rc=%Rrc\n", rc));
     
    42425066}
    42435067
    4244 static int iscsiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
     5068static int iscsiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbToWrite,
    42455069                           PVDIOCTX pIoCtx,
    42465070                           size_t *pcbWriteProcess, size_t *pcbPreRead,
     
    42485072{
    42495073    PISCSIIMAGE pImage = (PISCSIIMAGE)pvBackendData;
    4250     int rc = VERR_NOT_SUPPORTED;
    4251 
    4252     LogFlowFunc(("pBackendData=%p uOffset=%llu pIoCtx=%#p cbWrite=%u pcbWriteProcess=%p pcbPreRead=%p pcbPostRead=%p fWrite=%u\n",
    4253                  pvBackendData, uOffset, pIoCtx, cbWrite, 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));
    42545078
    42555079    AssertPtr(pImage);
    42565080    Assert(uOffset % 512 == 0);
    4257     Assert(cbWrite % 512 == 0);
    4258 
    4259     if (uOffset + cbWrite > pImage->cbSize)
     5081    Assert(cbToWrite % 512 == 0);
     5082
     5083    if (uOffset + cbToWrite > pImage->cbSize)
    42605084        return VERR_INVALID_PARAMETER;
    42615085
     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));
    42625163    return rc;
    42635164}
     
    42665167{
    42675168    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;
    42705225}
    42715226
     
    42785233    sizeof(VBOXHDDBACKEND),
    42795234    /* uBackendCaps */
    4280     VD_CAP_CONFIG | VD_CAP_TCPNET,
     5235    VD_CAP_CONFIG | VD_CAP_TCPNET | VD_CAP_ASYNC,
    42815236    /* papszFileExtensions */
    42825237    NULL,
Note: See TracChangeset for help on using the changeset viewer.

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