VirtualBox

Changeset 32069 in vbox for trunk/src


Ignore:
Timestamp:
Aug 29, 2010 3:54:53 PM (14 years ago)
Author:
vboxsync
Message:

AHCI: Support for CD/DVD devices (inclusive passthrough and runtime media changes)

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

Legend:

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

    r31087 r32069  
    100100#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH    4
    101101
     102/* MediaEventStatus */
     103#define ATA_EVENT_STATUS_UNCHANGED              0    /**< medium event status not changed */
     104#define ATA_EVENT_STATUS_MEDIA_NEW              1    /**< new medium inserted */
     105#define ATA_EVENT_STATUS_MEDIA_REMOVED          2    /**< medium removed */
     106#define ATA_EVENT_STATUS_MEDIA_CHANGED          3    /**< medium was removed + new medium was inserted */
     107#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED  4    /**< medium eject requested (eject button pressed) */
     108
     109/** ATAPI sense info size. */
     110#define ATAPI_SENSE_SIZE 64
     111
    102112/* Command Header. */
    103113typedef struct
     
    253263    /** The ATAPI comnmand data. */
    254264    uint8_t                    aATAPICmd[ATAPI_PACKET_SIZE];
     265    /** Size of one sector for the ATAPI transfer. */
     266    size_t                     cbATAPISector;
    255267    /** Physical address of the command header. - GC */
    256268    RTGCPHYS                   GCPhysCmdHdrAddr;
     
    402414    /** Attached device is a CD/DVD drive. */
    403415    bool                            fATAPI;
    404 
    405 #if HC_ARCH_BITS == 64
    406     uint32_t                        Alignment3;
    407 #endif
     416    /** Passthrough SCSI commands. */
     417    bool                            fATAPIPassthrough;
    408418
    409419    /** Device specific settings. */
     
    441451    /** Currently active transfer mode (MDMA/UDMA) and speed. */
    442452    uint8_t                         uATATransferMode;
    443     /** ATAPI sense key. */
    444     uint8_t                         uATAPISenseKey;
    445     /** ATAPI additional sens code. */
    446     uint8_t                         uATAPIASC;
     453    /** ATAPI sense data. */
     454    uint8_t                         abATAPISense[ATAPI_SENSE_SIZE];
    447455    /** HACK: Countdown till we report a newly unmounted drive as mounted. */
    448456    uint8_t                         cNotifiedMediaChange;
     457    /** The same for GET_EVENT_STATUS for mechanism */
     458    volatile uint32_t               MediaEventStatus;
    449459
    450460    /** The LUN. */
     
    457467    /** Bitmask for finished queued tasks. */
    458468    volatile uint32_t               u32QueuedTasksFinished;
     469
     470    uint32_t                        u32Alignment6;
    459471
    460472    /**
     
    27172729        | ((pAhciPortTaskState->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
    27182730        | (!pAhciPortTaskState->cbTransfer ? ATAPI_INT_REASON_CD : 0);
    2719     pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
    2720     pAhciPort->uATAPIASC = SCSI_ASC_NONE;
    2721 }
    2722 
    2723 
    2724 static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
    2725 {
    2726     pAhciPortTaskState->uATARegError = uATAPISenseKey << 4;
     2731    memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
     2732    pAhciPort->abATAPISense[0] = 0x70;
     2733    pAhciPort->abATAPISense[7] = 10;
     2734}
     2735
     2736static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, const uint8_t *pabATAPISense, size_t cbATAPISense)
     2737{
     2738    Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
     2739             pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
     2740    pAhciPortTaskState->uATARegError = pabATAPISense[2] << 4;
    27272741    pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
    27282742    pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
    27292743                                                     ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
    2730     pAhciPort->uATAPISenseKey = uATAPISenseKey;
    2731     pAhciPort->uATAPIASC = uATAPIASC;
     2744    memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
     2745    memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
     2746}
     2747
     2748/** @todo deprecated function - doesn't provide enough info. Replace by direct
     2749 * calls to atapiCmdError()  with full data. */
     2750static void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
     2751{
     2752    uint8_t abATAPISense[ATAPI_SENSE_SIZE];
     2753    memset(abATAPISense, '\0', sizeof(abATAPISense));
     2754    abATAPISense[0] = 0x70 | (1 << 7);
     2755    abATAPISense[2] = uATAPISenseKey & 0x0f;
     2756    abATAPISense[7] = 10;
     2757    abATAPISense[12] = uATAPIASC;
     2758    atapiCmdError(pAhciPort, pAhciPortTaskState, abATAPISense, sizeof(abATAPISense));
    27322759}
    27332760
     
    28312858
    28322859static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
     2860static int atapiGetEventStatusNotificationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
    28332861static int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
    28342862static int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
     
    28432871static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
    28442872static int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
    2845 //static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
     2873static int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
    28462874
    28472875/**
     
    28522880    ATAFN_SS_NULL = 0,
    28532881    ATAFN_SS_ATAPI_GET_CONFIGURATION,
     2882    ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION,
    28542883    ATAFN_SS_ATAPI_IDENTIFY,
    28552884    ATAFN_SS_ATAPI_INQUIRY,
     
    28642893    ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
    28652894    ATAFN_SS_ATAPI_REQUEST_SENSE,
    2866     //ATAFN_SS_ATAPI_PASSTHROUGH,
     2895    ATAFN_SS_ATAPI_PASSTHROUGH,
    28672896    ATAFN_SS_MAX
    28682897} ATAPIFN;
     
    28762905    NULL,
    28772906    atapiGetConfigurationSS,
     2907    atapiGetEventStatusNotificationSS,
    28782908    atapiIdentifySS,
    28792909    atapiInquirySS,
     
    28872917    atapiReadTOCRawSS,
    28882918    atapiReadTrackInformationSS,
    2889     atapiRequestSenseSS
    2890     //atapiPassthroughSS
     2919    atapiRequestSenseSS,
     2920    atapiPassthroughSS
    28912921};
    28922922
     
    29162946    p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
    29172947    p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
    2918     p[75] = RT_H2LE_U16(1); /* queue depth 1 */
    29192948    p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
    29202949    p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
     
    29883017    if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
    29893018    {
    2990         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3019        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    29913020        return VINF_SUCCESS;
    29923021    }
     
    30183047    if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
    30193048    {
    3020         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3049        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    30213050        return VINF_SUCCESS;
    30223051    }
     
    30403069    /* Copy the buffer in to the scatter gather list. */
    30413070    *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
     3071
     3072    atapiCmdOK(pAhciPort, pAhciPortTaskState);
     3073    return VINF_SUCCESS;
     3074}
     3075
     3076
     3077static int atapiGetEventStatusNotificationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
     3078{
     3079    uint8_t abBuf[8];
     3080
     3081    Assert(pAhciPortTaskState->enmTxDir == AHCITXDIR_READ);
     3082    Assert(pAhciPortTaskState->cbTransfer <= 8);
     3083
     3084    if (!(pAhciPortTaskState->aATAPICmd[1] & 1))
     3085    {
     3086        /* no asynchronous operation supported */
     3087        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3088        return VINF_SUCCESS;
     3089    }
     3090
     3091    uint32_t OldStatus, NewStatus;
     3092    do
     3093    {
     3094        OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
     3095        NewStatus = ATA_EVENT_STATUS_UNCHANGED;
     3096        switch (OldStatus)
     3097        {
     3098            case ATA_EVENT_STATUS_MEDIA_NEW:
     3099                /* mount */
     3100                ataH2BE_U16(abBuf + 0, 6);
     3101                abBuf[2] = 0x04; /* media */
     3102                abBuf[3] = 0x5e; /* suppored = busy|media|external|power|operational */
     3103                abBuf[4] = 0x02; /* new medium */
     3104                abBuf[5] = 0x02; /* medium present / door closed */
     3105                abBuf[6] = 0x00;
     3106                abBuf[7] = 0x00;
     3107                break;
     3108
     3109            case ATA_EVENT_STATUS_MEDIA_CHANGED:
     3110            case ATA_EVENT_STATUS_MEDIA_REMOVED:
     3111                /* umount */
     3112                ataH2BE_U16(abBuf + 0, 6);
     3113                abBuf[2] = 0x04; /* media */
     3114                abBuf[3] = 0x5e; /* suppored = busy|media|external|power|operational */
     3115                abBuf[4] = 0x03; /* media removal */
     3116                abBuf[5] = 0x00; /* medium absent / door closed */
     3117                abBuf[6] = 0x00;
     3118                abBuf[7] = 0x00;
     3119                if (OldStatus == ATA_EVENT_STATUS_MEDIA_CHANGED)
     3120                    NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
     3121                break;
     3122
     3123            case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
     3124                ataH2BE_U16(abBuf + 0, 6);
     3125                abBuf[2] = 0x04; /* media */
     3126                abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
     3127                abBuf[4] = 0x01; /* eject requested (eject button pressed) */
     3128                abBuf[5] = 0x02; /* medium present / door closed */
     3129                abBuf[6] = 0x00;
     3130                abBuf[7] = 0x00;
     3131                break;
     3132
     3133            case ATA_EVENT_STATUS_UNCHANGED:
     3134            default:
     3135                ataH2BE_U16(abBuf + 0, 6);
     3136                abBuf[2] = 0x01; /* operational change request / notification */
     3137                abBuf[3] = 0x5e; /* suppored = busy|media|external|power|operational */
     3138                abBuf[4] = 0x00;
     3139                abBuf[5] = 0x00;
     3140                abBuf[6] = 0x00;
     3141                abBuf[7] = 0x00;
     3142                break;
     3143        }
     3144    } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
     3145
     3146    *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&abBuf[0], sizeof(abBuf));
    30423147
    30433148    atapiCmdOK(pAhciPort, pAhciPortTaskState);
     
    31513256static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
    31523257{
    3153     uint8_t aBuf[18];
    3154 
    3155     memset(&aBuf[0], 0, 18);
    3156     aBuf[0] = 0x70 | (1 << 7);
    3157     aBuf[2] = pAhciPort->uATAPISenseKey;
    3158     aBuf[7] = 10;
    3159     aBuf[12] = pAhciPort->uATAPIASC;
    3160 
    31613258    /* Copy the buffer in to the scatter gather list. */
    3162     *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
     3259    *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, pAhciPort->abATAPISense, sizeof(pAhciPort->abATAPISense));
    31633260
    31643261    atapiCmdOK(pAhciPort, pAhciPortTaskState);
     
    31973294    if (iStartTrack > 1 && iStartTrack != 0xaa)
    31983295    {
    3199         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3296        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    32003297        return VINF_SUCCESS;
    32013298    }
     
    33693466}
    33703467
     3468static int atapiPassthroughSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
     3469{
     3470    int rc = VINF_SUCCESS;
     3471    uint8_t abATAPISense[ATAPI_SENSE_SIZE];
     3472    uint32_t cbTransfer;
     3473
     3474    cbTransfer = pAhciPortTaskState->cbTransfer;
     3475
     3476    /* Simple heuristics: if there is at least one sector of data
     3477     * to transfer, it's worth updating the LEDs. */
     3478    if (cbTransfer >= 2048)
     3479    {
     3480        if (pAhciPortTaskState->enmTxDir != AHCITXDIR_WRITE)
     3481            pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
     3482        else
     3483            pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
     3484    }
     3485
     3486    if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
     3487    {
     3488        /* Linux accepts commands with up to 100KB of data, but expects
     3489         * us to handle commands with up to 128KB of data. The usual
     3490         * imbalance of powers. */
     3491        uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
     3492        uint32_t iATAPILBA, cSectors, cReqSectors, cbCurrTX;
     3493        uint8_t *pbBuf = (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg;
     3494
     3495        Assert(pAhciPortTaskState->cSGListUsed == 1);
     3496
     3497        switch (pAhciPortTaskState->aATAPICmd[0])
     3498        {
     3499            case SCSI_READ_10:
     3500            case SCSI_WRITE_10:
     3501            case SCSI_WRITE_AND_VERIFY_10:
     3502                iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
     3503                cSectors = ataBE2H_U16(pAhciPortTaskState->aATAPICmd + 7);
     3504                break;
     3505            case SCSI_READ_12:
     3506            case SCSI_WRITE_12:
     3507                iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
     3508                cSectors = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 6);
     3509                break;
     3510            case SCSI_READ_CD:
     3511                iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
     3512                cSectors = ataBE2H_U24(pAhciPortTaskState->aATAPICmd + 6) / pAhciPortTaskState->cbATAPISector;
     3513                break;
     3514            case SCSI_READ_CD_MSF:
     3515                iATAPILBA = ataMSF2LBA(pAhciPortTaskState->aATAPICmd + 3);
     3516                cSectors = ataMSF2LBA(pAhciPortTaskState->aATAPICmd + 6) - iATAPILBA;
     3517                break;
     3518            default:
     3519                AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciPortTaskState->aATAPICmd[0]));
     3520                //if (s->cErrors++ < MAX_LOG_REL_ERRORS)
     3521                LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
     3522                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     3523                return false;
     3524        }
     3525        memcpy(aATAPICmd, pAhciPortTaskState->aATAPICmd, ATAPI_PACKET_SIZE);
     3526        cReqSectors = 0;
     3527        for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
     3528        {
     3529            if (i * pAhciPortTaskState->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
     3530                cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciPortTaskState->cbATAPISector;
     3531            else
     3532                cReqSectors = i;
     3533            cbCurrTX = pAhciPortTaskState->cbATAPISector * cReqSectors;
     3534            switch (pAhciPortTaskState->aATAPICmd[0])
     3535            {
     3536                case SCSI_READ_10:
     3537                case SCSI_WRITE_10:
     3538                case SCSI_WRITE_AND_VERIFY_10:
     3539                    ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
     3540                    ataH2BE_U16(aATAPICmd + 7, cReqSectors);
     3541                    break;
     3542                case SCSI_READ_12:
     3543                case SCSI_WRITE_12:
     3544                    ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
     3545                    ataH2BE_U32(aATAPICmd + 6, cReqSectors);
     3546                    break;
     3547                case SCSI_READ_CD:
     3548                    ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
     3549                    ataH2BE_U24(aATAPICmd + 6, cbCurrTX);
     3550                    break;
     3551                case SCSI_READ_CD_MSF:
     3552                    ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
     3553                    ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
     3554                    break;
     3555            }
     3556            rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
     3557                                                  aATAPICmd,
     3558                                                  pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
     3559                                                  ? PDMBLOCKTXDIR_FROM_DEVICE
     3560                                                  : PDMBLOCKTXDIR_TO_DEVICE,
     3561                                                  pbBuf,
     3562                                                  &cbCurrTX,
     3563                                                  abATAPISense,
     3564                                                  sizeof(abATAPISense),
     3565                                                  30000 /**< @todo timeout */);
     3566            if (rc != VINF_SUCCESS)
     3567                break;
     3568            iATAPILBA += cReqSectors;
     3569            pbBuf += pAhciPortTaskState->cbATAPISector * cReqSectors;
     3570        }
     3571    }
     3572    else
     3573    {
     3574        PDMBLOCKTXDIR enmBlockTxDir = PDMBLOCKTXDIR_NONE;
     3575
     3576        if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
     3577            enmBlockTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
     3578        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
     3579            enmBlockTxDir = PDMBLOCKTXDIR_TO_DEVICE;
     3580        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_NONE)
     3581            enmBlockTxDir = PDMBLOCKTXDIR_NONE;
     3582        else
     3583            AssertMsgFailed(("Invalid transfer direction %d\n", pAhciPortTaskState->enmTxDir));
     3584
     3585        rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
     3586                                              pAhciPortTaskState->aATAPICmd,
     3587                                              enmBlockTxDir,
     3588                                              pAhciPortTaskState->pSGListHead[0].pvSeg,
     3589                                              &cbTransfer,
     3590                                              abATAPISense,
     3591                                              sizeof(abATAPISense),
     3592                                              30000 /**< @todo timeout */);
     3593    }
     3594
     3595    /* Update the LEDs and the read/write statistics. */
     3596    if (cbTransfer >= 2048)
     3597    {
     3598        if (pAhciPortTaskState->enmTxDir != AHCITXDIR_WRITE)
     3599        {
     3600            pAhciPort->Led.Actual.s.fReading = 0;
     3601            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
     3602        }
     3603        else
     3604        {
     3605            pAhciPort->Led.Actual.s.fWriting = 0;
     3606            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
     3607        }
     3608    }
     3609
     3610    if (RT_SUCCESS(rc))
     3611    {
     3612       Assert(cbTransfer <= pAhciPortTaskState->cbTransfer);
     3613       /* Reply with the same amount of data as the real drive. */
     3614       *pcbData = cbTransfer;
     3615
     3616        if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
     3617        {
     3618            if (pAhciPortTaskState->aATAPICmd[0] == SCSI_INQUIRY)
     3619            {
     3620                /* Make sure that the real drive cannot be identified.
     3621                 * Motivation: changing the VM configuration should be as
     3622                 *             invisible as possible to the guest. */
     3623                ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 8, "VBOX", 8);
     3624                ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 16, "CD-ROM", 16);
     3625                ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 32, "1.0", 4);
     3626            }
     3627            if (cbTransfer)
     3628                Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg));
     3629        }
     3630        atapiCmdOK(pAhciPort, pAhciPortTaskState);
     3631    }
     3632    else
     3633    {
     3634        if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
     3635        {
     3636            uint8_t u8Cmd = pAhciPortTaskState->aATAPICmd[0];
     3637            do
     3638            {
     3639                /* don't log superflous errors */
     3640                if (    rc == VERR_DEV_IO_ERROR
     3641                    && (   u8Cmd == SCSI_TEST_UNIT_READY
     3642                        || u8Cmd == SCSI_READ_CAPACITY
     3643                        || u8Cmd == SCSI_READ_DVD_STRUCTURE
     3644                        || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
     3645                    break;
     3646                pAhciPort->cErrors++;
     3647                LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
     3648                            pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
     3649            } while (0);
     3650        }
     3651        atapiCmdError(pAhciPort, pAhciPortTaskState, abATAPISense, sizeof(abATAPISense));
     3652    }
     3653    return false;
     3654}
     3655
    33713656static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
    33723657{
    3373     int cbTransfered;
     3658    int cbTransfered = 0;
    33743659    int rc, rcSourceSink;
    33753660
     
    33803665     */
    33813666    ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
    3382     rc = ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, false, 0);
    3383     AssertRC(rc);
     3667    if (pAhciPortTaskState->cbSGBuffers)
     3668    {
     3669        rc = ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, false, 0);
     3670        AssertRC(rc);
     3671    }
    33843672
    33853673    rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
     
    33873675    pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
    33883676
    3389     rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
    3390     AssertRC(rc);
     3677    LogFlow(("cbTransfered=%d\n", cbTransfered));
     3678
     3679    if (pAhciPortTaskState->cbSGBuffers)
     3680    {
     3681        rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
     3682        AssertRC(rc);
     3683    }
    33913684
    33923685    /* Write updated command header into memory of the guest. */
     
    34503743}
    34513744
    3452 static int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
    3453 {
    3454     int iTxDir = PDMBLOCKTXDIR_NONE;
     3745static AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
     3746{
     3747    AHCITXDIR rc = AHCITXDIR_NONE;
    34553748    const uint8_t *pbPacket;
    34563749    uint32_t cbMax;
     
    34663759            {
    34673760                if (pAhciPort->cNotifiedMediaChange-- > 2)
    3468                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3761                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    34693762                else
    3470                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     3763                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    34713764            }
    34723765            else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    34733766                atapiCmdOK(pAhciPort, pAhciPortTaskState);
    34743767            else
    3475                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3768                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    34763769            break;
    34773770        case SCSI_MODE_SENSE_10:
     
    35023795                    default:
    35033796                    case SCSI_PAGECONTROL_SAVED:
    3504                         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
     3797                        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
    35053798                        break;
    35063799                }
     
    35213814            }
    35223815            else
    3523                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3816                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    35243817            break;
    35253818        case SCSI_READ_10:
     
    35313824                {
    35323825                    pAhciPort->cNotifiedMediaChange-- ;
    3533                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     3826                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    35343827                    break;
    35353828                }
    35363829                else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    35373830                {
    3538                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3831                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    35393832                    break;
    35403833                }
     
    35613854                        uLastLogTS = RTTimeMilliTS();
    35623855                    }
    3563                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
     3856                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
    35643857                    break;
    35653858                }
    35663859                atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
    3567                 iTxDir = AHCITXDIR_READ;
     3860                rc = AHCITXDIR_READ;
    35683861            }
    35693862            break;
     
    35753868                {
    35763869                    pAhciPort->cNotifiedMediaChange-- ;
    3577                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     3870                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    35783871                    break;
    35793872                }
    35803873                else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    35813874                {
    3582                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3875                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    35833876                    break;
    35843877                }
     
    36023895                        uLastLogTS = RTTimeMilliTS();
    36033896                    }
    3604                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
     3897                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
    36053898                    break;
    36063899                }
     
    36143907                        /* normal read */
    36153908                        atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
    3616                         iTxDir = AHCITXDIR_READ;
     3909                        rc = AHCITXDIR_READ;
    36173910                        break;
    36183911                    case 0xf8:
    36193912                        /* read all data */
    36203913                        atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
    3621                         iTxDir = AHCITXDIR_READ;
     3914                        rc = AHCITXDIR_READ;
    36223915                        break;
    36233916                    default:
    36243917                        LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
    3625                         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     3918                        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    36263919                        break;
    36273920                }
     
    36343927                {
    36353928                    pAhciPort->cNotifiedMediaChange-- ;
    3636                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     3929                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    36373930                    break;
    36383931                }
    36393932                else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    36403933                {
    3641                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     3934                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    36423935                    break;
    36433936                }
     
    36553948                        uLastLogTS = RTTimeMilliTS();
    36563949                    }
    3657                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
     3950                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
    36583951                    break;
    36593952                }
     
    36643957        case SCSI_START_STOP_UNIT:
    36653958            {
    3666                 int rc = VINF_SUCCESS;
     3959                int rc2 = VINF_SUCCESS;
    36673960                switch (pbPacket[4] & 3)
    36683961                {
     
    36763969                            PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
    36773970
    3678                             rc = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
    3679                                                  (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
    3680                             Assert(RT_SUCCESS(rc) || (rc == VERR_PDM_MEDIA_LOCKED));
     3971                            rc2 = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
     3972                                                  (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
     3973                            Assert(RT_SUCCESS(rc2) || (rc == VERR_PDM_MEDIA_LOCKED));
    36813974                        }
    36823975                        break;
     
    36853978                        break;
    36863979                }
    3687                 if (RT_SUCCESS(rc))
     3980                if (RT_SUCCESS(rc2))
    36883981                    atapiCmdOK(pAhciPort, pAhciPortTaskState);
    36893982                else
    3690                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
     3983                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
    36913984            }
    36923985            break;
     
    37043997                {
    37053998                    pAhciPort->cNotifiedMediaChange-- ;
    3706                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     3999                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    37074000                    break;
    37084001                }
    37094002                else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    37104003                {
    3711                     atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     4004                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    37124005                    break;
    37134006                }
     
    37304023                    default:
    37314024                    error_cmd:
    3732                         atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     4025                        atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    37334026                        break;
    37344027                }
     
    37394032            {
    37404033                pAhciPort->cNotifiedMediaChange-- ;
    3741                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     4034                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    37424035                break;
    37434036            }
    37444037            else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    37454038            {
    3746                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     4039                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    37474040                break;
    37484041            }
     
    37534046            {
    37544047                pAhciPort->cNotifiedMediaChange-- ;
    3755                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     4048                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    37564049                break;
    37574050            }
    37584051            else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    37594052            {
    3760                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     4053                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    37614054                break;
    37624055            }
     
    37684061            {
    37694062                pAhciPort->cNotifiedMediaChange-- ;
    3770                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
     4063                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
    37714064                break;
    37724065            }
    37734066            else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
    37744067            {
    3775                 atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
     4068                atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
    37764069                break;
    37774070            }
     
    37894082            break;
    37904083        default:
    3791             atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     4084            atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
    37924085            break;
    37934086    }
    37944087
    3795     return iTxDir;
     4088    return rc;
     4089}
     4090
     4091/*
     4092 * Parse ATAPI commands, passing them directly to the CD/DVD drive.
     4093 */
     4094static AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
     4095{
     4096    const uint8_t *pbPacket;
     4097    uint32_t cSectors, iATAPILBA;
     4098    uint32_t cbTransfer = 0;
     4099    AHCITXDIR enmTxDir = AHCITXDIR_NONE;
     4100
     4101    pbPacket = pAhciPortTaskState->aATAPICmd;
     4102    switch (pbPacket[0])
     4103    {
     4104        case SCSI_BLANK:
     4105            goto sendcmd;
     4106        case SCSI_CLOSE_TRACK_SESSION:
     4107            goto sendcmd;
     4108        case SCSI_ERASE_10:
     4109            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4110            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4111            Log2(("ATAPI PT: lba %d\n", iATAPILBA));
     4112            enmTxDir = AHCITXDIR_WRITE;
     4113            goto sendcmd;
     4114        case SCSI_FORMAT_UNIT:
     4115            cbTransfer = pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
     4116            enmTxDir = AHCITXDIR_WRITE;
     4117            goto sendcmd;
     4118        case SCSI_GET_CONFIGURATION:
     4119            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4120            enmTxDir = AHCITXDIR_READ;
     4121            goto sendcmd;
     4122        case SCSI_GET_EVENT_STATUS_NOTIFICATION:
     4123            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4124            if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
     4125            {
     4126                pAhciPortTaskState->cbTransfer = RT_MIN(cbTransfer, 8);
     4127                atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
     4128                break;
     4129            }
     4130            enmTxDir = AHCITXDIR_READ;
     4131            goto sendcmd;
     4132        case SCSI_GET_PERFORMANCE:
     4133            cbTransfer = pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
     4134            enmTxDir = AHCITXDIR_READ;
     4135            goto sendcmd;
     4136        case SCSI_INQUIRY:
     4137            cbTransfer = ataBE2H_U16(pbPacket + 3);
     4138            enmTxDir = AHCITXDIR_READ;
     4139            goto sendcmd;
     4140        case SCSI_LOAD_UNLOAD_MEDIUM:
     4141            goto sendcmd;
     4142        case SCSI_MECHANISM_STATUS:
     4143            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4144            enmTxDir = AHCITXDIR_READ;
     4145            goto sendcmd;
     4146        case SCSI_MODE_SELECT_10:
     4147            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4148            enmTxDir = AHCITXDIR_WRITE;
     4149            goto sendcmd;
     4150        case SCSI_MODE_SENSE_10:
     4151            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4152            enmTxDir = AHCITXDIR_READ;
     4153            goto sendcmd;
     4154        case SCSI_PAUSE_RESUME:
     4155            goto sendcmd;
     4156        case SCSI_PLAY_AUDIO_10:
     4157            goto sendcmd;
     4158        case SCSI_PLAY_AUDIO_12:
     4159            goto sendcmd;
     4160        case SCSI_PLAY_AUDIO_MSF:
     4161            goto sendcmd;
     4162        case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
     4163            /** @todo do not forget to unlock when a VM is shut down */
     4164            goto sendcmd;
     4165        case SCSI_READ_10:
     4166            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4167            cSectors = ataBE2H_U16(pbPacket + 7);
     4168            Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
     4169            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4170            cbTransfer = cSectors * pAhciPortTaskState->cbATAPISector;
     4171            enmTxDir = AHCITXDIR_READ;
     4172            goto sendcmd;
     4173        case SCSI_READ_12:
     4174            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4175            cSectors = ataBE2H_U32(pbPacket + 6);
     4176            Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
     4177            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4178            cbTransfer = cSectors * pAhciPortTaskState->cbATAPISector;
     4179            enmTxDir = AHCITXDIR_READ;
     4180            goto sendcmd;
     4181        case SCSI_READ_BUFFER:
     4182            cbTransfer = ataBE2H_U24(pbPacket + 6);
     4183            enmTxDir = AHCITXDIR_READ;
     4184            goto sendcmd;
     4185        case SCSI_READ_BUFFER_CAPACITY:
     4186            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4187            enmTxDir = AHCITXDIR_READ;
     4188            goto sendcmd;
     4189        case SCSI_READ_CAPACITY:
     4190            cbTransfer = 8;
     4191            enmTxDir = AHCITXDIR_READ;
     4192            goto sendcmd;
     4193        case SCSI_READ_CD:
     4194            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4195            cbTransfer = ataBE2H_U24(pbPacket + 6) / pAhciPortTaskState->cbATAPISector * pAhciPortTaskState->cbATAPISector;
     4196            enmTxDir = AHCITXDIR_READ;
     4197            goto sendcmd;
     4198        case SCSI_READ_CD_MSF:
     4199            cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
     4200            if (cSectors > 32)
     4201                cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
     4202            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4203            cbTransfer = cSectors * pAhciPortTaskState->cbATAPISector;
     4204            enmTxDir = AHCITXDIR_READ;
     4205            goto sendcmd;
     4206        case SCSI_READ_DISC_INFORMATION:
     4207            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4208            enmTxDir = AHCITXDIR_READ;
     4209            goto sendcmd;
     4210        case SCSI_READ_DVD_STRUCTURE:
     4211            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4212            enmTxDir = AHCITXDIR_READ;
     4213            goto sendcmd;
     4214        case SCSI_READ_FORMAT_CAPACITIES:
     4215            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4216            enmTxDir = AHCITXDIR_READ;
     4217            goto sendcmd;
     4218        case SCSI_READ_SUBCHANNEL:
     4219            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4220            enmTxDir = AHCITXDIR_READ;
     4221            goto sendcmd;
     4222        case SCSI_READ_TOC_PMA_ATIP:
     4223            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4224            enmTxDir = AHCITXDIR_READ;
     4225            goto sendcmd;
     4226        case SCSI_READ_TRACK_INFORMATION:
     4227            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4228            enmTxDir = AHCITXDIR_READ;
     4229            goto sendcmd;
     4230        case SCSI_REPAIR_TRACK:
     4231            goto sendcmd;
     4232        case SCSI_REPORT_KEY:
     4233            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4234            enmTxDir = AHCITXDIR_READ;
     4235            goto sendcmd;
     4236        case SCSI_REQUEST_SENSE:
     4237            cbTransfer = pbPacket[4];
     4238            if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
     4239            {
     4240                pAhciPortTaskState->cbTransfer = cbTransfer;
     4241                pAhciPortTaskState->enmTxDir = AHCITXDIR_READ;
     4242                atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_REQUEST_SENSE);
     4243                break;
     4244            }
     4245            enmTxDir = AHCITXDIR_READ;
     4246            goto sendcmd;
     4247        case SCSI_RESERVE_TRACK:
     4248            goto sendcmd;
     4249        case SCSI_SCAN:
     4250            goto sendcmd;
     4251        case SCSI_SEEK_10:
     4252            goto sendcmd;
     4253        case SCSI_SEND_CUE_SHEET:
     4254            cbTransfer = ataBE2H_U24(pbPacket + 6);
     4255            enmTxDir = AHCITXDIR_WRITE;
     4256            goto sendcmd;
     4257        case SCSI_SEND_DVD_STRUCTURE:
     4258            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4259            enmTxDir = AHCITXDIR_WRITE;
     4260            goto sendcmd;
     4261        case SCSI_SEND_EVENT:
     4262            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4263            enmTxDir = AHCITXDIR_WRITE;
     4264            goto sendcmd;
     4265        case SCSI_SEND_KEY:
     4266            cbTransfer = ataBE2H_U16(pbPacket + 8);
     4267            enmTxDir = AHCITXDIR_WRITE;
     4268            goto sendcmd;
     4269        case SCSI_SEND_OPC_INFORMATION:
     4270            cbTransfer = ataBE2H_U16(pbPacket + 7);
     4271            enmTxDir = AHCITXDIR_WRITE;
     4272            goto sendcmd;
     4273        case SCSI_SET_CD_SPEED:
     4274            goto sendcmd;
     4275        case SCSI_SET_READ_AHEAD:
     4276            goto sendcmd;
     4277        case SCSI_SET_STREAMING:
     4278            cbTransfer = ataBE2H_U16(pbPacket + 9);
     4279            enmTxDir = AHCITXDIR_WRITE;
     4280            goto sendcmd;
     4281        case SCSI_START_STOP_UNIT:
     4282            goto sendcmd;
     4283        case SCSI_STOP_PLAY_SCAN:
     4284            goto sendcmd;
     4285        case SCSI_SYNCHRONIZE_CACHE:
     4286            goto sendcmd;
     4287        case SCSI_TEST_UNIT_READY:
     4288            goto sendcmd;
     4289        case SCSI_VERIFY_10:
     4290            goto sendcmd;
     4291        case SCSI_WRITE_10:
     4292            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4293            cSectors = ataBE2H_U16(pbPacket + 7);
     4294            Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
     4295            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4296            cbTransfer = cSectors * pAhciPortTaskState->cbATAPISector;
     4297            enmTxDir = AHCITXDIR_WRITE;
     4298            goto sendcmd;
     4299        case SCSI_WRITE_12:
     4300            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4301            cSectors = ataBE2H_U32(pbPacket + 6);
     4302            Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
     4303            pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
     4304            cbTransfer = cSectors * pAhciPortTaskState->cbATAPISector;
     4305            enmTxDir = AHCITXDIR_WRITE;
     4306            goto sendcmd;
     4307        case SCSI_WRITE_AND_VERIFY_10:
     4308            iATAPILBA = ataBE2H_U32(pbPacket + 2);
     4309            cSectors = ataBE2H_U16(pbPacket + 7);
     4310            Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
     4311            /* The sector size is determined by the async I/O thread. */
     4312            pAhciPortTaskState->cbATAPISector = 0;
     4313            /* Preliminary, will be corrected once the sector size is known. */
     4314            cbTransfer = cSectors;
     4315            enmTxDir = AHCITXDIR_WRITE;
     4316            goto sendcmd;
     4317        case SCSI_WRITE_BUFFER:
     4318            switch (pbPacket[1] & 0x1f)
     4319            {
     4320                case 0x04: /* download microcode */
     4321                case 0x05: /* download microcode and save */
     4322                case 0x06: /* download microcode with offsets */
     4323                case 0x07: /* download microcode with offsets and save */
     4324                case 0x0e: /* download microcode with offsets and defer activation */
     4325                case 0x0f: /* activate deferred microcode */
     4326                    LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
     4327                    atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
     4328                    break;
     4329                default:
     4330                    cbTransfer = ataBE2H_U16(pbPacket + 6);
     4331                    enmTxDir = AHCITXDIR_WRITE;
     4332                    goto sendcmd;
     4333            }
     4334            break;
     4335        case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
     4336            cbTransfer = ataBE2H_U32(pbPacket + 6);
     4337            enmTxDir = AHCITXDIR_READ;
     4338            goto sendcmd;
     4339        case SCSI_REZERO_UNIT:
     4340            /* Obsolete command used by cdrecord. What else would one expect?
     4341             * This command is not sent to the drive, it is handled internally,
     4342             * as the Linux kernel doesn't like it (message "scsi: unknown
     4343             * opcode 0x01" in syslog) and replies with a sense code of 0,
     4344             * which sends cdrecord to an endless loop. */
     4345            atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     4346            break;
     4347        default:
     4348            LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
     4349            atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
     4350            break;
     4351        sendcmd:
     4352            /* Send a command to the drive, passing data in/out as required. */
     4353            Log2(("ATAPI PT: max size %d\n", cbTransfer));
     4354            if (cbTransfer == 0)
     4355                enmTxDir = AHCITXDIR_NONE;
     4356            pAhciPortTaskState->enmTxDir = enmTxDir;
     4357            pAhciPortTaskState->cbTransfer = cbTransfer;
     4358            atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_PASSTHROUGH);
     4359    }
     4360
     4361    return AHCITXDIR_NONE;
     4362}
     4363
     4364static AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
     4365{
     4366    AHCITXDIR enmTxDir = AHCITXDIR_NONE;
     4367    const uint8_t *pbPacket;
     4368
     4369    pbPacket = pAhciPortTaskState->aATAPICmd;
     4370#ifdef DEBUG
     4371    Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
     4372#else /* !DEBUG */
     4373    Log(("%s: LUN#%d CMD=%#04x\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0]));
     4374#endif /* !DEBUG */
     4375    Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
     4376
     4377    if (pAhciPort->fATAPIPassthrough)
     4378        enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciPortTaskState);
     4379    else
     4380        enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
     4381
     4382    return enmTxDir;
    37964383}
    37974384
     
    40374624    ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
    40384625
    4039     /* Set start address of the entries. */
    4040     GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
    4041 
    4042     do
    4043     {
    4044         cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
    4045         cSGLEntriesGCLeft -= cSGLEntriesGCRead;
    4046 
    4047         /* Read the SG entries. */
    4048         PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
    4049 
    4050         for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
     4626    if (cSGLEntriesGCLeft)
     4627    {
     4628        /* Set start address of the entries. */
     4629        GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
     4630
     4631        do
     4632        {
     4633            cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
     4634            cSGLEntriesGCLeft -= cSGLEntriesGCRead;
     4635
     4636            /* Read the SG entries. */
     4637            PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
     4638
     4639            for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
    40514640            cbSGBuffers += (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
    40524641
    4053         /* Set address to the next entries to read. */
    4054         GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
    4055 
    4056     } while (cSGLEntriesGCLeft);
     4642            /* Set address to the next entries to read. */
     4643            GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
     4644        } while (cSGLEntriesGCLeft);
     4645    }
    40574646
    40584647    pAhciPortTaskState->cbSGBuffers = cbSGBuffers;
     
    50925681            }
    50935682            else
    5094             {
    5095                 int rc2 = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
    5096             }
     5683                rc = atapiParseCmd(pAhciPort, pAhciPortTaskState);
    50975684            break;
    50985685        case ATA_IDENTIFY_PACKET_DEVICE:
     
    58916478}
    58926479
    5893 /**
    5894  * Called when a media is mounted.
    5895  *
    5896  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    5897  */
    5898 static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
    5899 {
    5900     PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
    5901     Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
    5902 
    5903     /* Ignore the call if we're called while being attached. */
    5904     if (!pAhciPort->pDrvBlock)
    5905         return;
    5906 
    5907     pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
    5908 
    5909     /*
    5910      * Initialize registers
    5911      */
    5912     pAhciPort->regCMD  |= AHCI_PORT_CMD_CPS;
    5913     ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
    5914     pAhciPort->regSERR |= AHCI_PORT_SERR_N;
    5915     if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
    5916         ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
    5917 }
    5918 
    5919 /**
    5920  * Called when a media is unmounted
    5921  * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    5922  */
    5923 static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
    5924 {
    5925     PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
    5926     Log(("%s:\n", __FUNCTION__));
    5927 
    5928     pAhciPort->cTotalSectors = 0;
    5929 
    5930     /*
    5931      * Inform the guest about the removed device.
    5932      */
    5933     pAhciPort->regSSTS = 0;
    5934     pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
    5935     ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
    5936     pAhciPort->regSERR |= AHCI_PORT_SERR_N;
    5937     if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
    5938         ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
    5939 }
    5940 
    59416480/* -=-=-=-=- DBGF -=-=-=-=- */
    59426481
     
    64326971
    64336972/**
     6973 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
     6974 * from now on, regardless if there was a medium inserted or not.
     6975 */
     6976static void ahciMediumRemoved(PAHCIPort pAhciPort)
     6977{
     6978    ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
     6979}
     6980
     6981
     6982/**
     6983 * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
     6984 * there was already a medium inserted, don't forget to send the "medium
     6985 * removed" event first.
     6986 */
     6987static void ahciMediumInserted(PAHCIPort pAhciPort)
     6988{
     6989    uint32_t OldStatus, NewStatus;
     6990    do
     6991    {
     6992        OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
     6993        switch (OldStatus)
     6994        {
     6995            case ATA_EVENT_STATUS_MEDIA_CHANGED:
     6996            case ATA_EVENT_STATUS_MEDIA_REMOVED:
     6997                /* no change, we will send "medium removed" + "medium inserted" */
     6998                NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
     6999                break;
     7000            default:
     7001                NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
     7002                break;
     7003        }
     7004    } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
     7005}
     7006
     7007/**
     7008 * Called when a media is mounted.
     7009 *
     7010 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     7011 */
     7012static DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
     7013{
     7014    PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
     7015    Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
     7016
     7017    /* Ignore the call if we're called while being attached. */
     7018    if (!pAhciPort->pDrvBlock)
     7019        return;
     7020
     7021    if (pAhciPort->fATAPI)
     7022    {
     7023        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
     7024
     7025        LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
     7026
     7027        /* Report media changed in TEST UNIT and other (probably incorrect) places. */
     7028        if (pAhciPort->cNotifiedMediaChange < 2)
     7029            pAhciPort->cNotifiedMediaChange = 2;
     7030        ahciMediumInserted(pAhciPort);
     7031    }
     7032    else
     7033    {
     7034        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
     7035
     7036        /*
     7037         * Initialize registers
     7038         */
     7039        pAhciPort->regCMD  |= AHCI_PORT_CMD_CPS;
     7040        ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
     7041        pAhciPort->regSERR |= AHCI_PORT_SERR_N;
     7042        if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
     7043            ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
     7044    }
     7045}
     7046
     7047/**
     7048 * Called when a media is unmounted
     7049 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
     7050 */
     7051static DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
     7052{
     7053    PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
     7054    Log(("%s:\n", __FUNCTION__));
     7055
     7056    pAhciPort->cTotalSectors = 0;
     7057
     7058    if (pAhciPort->fATAPI)
     7059    {
     7060        /*
     7061         * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
     7062         * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
     7063         * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
     7064         * present and 2 in which it is changed.
     7065         */
     7066        pAhciPort->cNotifiedMediaChange = 4;
     7067        ahciMediumRemoved(pAhciPort);
     7068    }
     7069    else
     7070    {
     7071        /*
     7072         * Inform the guest about the removed device.
     7073         */
     7074        pAhciPort->regSSTS = 0;
     7075        pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
     7076        ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
     7077        pAhciPort->regSERR |= AHCI_PORT_SERR_N;
     7078        if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
     7079            ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
     7080    }
     7081}
     7082
     7083/**
    64347084 * Configure the attached device for a port.
    64357085 *
     
    64867136    }
    64877137    pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
     7138    pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
    64887139
    64897140    if (pAhciPort->fATAPI)
     
    66427293    if (pCtl)
    66437294        ataControllerDetach(pCtl, fMaster);
     7295
     7296    if (pAhciPort->fATAPI)
     7297        ahciMediumRemoved(pAhciPort);
    66447298
    66457299    /*
     
    67167370        if (RT_SUCCESS(rc))
    67177371        {
    6718             if (pAhciPort->pDrvBlockAsync)
     7372            if (   pAhciPort->pDrvBlockAsync
     7373                && !pAhciPort->fATAPI)
    67197374            {
    67207375                pAhciPort->fAsyncInterface = true;
     
    67447399                }
    67457400            }
     7401
     7402            if (RT_SUCCESS(rc) && pAhciPort->fATAPI)
     7403                ahciMediumInserted(pAhciPort);
    67467404        }
    67477405    }
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r31899 r32069  
    11761176    GEN_CHECK_OFF(AHCIPort, fFirstD2HFisSend);
    11771177    GEN_CHECK_OFF(AHCIPort, fATAPI);
     1178    GEN_CHECK_OFF(AHCIPort, fATAPIPassthrough);
    11781179    GEN_CHECK_OFF(AHCIPort, pDrvBase);
    11791180    GEN_CHECK_OFF(AHCIPort, pDrvBlock);
     
    11901191    GEN_CHECK_OFF(AHCIPort, cMultSectors);
    11911192    GEN_CHECK_OFF(AHCIPort, uATATransferMode);
    1192     GEN_CHECK_OFF(AHCIPort, uATAPISenseKey);
    1193     GEN_CHECK_OFF(AHCIPort, uATAPIASC);
     1193    GEN_CHECK_OFF(AHCIPort, abATAPISense);
    11941194    GEN_CHECK_OFF(AHCIPort, cNotifiedMediaChange);
    11951195    GEN_CHECK_OFF(AHCIPort, iLUN);
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