VirtualBox

Changeset 89266 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
May 25, 2021 11:10:45 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
144609
Message:

Devices/DevBusLogic: Implement support for the EXECUTE SCSI command which will be used by the BIOS to not interfer with other drivers accessing the controller through the mailbox interface, bugref:4841

File:
1 edited

Legend:

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

    r89197 r89266  
    336336    volatile uint8_t                regGeometry;
    337337    /** Pending (delayed) interrupt. */
    338     uint8_t                         uPendingIntr;
     338    volatile uint8_t                uPendingIntr;
    339339
    340340    /** Command code the guest issued. */
     
    395395    /** Whether a notification to R3 was sent. */
    396396    volatile bool                   fNotificationSent;
     397    /** Flag whether a BIOS request is pending. */
     398    volatile bool                   fBiosReqPending;
    397399
    398400    /** Whether strict round robin is enabled. */
     
    996998} BUSLOGICREQ;
    997999
     1000/**
     1001 * S/G buffer copy arguments.
     1002 */
     1003typedef struct BUSLOGICCOPYARGS
     1004{
     1005    /** Pointer to the shared BusLogic instance data. */
     1006    PBUSLOGIC                       pThis;
     1007    /** Pointer to the device instance data. */
     1008    PPDMDEVINS                      pDevIns;
     1009    /** Pointer to the SCSI command buffer. */
     1010    PESCMD                          pCmd;
     1011    /** Number of bytes copied already. */
     1012    size_t                          cbCopied;
     1013} BUSLOGICCOPYARGS;
     1014/** Pointer to BUSLOGICCOPYARGS. */
     1015typedef BUSLOGICCOPYARGS *PBUSLOGICCOPYARGS;
     1016
    9981017#ifdef IN_RING3
    9991018/**
     
    18851904    bool fSuppressIrq = false;
    18861905    bool fSuppressCMDC = false;
     1906    bool fCmdComplete  = true;
    18871907
    18881908    LogFlowFunc(("pThis=%#p\n", pThis));
     
    20212041                /* Second pass - process received data. */
    20222042                Log(("Execute SCSI cmd: received %u bytes\n", pThis->aCommandBuffer[0]));
    2023 
    20242043                pCmd = (PESCMD)pThis->aCommandBuffer;
    20252044                Log(("Addr %08X, cbData %08X, cbCDB=%u\n", pCmd->u32PhysAddrData, pCmd->cbData, pCmd->cbCDB));
     2045
     2046                if (!ASMAtomicXchgBool(&pThis->fBiosReqPending, true))
     2047                {
     2048                    /* Wake up the worker thread. */
     2049                    int rc2 = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
     2050                    AssertRC(rc2);
     2051                }
     2052
     2053                fCmdComplete = false;
    20262054            }
    2027             // This is currently a dummy - just fails every command.
    2028             pThis->cbReplyParametersLeft = 4;
    2029             pThis->aReplyBuffer[0] = pThis->aReplyBuffer[1] = 0;
    2030             pThis->aReplyBuffer[2] = 0x11;      /* HBA status (timeout). */
    2031             pThis->aReplyBuffer[3] = 0;         /* Device status. */
    20322055            break;
    20332056
     
    24242447    }
    24252448
    2426     /* Set the data in ready bit in the status register in case the command has a reply. */
    2427     if (pThis->cbReplyParametersLeft)
    2428         pThis->regStatus |= BL_STAT_DIRRDY;
    2429     else if (!pThis->cbCommandParametersLeft)
    2430         buslogicCommandComplete(pDevIns, pThis, fSuppressIrq, fSuppressCMDC);
     2449    if (fCmdComplete)
     2450    {
     2451        /* Set the data in ready bit in the status register in case the command has a reply. */
     2452        if (pThis->cbReplyParametersLeft)
     2453            pThis->regStatus |= BL_STAT_DIRRDY;
     2454        else if (!pThis->cbCommandParametersLeft)
     2455            buslogicCommandComplete(pDevIns, pThis, fSuppressIrq, fSuppressCMDC);
     2456    }
    24312457
    24322458    return rc;
     
    28752901}
    28762902
     2903/**
     2904 * Completes a request initiated by the BIOS through the BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND command.
     2905 *
     2906 * @returns nothing.
     2907 * @param   pThis       Pointer to the shared BusLogic instance data.
     2908 * @param   u8ScsiSts   The SCSI status code.
     2909 */
     2910static void buslogicR3ReqCompleteBios(PBUSLOGIC pThis, uint8_t u8ScsiSts)
     2911{
     2912    pThis->cbReplyParametersLeft = 4;
     2913    pThis->aReplyBuffer[0] = pThis->aReplyBuffer[1] = 0;
     2914    pThis->aReplyBuffer[2] = u8ScsiSts;
     2915    pThis->aReplyBuffer[3] = 0;
     2916
     2917    pThis->regStatus |= BL_STAT_DIRRDY;
     2918}
    28772919
    28782920static int buslogicR3ReqComplete(PPDMDEVINS pDevIns, PBUSLOGIC pThis, PBUSLOGICCC pThisCC, PBUSLOGICREQ pReq, int rcReq)
     
    28852927    LogFlowFunc(("after decrement %u\n", pTgtDev->cOutstandingRequests));
    28862928
    2887     if (pReq->pbSenseBuffer)
    2888         buslogicR3SenseBufferFree(pReq, (pReq->u8ScsiSts != SCSI_STATUS_OK));
    2889 
    2890     /* Update residual data length. */
    2891     if (   (pReq->CCBGuest.c.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
    2892         || (pReq->CCBGuest.c.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
    2893     {
    2894         size_t cbResidual = 0;
    2895         int rc = pTgtDev->pDrvMediaEx->pfnIoReqQueryResidual(pTgtDev->pDrvMediaEx, pReq->hIoReq, &cbResidual);
    2896         AssertRC(rc); Assert(cbResidual == (uint32_t)cbResidual);
    2897 
    2898         if (pReq->fIs24Bit)
    2899             U32_TO_LEN(pReq->CCBGuest.o.acbData, (uint32_t)cbResidual);
     2929    if (pReq->fBIOS)
     2930    {
     2931        uint8_t u8ScsiSts = pReq->u8ScsiSts;
     2932        pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
     2933        buslogicR3ReqCompleteBios(pThis, u8ScsiSts);
     2934    }
     2935    else
     2936    {
     2937        if (pReq->pbSenseBuffer)
     2938            buslogicR3SenseBufferFree(pReq, (pReq->u8ScsiSts != SCSI_STATUS_OK));
     2939
     2940        /* Update residual data length. */
     2941        if (   (pReq->CCBGuest.c.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
     2942            || (pReq->CCBGuest.c.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
     2943        {
     2944            size_t cbResidual = 0;
     2945            int rc = pTgtDev->pDrvMediaEx->pfnIoReqQueryResidual(pTgtDev->pDrvMediaEx, pReq->hIoReq, &cbResidual);
     2946            AssertRC(rc); Assert(cbResidual == (uint32_t)cbResidual);
     2947
     2948            if (pReq->fIs24Bit)
     2949                U32_TO_LEN(pReq->CCBGuest.o.acbData, (uint32_t)cbResidual);
     2950            else
     2951                pReq->CCBGuest.n.cbData = (uint32_t)cbResidual;
     2952        }
     2953
     2954        /*
     2955         * Save vital things from the request and free it before posting completion
     2956         * to avoid that the guest submits a new request with the same ID as the still
     2957         * allocated one.
     2958         */
     2959#ifdef LOG_ENABLED
     2960        bool fIs24Bit = pReq->fIs24Bit;
     2961#endif
     2962        uint8_t u8ScsiSts = pReq->u8ScsiSts;
     2963        RTGCPHYS GCPhysAddrCCB = pReq->GCPhysAddrCCB;
     2964        CCBU CCBGuest;
     2965        memcpy(&CCBGuest, &pReq->CCBGuest, sizeof(CCBU));
     2966
     2967        pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
     2968        if (u8ScsiSts == SCSI_STATUS_OK)
     2969            buslogicR3SendIncomingMailbox(pDevIns, pThis, GCPhysAddrCCB, &CCBGuest,
     2970                                          BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED,
     2971                                          BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_OPERATION_GOOD,
     2972                                          BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITHOUT_ERROR);
     2973        else if (u8ScsiSts == SCSI_STATUS_CHECK_CONDITION)
     2974            buslogicR3SendIncomingMailbox(pDevIns, pThis, GCPhysAddrCCB, &CCBGuest,
     2975                                          BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED,
     2976                                          BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_CHECK_CONDITION,
     2977                                          BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITH_ERROR);
    29002978        else
    2901             pReq->CCBGuest.n.cbData = (uint32_t)cbResidual;
    2902     }
    2903 
    2904     /*
    2905      * Save vital things from the request and free it before posting completion
    2906      * to avoid that the guest submits a new request with the same ID as the still
    2907      * allocated one.
    2908      */
     2979            AssertMsgFailed(("invalid completion status %u\n", u8ScsiSts));
     2980
    29092981#ifdef LOG_ENABLED
    2910     bool fIs24Bit = pReq->fIs24Bit;
     2982        buslogicR3DumpCCBInfo(&CCBGuest, fIs24Bit);
    29112983#endif
    2912     uint8_t u8ScsiSts = pReq->u8ScsiSts;
    2913     RTGCPHYS GCPhysAddrCCB = pReq->GCPhysAddrCCB;
    2914     CCBU CCBGuest;
    2915     memcpy(&CCBGuest, &pReq->CCBGuest, sizeof(CCBU));
    2916 
    2917     pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
    2918     if (u8ScsiSts == SCSI_STATUS_OK)
    2919         buslogicR3SendIncomingMailbox(pDevIns, pThis, GCPhysAddrCCB, &CCBGuest,
    2920                                       BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED,
    2921                                       BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_OPERATION_GOOD,
    2922                                       BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITHOUT_ERROR);
    2923     else if (u8ScsiSts == SCSI_STATUS_CHECK_CONDITION)
    2924         buslogicR3SendIncomingMailbox(pDevIns, pThis, GCPhysAddrCCB, &CCBGuest,
    2925                                       BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED,
    2926                                       BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_CHECK_CONDITION,
    2927                                       BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITH_ERROR);
    2928     else
    2929         AssertMsgFailed(("invalid completion status %u\n", u8ScsiSts));
    2930 
    2931 #ifdef LOG_ENABLED
    2932     buslogicR3DumpCCBInfo(&CCBGuest, fIs24Bit);
    2933 #endif
     2984    }
    29342985
    29352986    if (pTgtDev->cOutstandingRequests == 0 && pThisCC->fSignalIdle)
     
    29573008
    29583009    return VINF_SUCCESS;
     3010}
     3011
     3012static DECLCALLBACK(size_t) buslogicR3CopySgToGuestBios(PCRTSGBUF pSgBuf, const void *pvSrc, size_t cbSrc, void *pvUser)
     3013{
     3014    PBUSLOGICCOPYARGS pArgs = (PBUSLOGICCOPYARGS)pvUser;
     3015    size_t cbThisCopy = RT_MIN(cbSrc, pArgs->pCmd->cbData - pArgs->cbCopied);
     3016    RT_NOREF(pSgBuf);
     3017
     3018    blPhysWriteUser(pArgs->pDevIns, pArgs->pThis, pArgs->pCmd->u32PhysAddrData + pArgs->cbCopied, pvSrc, cbThisCopy);
     3019    pArgs->cbCopied += cbThisCopy;
     3020    return cbThisCopy;
    29593021}
    29603022
     
    29713033    RT_NOREF(hIoReq);
    29723034
    2973     size_t cbCopied = buslogicR3CopySgBufToGuest(pDevIns, PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC), pReq, pSgBuf, offDst, cbCopy);
     3035    size_t cbCopied = 0;
     3036    if (RT_LIKELY(!pReq->fBIOS))
     3037        cbCopied = buslogicR3CopySgBufToGuest(pDevIns, PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC), pReq, pSgBuf, offDst, cbCopy);
     3038    else
     3039    {
     3040        BUSLOGICCOPYARGS Args;
     3041        PBUSLOGIC pThis = PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC);
     3042        PESCMD pCmd = (PESCMD)pThis->aCommandBuffer;
     3043
     3044        Args.pCmd     = pCmd;
     3045        Args.pThis    = pThis;
     3046        Args.pDevIns  = pDevIns;
     3047        Args.cbCopied = 0;
     3048        cbCopied = RTSgBufCopyToFn(pSgBuf, RT_MIN(pCmd->cbData, cbCopy), buslogicR3CopySgToGuestBios, &Args);
     3049    }
    29743050    return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
     3051}
     3052
     3053static DECLCALLBACK(size_t) buslogicR3CopySgFromGuestBios(PCRTSGBUF pSgBuf, void *pvDst, size_t cbDst, void *pvUser)
     3054{
     3055    PBUSLOGICCOPYARGS pArgs = (PBUSLOGICCOPYARGS)pvUser;
     3056    size_t cbThisCopy = RT_MIN(cbDst, pArgs->pCmd->cbData - pArgs->cbCopied);
     3057    RT_NOREF(pSgBuf);
     3058
     3059    blPhysReadUser(pArgs->pDevIns, pArgs->pThis, pArgs->pCmd->u32PhysAddrData + pArgs->cbCopied, pvDst, cbThisCopy);
     3060    pArgs->cbCopied += cbThisCopy;
     3061    return cbThisCopy;
    29753062}
    29763063
     
    29873074    PBUSLOGICREQ    pReq    = (PBUSLOGICREQ)pvIoReqAlloc;
    29883075
    2989     size_t cbCopied = buslogicR3CopySgBufFromGuest(pDevIns, PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC), pReq, pSgBuf, offSrc, cbCopy);
     3076    size_t cbCopied = 0;
     3077    if (RT_LIKELY(!pReq->fBIOS))
     3078        cbCopied = buslogicR3CopySgBufFromGuest(pDevIns, PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC), pReq, pSgBuf, offSrc, cbCopy);
     3079    else
     3080    {
     3081        BUSLOGICCOPYARGS Args;
     3082        PBUSLOGIC pThis = PDMDEVINS_2_DATA(pDevIns, PBUSLOGIC);
     3083        PESCMD pCmd = (PESCMD)pThis->aCommandBuffer;
     3084
     3085        Args.pCmd     = pCmd;
     3086        Args.pThis    = pThis;
     3087        Args.pDevIns  = pDevIns;
     3088        Args.cbCopied = 0;
     3089        cbCopied = RTSgBufCopyFromFn(pSgBuf, RT_MIN(pCmd->cbData, cbCopy), buslogicR3CopySgFromGuestBios, &Args);
     3090    }
     3091
    29903092    return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
    29913093}
     
    32693371    return rc;
    32703372}
     3373
     3374/**
     3375 * Processes a SCSI request issued by the BIOS with the BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND command.
     3376 *
     3377 * @returns nothing.
     3378 * @param   pDevIns     The device instance.
     3379 * @param   pThis       Pointer to the shared BusLogic instance data.
     3380 * @param   pThisCC     Pointer to the ring-3 BusLogic instance data.
     3381 */
     3382static void buslogicR3ProcessBiosReq(PPDMDEVINS pDevIns, PBUSLOGIC pThis, PBUSLOGICCC pThisCC)
     3383{
     3384    PESCMD pCmd = (PESCMD)pThis->aCommandBuffer;
     3385
     3386    if (RT_LIKELY(   pCmd->uTargetId < RT_ELEMENTS(pThisCC->aDeviceStates)
     3387                  && pCmd->cbCDB <= 16))
     3388    {
     3389        PBUSLOGICDEVICE pTgtDev = &pThisCC->aDeviceStates[pCmd->uTargetId];
     3390
     3391        /* Check if device is present on bus. If not return error immediately and don't process this further. */
     3392        if (RT_LIKELY(pTgtDev->fPresent))
     3393        {
     3394            PDMMEDIAEXIOREQ hIoReq;
     3395            PBUSLOGICREQ pReq;
     3396            int rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pReq,
     3397                                                         0, PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
     3398            if (RT_SUCCESS(rc))
     3399            {
     3400                pReq->pTargetDevice = pTgtDev;
     3401                pReq->GCPhysAddrCCB = 0;
     3402                pReq->fBIOS         = true;
     3403                pReq->hIoReq        = hIoReq;
     3404                pReq->fIs24Bit      = false;
     3405
     3406                uint32_t uLun = pCmd->uLogicalUnit;
     3407
     3408                PDMMEDIAEXIOREQSCSITXDIR enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN;
     3409
     3410                if (pCmd->uDataDirection == 2)
     3411                    enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE;
     3412                else if (pCmd->uDataDirection == 1)
     3413                    enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
     3414
     3415                ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
     3416                rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pReq->hIoReq, uLun,
     3417                                                               &pCmd->abCDB[0], pCmd->cbCDB,
     3418                                                               enmXferDir, NULL, pCmd->cbData, NULL, 0 /*cbSense*/, NULL,
     3419                                                               &pReq->u8ScsiSts, 30 * RT_MS_1SEC);
     3420                if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
     3421                    buslogicR3ReqComplete(pDevIns, pThis, pThisCC, pReq, rc);
     3422            }
     3423            else
     3424                buslogicR3ReqCompleteBios(pThis, SCSI_STATUS_CHECK_CONDITION);
     3425        }
     3426        else
     3427            buslogicR3ReqCompleteBios(pThis, SCSI_STATUS_CHECK_CONDITION);
     3428    }
     3429    else
     3430        buslogicR3ReqCompleteBios(pThis, SCSI_STATUS_CHECK_CONDITION);
     3431}
     3432
    32713433
    32723434/** @callback_method_impl{FNSSMDEVLIVEEXEC}  */
     
    36023764        ASMAtomicWriteBool(&pThisCC->fWrkThreadSleeping, false);
    36033765
    3604 
    3605         ASMAtomicXchgU32(&pThis->cMailboxesReady, 0); /** @todo Actually not required anymore but to stay compatible with older saved states. */
    3606 
    3607         /* Process mailboxes. */
    3608         do
    3609         {
    3610             rc = buslogicR3ProcessMailboxNext(pDevIns, pThis, pThisCC);
    3611             AssertMsg(RT_SUCCESS(rc) || rc == VERR_NO_DATA, ("Processing mailbox failed rc=%Rrc\n", rc));
    3612         } while (RT_SUCCESS(rc));
     3766        if (ASMAtomicXchgBool(&pThis->fBiosReqPending, false))
     3767            buslogicR3ProcessBiosReq(pDevIns, pThis, pThisCC);
     3768
     3769        if (ASMAtomicXchgU32(&pThis->cMailboxesReady, 0))
     3770        {
     3771            /* Process mailboxes. */
     3772            do
     3773            {
     3774                rc = buslogicR3ProcessMailboxNext(pDevIns, pThis, pThisCC);
     3775                AssertMsg(RT_SUCCESS(rc) || rc == VERR_NO_DATA, ("Processing mailbox failed rc=%Rrc\n", rc));
     3776            } while (RT_SUCCESS(rc));
     3777        }
    36133778    } /* While running */
    36143779
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