VirtualBox

Changeset 80527 in vbox for trunk/src


Ignore:
Timestamp:
Sep 1, 2019 4:28:56 PM (5 years ago)
Author:
vboxsync
Message:

Storage/DevVirtioSCSI.cpp: Added code to intercept requests to non-existent LUNs and return proper sense code, since DrvSCSI layer doesn't. Also fixed usage of rcReq returned from DrvSCSI callback. See bugref:9440, Comment #63

Location:
trunk/src/VBox/Devices
Files:
3 edited

Legend:

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

    r80522 r80527  
    179179struct REQ_RESP_HDR
    180180{
    181     uint32_t uSenseLen;                                         /**< sense_len                                    */
     181    uint32_t cbSense;                                           /**< sense_len                                    */
    182182    uint32_t uResidual;                                         /**< residual                                     */
    183183    uint16_t uStatusQualifier;                                  /**< status_qualifier                             */
     
    620620        return cbMax;
    621621}
    622 DECLINLINE(uint8_t) virtioScsiMapVerrToVirtio(uint32_t vboxRc)
    623 {
    624     switch(vboxRc)
    625     {
    626         case VINF_SUCCESS:
    627             return VIRTIOSCSI_S_OK;
    628 
    629         case VERR_PDM_MEDIAEX_IOBUF_OVERFLOW:
    630             return VIRTIOSCSI_S_OVERRUN;
    631 
    632         case VERR_PDM_MEDIAEX_IOBUF_UNDERRUN:
    633             return VIRTIOSCSI_S_TRANSPORT_FAILURE;
    634 
    635         case VERR_IO_BAD_UNIT:
    636             return VIRTIOSCSI_S_BAD_TARGET;
    637 
    638         case VERR_RESOURCE_BUSY:
    639             return VIRTIOSCSI_S_BUSY;
    640 
    641         case VERR_STATE_CHANGED:
    642             return VIRTIOSCSI_S_RESET;
    643 
    644         case VERR_CANCELLED:
    645             return VIRTIOSCSI_S_ABORTED;
    646 
    647         case VERR_IO_NOT_READY:
    648             return VIRTIOSCSI_S_TARGET_FAILURE;
    649 
    650         case VERR_DEV_IO_ERROR:
    651             return VIRTIOSCSI_S_TRANSPORT_FAILURE;
    652 
    653         case VERR_NOT_SUPPORTED:
    654             return VIRTIOSCSI_S_NEXUS_FAILURE;
    655 
    656         case VERR_IO_GEN_FAILURE:
    657             return VIRTIOSCSI_S_FAILURE;
    658     }
    659     return VIRTIOSCSI_S_FAILURE;
    660 }
    661622
    662623/**
     
    772733    /** DrvSCSI.cpp, that issues this callback, just sticks one segment in the buffer */
    773734    memcpy(pReq->pbDataIn + offDst, pSgBuf->paSegs[0].pvSeg, cbCopy);
    774 
    775735    return VINF_SUCCESS;
    776736}
     
    788748
    789749    PVIRTIOSCSIREQ pReq = (PVIRTIOSCSIREQ)pvIoReqAlloc;
    790 
    791750    /** DrvSCSI.cpp, that issues this callback, just sticks one segment in the buffer */
    792751    memcpy(pSgBuf->paSegs[0].pvSeg, pReq->pbDataOut + offSrc, cbCopy);
     
    862821}
    863822
    864 /**
    865  * This is called to complete a request buffer immediately
    866  *
    867  * @param pThis     - PDM driver instance state
    868  * @param qIdx      - Queue index
    869  * @param rcReq     - VirtualBox code to map to VirtIO response code.
    870  *
    871  * @returns virtual box status code
    872  */
    873 static int virtioScsiReqFinish(PVIRTIOSCSI pThis, uint16_t qIdx, uint32_t rcReq)
    874 {
    875     struct REQ_RESP_HDR respHdr;
    876     respHdr.uSenseLen = 0;
    877     respHdr.uResidual = 0;
    878     respHdr.uStatusQualifier = 0;  /** TBD. Seems to be for iSCSI. Can't find any real info */
    879     respHdr.uStatus = 0;
    880     respHdr.uResponse = virtioScsiMapVerrToVirtio(rcReq);
    881     RTSGBUF reqSegBuf;
    882     RTSGSEG aReqSegs[] = { { &respHdr, sizeof(respHdr) } };
    883     RTSgBufInit(&reqSegBuf, aReqSegs, 1);
    884     virtioQueuePut(pThis->hVirtio, qIdx, &reqSegBuf, true /* fFence */);
    885     virtioQueueSync(pThis->hVirtio, qIdx);
    886     LogFunc(("Response code: %s\n", virtioGetReqRespText(respHdr.uResponse)));
    887     Log(("---------------------------------------------------------------------------------\n"));
    888     return VINF_SUCCESS;
    889 }
    890 
    891823static int virtioScsiReqFinish(PVIRTIOSCSI pThis, PVIRTIOSCSIREQ pReq, int rcReq)
    892824{
     
    907839
    908840    struct REQ_RESP_HDR respHdr;
    909     respHdr.uSenseLen = pReq->cbSense;
     841    respHdr.cbSense  = pReq->cbSense;
    910842    respHdr.uResidual = cbResidual;
    911     respHdr.uStatusQualifier = 0;  /** TBD. Seems to be iSCSI specific. Can't find any real info */
    912     respHdr.uStatus = pReq->uStatus;
    913     respHdr.uResponse = virtioScsiMapVerrToVirtio(rcReq);
    914 
     843    respHdr.uStatus   = pReq->uStatus;
     844    respHdr.uResponse = rcReq;
     845    respHdr.uStatusQualifier = 0;
    915846
    916847    LogFunc(("Status: %s (0x%x%x)      Response: %s (0x%x%x)\n",
     
    920851    if (pReq->cbSense)
    921852    {
     853    pReq->pbSense[12] = 0x25;
     854    pReq->pbSense[13] = 0x00;
    922855        Log2Func(("Sense: %s\n", SCSISenseText(pReq->pbSense[2])));
    923         Log2Func(("Sense Ext3: %s\n", SCSISenseExtText(pReq->pbSense[12], pReq->pbSense[12])));
    924         virtioScsiHexDump( pReq->pbSense, pReq->cbSense, 0, "\nSense");
     856        Log2Func(("Sense Ext3: %s\n", SCSISenseExtText(pReq->pbSense[12], pReq->pbSense[13])));
     857        virtioScsiHexDump(pReq->pbSense, pReq->cbSense, 0, "\nSense");
    925858    }
    926859
    927860    if (pReq->cbDataIn)
    928         virtioScsiHexDump( pReq->pbDataIn, pReq->cbDataIn, 0, "\ndatain");
     861        virtioScsiHexDump(pReq->pbDataIn, pReq->cbDataIn, 0, "\ndatain");
    929862
    930863    if (pReq->cbPiIn)
    931         virtioScsiHexDump( pReq->pbPiIn, pReq->cbPiIn, 0, "\nPi in");
     864        virtioScsiHexDump(pReq->pbPiIn, pReq->cbPiIn, 0, "\nPi in");
    932865
    933866    if (cbResidual)
     
    976909    RTMemFree(pReq->pbSense);
    977910    RTMemFree(pReq->pbDataIn);
     911    RTMemFree(pReq->pbPiIn);
    978912
    979913    pIMediaEx->pfnIoReqFree(pIMediaEx, pReq->hIoReq);
     
    986920
    987921/**
    988  * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
    989  */
    990 static DECLCALLBACK(int) virtioScsiR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
    991                                                        void *pvIoReqAlloc, int rcReq)
    992 {
    993     RT_NOREF(hIoReq);
    994     PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
    995     virtioScsiReqFinish(pTarget->CTX_SUFF(pVirtioScsi), (PVIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
     922 * This is called to complete a request immediately
     923 *
     924 * @param pThis     - PDM driver instance state
     925 * @param qIdx      - Queue index
     926 * @param respHdr   - Response header
     927 * @param pbSense   - Pointer to sense buffer or NULL if none.
     928 *
     929 * @returns virtual box status code
     930 */
     931static int virtioScsiReqFinish(PVIRTIOSCSI pThis, uint16_t qIdx, struct REQ_RESP_HDR *respHdr, uint8_t *pbSense)
     932{
     933    int cSegs = 0;
     934    RTSGSEG aReqSegs[2];
     935    aReqSegs[cSegs].pvSeg = &respHdr;
     936    aReqSegs[cSegs++].cbSeg = sizeof(respHdr);
     937    if (respHdr->cbSense)
     938    {
     939        aReqSegs[cSegs].pvSeg = pbSense;
     940        aReqSegs[cSegs++].cbSeg = respHdr->cbSense;
     941    }
     942    RTSGBUF reqSegBuf;
     943    RTSgBufInit(&reqSegBuf, aReqSegs, cSegs);
     944    virtioQueuePut(pThis->hVirtio, qIdx, &reqSegBuf, true /* fFence */);
     945    virtioQueueSync(pThis->hVirtio, qIdx);
     946    LogFunc(("Response code: %s\n", virtioGetReqRespText(respHdr->uResponse)));
     947    Log(("---------------------------------------------------------------------------------\n"));
    996948    return VINF_SUCCESS;
    997949}
     
    1011963    size_t cbRespHdr = sizeof(REQ_RESP_HDR);
    1012964
     965
    1013966    AssertMsgReturn(cbOut >= RT_SIZEOFMEMB(VIRTIOSCSI_REQ_CMD_T, cmdHdr), ("Req to short"), VERR_BUFFER_UNDERFLOW);
    1014967
     
    1017970        cbCdb -= (cbCmdHdr - cbOut);
    1018971
    1019     /**
    1020      * For the time being, assume one descriptor chain has the complete req data to write to device,
    1021      * and that it's not too much to shove into virtual memory at once
    1022      */
    1023972    PVIRTIOSCSI_REQ_CMD_T pVirtqReq = (PVIRTIOSCSI_REQ_CMD_T)RTMemAllocZ(cbOut);
    1024973    off_t  cbOff = 0;
     
    1037986    uint32_t uLUN = (pVirtqReq->cmdHdr.uLUN[2] << 8 | pVirtqReq->cmdHdr.uLUN[3]) & 0x3fff;
    1038987
    1039     LogFunc(("[%s]  (Target: %d LUN: %d)  CDB: %.*Rhxs\n",
     988    LogFunc(("[%s]%*s (Target: %d LUN: %d)  CDB: %.*Rhxs\n",
    1040989         SCSICmdText(pbCdb[0]), uTarget, uLUN,
    1041990            virtioScsiEstimateCdbLen(pbCdb[0], pThis->virtioScsiConfig.uCdbSize), pbCdb));
     
    1044993        pVirtqReq->cmdHdr.uId, pVirtqReq->cmdHdr.uTaskAttr, pVirtqReq->cmdHdr.uPrio, pVirtqReq->cmdHdr.uCrn));
    1045994
    1046     if (uTarget >= pThis->cTargets)
    1047     {
    1048         virtioScsiReqFinish(pThis, qIdx, VERR_IO_BAD_UNIT);
    1049         return VINF_SUCCESS;
    1050     }
    1051     if (uLUN != 0)
    1052     {
    1053         virtioScsiReqFinish(pThis, qIdx, VERR_IO_BAD_UNIT);
    1054         return VINF_SUCCESS;
    1055     }
    1056995
    1057996    off_t    uPiOutOff = 0;
     
    10781017
    10791018    if (cbDataOut)
    1080         virtioScsiHexDump( pVirtqReq->uDataOut, cbDataOut, 0, "\ndataout");
     1019        virtioScsiHexDump(pVirtqReq->uDataOut, cbDataOut, 0, "\ndataout");
    10811020
    10821021
     
    10901029
    10911030    size_t cbDataIn  = cbIn - (cbRespHdr + cbSense + cbPiIn);
     1031
     1032    if (uTarget >= pThis->cTargets)
     1033    {
     1034        struct REQ_RESP_HDR respHdr;
     1035        respHdr.cbSense = 0;
     1036        respHdr.uResidual = cbDataOut + cbDataIn;
     1037        respHdr.uStatus = SCSI_STATUS_OK;
     1038        respHdr.uResponse = VIRTIOSCSI_S_BAD_TARGET;
     1039        respHdr.uStatusQualifier = 0;
     1040        virtioScsiReqFinish(pThis, qIdx, &respHdr, NULL /* pbSense */);
     1041        return VINF_SUCCESS;
     1042    }
     1043
     1044    struct REQ_RESP_HDR respHdr = { 0 };
     1045    if (uLUN != 0)
     1046    {
     1047        /**
     1048         * This is needed for the time being to respond with the right error condition and sense data
     1049         * at the right time.  It doesn't work to send requests to bad luns down to DrvSCSI. It returs
     1050         * success for the INQUIRY commands and then starts failing future requests with BAD PARAM errors.
     1051         * Unfortunately that's too late for Linux. If it doesn't get the bad lun error at inquiry it
     1052         * seems to mishandle the error on future requests and will create 8 devices for the target and
     1053         * it gets ugly. */
     1054
     1055        uint8_t pbSense[] = { RT_BIT(7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED, 0, SCSI_SENSE_ILLEGAL_REQUEST,
     1056                              0, 0, 0, 0, 10, SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 0, 0 };
     1057        respHdr.cbSense = sizeof(pbSense);
     1058        respHdr.uResidual = cbDataIn + cbDataOut;
     1059        respHdr.uStatus   = SCSI_STATUS_CHECK_CONDITION;
     1060        respHdr.uResponse = VIRTIOSCSI_S_OK;
     1061        respHdr.uStatusQualifier = 0;
     1062        virtioScsiReqFinish(pThis, qIdx, &respHdr, pbSense);
     1063        return VINF_SUCCESS;
     1064    }
    10921065
    10931066    if (RT_LIKELY(pTarget->fPresent))
     
    11361109        if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
    11371110        {
    1138             pIMediaEx->pfnIoReqFree(pIMediaEx, hIoReq);
    1139             virtioScsiReqFinish(pThis, qIdx, rc);
     1111            size_t cbResidual;
     1112            pIMediaEx->pfnIoReqQueryResidual(pIMediaEx, pReq->hIoReq, &cbResidual);
     1113            respHdr.cbSense = 0;
     1114            respHdr.uResidual = (uint32_t)cbResidual;
     1115            respHdr.uStatus   = SCSI_STATUS_OK;
     1116            respHdr.uResponse = VIRTIOSCSI_S_OK;
     1117            respHdr.uStatusQualifier = 0;
     1118            virtioScsiReqFinish(pThis, qIdx, &respHdr,  NULL /* pbSense */);
    11401119            return VINF_SUCCESS;
    11411120        }
    11421121    } else {
    1143         virtioScsiReqFinish(pThis, qIdx, VERR_IO_NOT_READY);
     1122        respHdr.cbSense = 0;
     1123        respHdr.uResidual = cbDataOut + cbDataIn;
     1124        respHdr.uStatus   = SCSI_STATUS_OK;
     1125        respHdr.uResponse = VIRTIOSCSI_S_TARGET_FAILURE;
     1126        respHdr.uStatusQualifier = 0;
     1127        virtioScsiReqFinish(pThis, qIdx, &respHdr, NULL /* pbSense */);
    11441128        return VINF_SUCCESS;
    11451129
    11461130    }
    11471131
     1132    return VINF_SUCCESS;
     1133}
     1134
     1135/**
     1136 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
     1137 */
     1138static DECLCALLBACK(int) virtioScsiR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
     1139                                                       void *pvIoReqAlloc, int rcReq)
     1140{
     1141    RT_NOREF(hIoReq);
     1142    PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
     1143    virtioScsiReqFinish(pTarget->CTX_SUFF(pVirtioScsi), (PVIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
    11481144    return VINF_SUCCESS;
    11491145}
     
    12441240            virtioGetControlAsyncMaskText(szTypeText, sizeof(szTypeText), pScsiCtrlAnQuery->uEventsRequested);
    12451241
    1246             Log2Func(("%s, VirtIO LUN: %.8Rhxs\n%*sAsync Query, types: %s\n",
     1242            Log3Func(("%s, VirtIO LUN: %.8Rhxs\n%*sAsync Query, types: %s\n",
    12471243                QUEUENAME(qIdx), pScsiCtrlAnQuery->uLUN, CBQUEUENAME(qIdx) + 30, "", szTypeText));
    12481244
     
    12651261            virtioGetControlAsyncMaskText(szTypeText, sizeof(szTypeText), pScsiCtrlAnSubscribe->uEventsRequested);
    12661262
    1267             Log2Func(("%s, VirtIO LUN: %.8Rhxs\n%*sAsync Subscribe, types: %s\n",
     1263            Log3Func(("%s, VirtIO LUN: %.8Rhxs\n%*sAsync Subscribe, types: %s\n",
    12681264                QUEUENAME(qIdx), pScsiCtrlAnSubscribe->uLUN, CBQUEUENAME(qIdx) + 30, "", szTypeText));
    12691265
     
    13521348        if (rc == VERR_NOT_AVAILABLE)
    13531349        {
    1354             Log2Func(("Nothing found in %s\n", QUEUENAME(qIdx)));
     1350            Log3Func(("Nothing found in %s\n", QUEUENAME(qIdx)));
    13551351            continue;
    13561352        }
     
    13601356            virtioScsiCtrl(pThis, qIdx, pInSgBuf, pOutSgBuf);
    13611357        else
    1362             virtioScsiReqSubmit(pThis, qIdx, pInSgBuf, pOutSgBuf);
     1358        {
     1359            rc = virtioScsiReqSubmit(pThis, qIdx, pInSgBuf, pOutSgBuf);
     1360            if (RT_FAILURE(rc))
     1361            {
     1362                LogRel(("Fatal error submitting req packet, resetting %Rrc", rc));
     1363                /** TBD: MUST AT LEAD RETURN VIRTIO_SCSI_S_FAILURE for all pending I/O, Aborting is an option! */
     1364                virtioResetAll(pThis->hVirtio);
     1365            }
     1366        }
    13631367    }
    13641368    return VINF_SUCCESS;
     
    15981602    if (fVirtioReady)
    15991603    {
    1600         LogFunc(("VirtIO ready\n---------------------------------------------------------------------------------"));
     1604        LogFunc(("VirtIO ready\n---------------------------------------------------------------------------------\n"));
    16011605        uint64_t features = virtioGetNegotiatedFeatures(hVirtio);
    16021606        pThis->fHasT10pi     = features & VIRTIO_SCSI_F_T10_PI;
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r80522 r80527  
    638638            Log3Func(("Guest wrote uDeviceStatus ................ ("));
    639639            virtioLogDeviceStatus(pVirtio->uDeviceStatus);
    640             Log((")\n"));
     640            Log3((")\n"));
    641641            if (pVirtio->uDeviceStatus == 0)
    642642                virtioGuestResetted(pVirtio);
     
    656656            *(uint32_t *)pv = pVirtio->uDeviceStatus;
    657657            virtioLogDeviceStatus(pVirtio->uDeviceStatus);
    658             Log((")\n"));
     658            Log3((")\n"));
    659659        }
    660660    }
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80522 r80527  
    512512{
    513513    if (status == 0)
    514         Log(("RESET"));
     514        Log3(("RESET"));
    515515    else
    516516    {
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