DevATA.cpp revision d4bc81a2be43a3c11f479f600c48581f6d496ac8
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * VBox storage devices: ATA/ATAPI controller device (disk and cdrom).
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * Copyright (C) 2006-2008 Sun Microsystems, Inc.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * available from http://www.virtualbox.org. This file is free software;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * General Public License (GPL) as published by the Free Software
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * additional information or have any questions.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/*******************************************************************************
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync* Defined Constants And Macros *
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync*******************************************************************************/
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync/** Temporary instrumentation for tracking down potential virtual disk
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * write performance issues. */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * The SSM saved state versions.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#define ATA_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 16
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/*******************************************************************************
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync* Header Files *
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync*******************************************************************************/
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* IN_RING3 */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsynctypedef struct PCIATAState {
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /** The controllers. */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /** Pointer to device instance. */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /** Status Port - Base interface. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /** Status Port - Leds interface. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /** Partner of ILeds. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /** Flag whether GC is enabled. */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync /** Flag whether R0 is enabled. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /** Flag indicating whether PIIX4 or PIIX3 is being emulated. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync bool Alignment0[HC_ARCH_BITS == 64 ? 5 : 1]; /**< Align the struct size. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define PDMIBASE_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, IBase)) )
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#define PDMILEDPORTS_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, ILeds)) )
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define PDMIBLOCKPORT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IPort)) )
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#define PDMIMOUNT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMount)) )
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define PDMIMOUNTNOTIFY_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMountNotify)) )
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define PCIDEV_2_PCIATASTATE(pPciDev) ( (PCIATAState *)(pPciDev) )
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#define ATACONTROLLER_IDX(pController) ( (pController) - PDMINS_2_DATA(CONTROLLER_2_DEVINS(pController), PCIATAState *)->aCts )
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/*******************************************************************************
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * Internal Functions *
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ******************************************************************************/
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncDECLINLINE(void) ataSetStatusValue(ATADevState *s, uint8_t stat)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* Freeze status register contents while processing RESET. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncDECLINLINE(void) ataSetStatus(ATADevState *s, uint8_t stat)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /* Freeze status register contents while processing RESET. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) ataUnsetStatus(ATADevState *s, uint8_t stat)
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* Freeze status register contents while processing RESET. */
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic bool ataExecuteDeviceDiagnosticSS(ATADevState *);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *);
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *);
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync * Begin of transfer function indexes for g_apfnBeginTransFuncs.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * Array of end transfer functions, the index is ATAFNET.
1969e98a26e5b56b67fbe3b6bfa007f8f09e86ebvboxsync * Make sure ATAFNET and this array match!
81614fc60e096e714022d10d38b70a36b9b21d48vboxsyncstatic const PBeginTransferFunc g_apfnBeginTransFuncs[ATAFN_BT_MAX] =
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * Source/sink function indexes for g_apfnSourceSinkFuncs.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * Array of source/sink functions, the index is ATAFNSS.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * Make sure ATAFNSS and this array match!
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const PSourceSinkFunc g_apfnSourceSinkFuncs[ATAFN_SS_MAX] =
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const ATARequest ataDMARequest = { ATA_AIO_DMA, };
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const ATARequest ataPIORequest = { ATA_AIO_PIO, };
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const ATARequest ataResetARequest = { ATA_AIO_RESET_ASSERTED, };
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const ATARequest ataResetCRequest = { ATA_AIO_RESET_CLEARED, };
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void ataAsyncIOClearRequests(PATACONTROLLER pCtl)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void ataAsyncIOPutRequest(PATACONTROLLER pCtl, const ATARequest *pReq)
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Assert((pCtl->AsyncIOReqHead + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests) != pCtl->AsyncIOReqTail);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync memcpy(&pCtl->aAsyncIORequests[pCtl->AsyncIOReqHead], pReq, sizeof(*pReq));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync pCtl->AsyncIOReqHead %= RT_ELEMENTS(pCtl->aAsyncIORequests);
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync LogBird(("ata: %x: signalling\n", pCtl->IOPortBase1));
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem);
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync LogBird(("ata: %x: schedule failed, rc=%Rrc\n", pCtl->IOPortBase1, rc));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic const ATARequest *ataAsyncIOGetCurrentRequest(PATACONTROLLER pCtl)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync pReq = &pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * Remove the request with the given type, as it's finished. The request
38745c55f37c31ba8b78cc728d2f08ea6eec38d6vboxsync * is not removed blindly, as this could mean a RESET request that is not
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * yet processed (but has cleared the request queue) is lost.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * @param pCtl Controller for which to remove the request.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * @param ReqType Type of the request to remove.
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void ataAsyncIORemoveCurrentRequest(PATACONTROLLER pCtl, ATAAIO ReqType)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail && pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail].ReqType == ReqType)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync pCtl->AsyncIOReqTail %= RT_ELEMENTS(pCtl->aAsyncIORequests);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * Dump the request queue for a particular controller. First dump the queue
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * contents, then the already processed entries, as long as they haven't been
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * overwritten.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * @param pCtl Controller for which to dump the queue.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void ataAsyncIODumpRequests(PATACONTROLLER pCtl)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("PIIX3 ATA: Ctl#%d: request queue dump (topmost is current):\n", ATACONTROLLER_IDX(pCtl)));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("PIIX3 ATA: Ctl#%d: processed requests (topmost is oldest):\n", ATACONTROLLER_IDX(pCtl)));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("new transfer request, iIf=%d iBeginTransfer=%d iSourceSink=%d cbTotalTransfer=%d uTxDir=%d\n", pCtl->aAsyncIORequests[curr].u.t.iIf, pCtl->aAsyncIORequests[curr].u.t.iBeginTransfer, pCtl->aAsyncIORequests[curr].u.t.iSourceSink, pCtl->aAsyncIORequests[curr].u.t.cbTotalTransfer, pCtl->aAsyncIORequests[curr].u.t.uTxDir));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("abort request, iIf=%d fResetDrive=%d\n", pCtl->aAsyncIORequests[curr].u.a.iIf, pCtl->aAsyncIORequests[curr].u.a.fResetDrive));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("unknown request %d\n", pCtl->aAsyncIORequests[curr].ReqType));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync curr = (curr + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * Checks whether the request queue for a particular controller is empty
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * or whether a particular controller is idle.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * @param pCtl Controller for which to check the queue.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * @param fStrict If set then the controller is checked to be idle.
38745c55f37c31ba8b78cc728d2f08ea6eec38d6vboxsyncstatic bool ataAsyncIOIsIdle(PATACONTROLLER pCtl, bool fStrict)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync fIdle = (pCtl->AsyncIOReqHead == pCtl->AsyncIOReqTail);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * Send a transfer request to the async I/O thread.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * @param s Pointer to the ATA device state data.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * @param cbTotalTransfer Data transfer size.
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync * @param uTxDir Data transfer direction.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @param iBeginTransfer Index of BeginTransfer callback.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @param iSourceSink Index of SourceSink callback.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * @param fChainedTransfer Whether this is a transfer that is part of the previous command/transfer.
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic void ataStartTransfer(ATADevState *s, uint32_t cbTotalTransfer, uint8_t uTxDir, ATAFNBT iBeginTransfer, ATAFNSS iSourceSink, bool fChainedTransfer)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* Do not issue new requests while the RESET line is asserted. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync Log2(("%s: Ctl#%d: suppressed new request as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync /* If the controller is already doing something else right now, ignore
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync * the command that is being submitted. Some broken guests issue commands
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync LogRel(("PIIX3 IDE: guest issued command %#04x while controller busy\n", s->uATARegCommand));
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync * Kick the worker thread into action.
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, new request\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync * Send an abort command request to the async I/O thread.
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync * @param s Pointer to the ATA device state data.
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync * @param fResetDrive Whether to reset the drive or just abort a command.
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsyncstatic void ataAbortCurrentCommand(ATADevState *s, bool fResetDrive)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Do not issue new requests while the RESET line is asserted. */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync Log2(("%s: Ctl#%d: suppressed aborting command as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
1379dfd407ada5fab15655776896f13b61a951fdvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, abort command on LUN#%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->iLUN));
1379dfd407ada5fab15655776896f13b61a951fdvboxsync Log2(("%s: LUN#%d asserting IRQ\n", __FUNCTION__, s->iLUN));
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if the interrupt
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * line is asserted. It monitors the line for a rising edge. */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync /* Only actually set the IRQ line if updating the currently selected drive. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /** @todo experiment with adaptive IRQ delivery: for reads it is
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync * better to wait for IRQ delivery, as it reduces latency. */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync#endif /* IN_RING3 */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync Log2(("%s: LUN#%d deasserting IRQ\n", __FUNCTION__, s->iLUN));
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync /* Only actually unset the IRQ line if updating the currently selected drive. */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsyncstatic void ataPIOTransferStart(ATADevState *s, uint32_t start, uint32_t size)
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync Log2(("%s: LUN#%d start %d size %d\n", __FUNCTION__, s->iLUN, start, size));
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic void ataPIOTransferLimitATAPI(ATADevState *s)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* Use maximum transfer size if the guest requested 0. Avoids a hang. */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync Log2(("%s: byte count limit=%d\n", __FUNCTION__, cbLimit));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->iIOBufferEnd - s->iIOBufferCur);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* Byte count limit for clipping must be even in this case */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return 65536;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return s->uATARegNSectorHOB << 8 | s->uATARegNSector;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return 256;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void ataCmdOK(ATADevState *s, uint8_t status)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync s->uATARegError = 0; /* Not needed by ATA spec, but cannot hurt. */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic void ataCmdError(ATADevState *s, uint8_t uErrorCode)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[1] = RT_H2LE_U16(RT_MIN(s->PCHSGeometry.cCylinders, 16383));
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync /* Block size; obsolete, but required for the BIOS. */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync ataPadString((uint8_t *)(p + 27), "VBOX HARDDISK", 40); /* model */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsync p[54] = RT_H2LE_U16(RT_MIN(s->PCHSGeometry.cCylinders, 16383));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync p[57] = RT_H2LE_U16( RT_MIN(s->PCHSGeometry.cCylinders, 16383)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[58] = RT_H2LE_U16( RT_MIN(s->PCHSGeometry.cCylinders, 16383)
76f3a3817b6b96f5beb30b76efebdf2d87090cf0vboxsync /* Report maximum number of sectors possible with LBA28 */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 12); /* supports FLUSH CACHE */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[86] = RT_H2LE_U16(1 << 12); /* enabled FLUSH CACHE */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
8865793e4f3435f5e2c728d9e6739cd24d08c0devboxsync return false;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync return false;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Removable CDROM, 50us response, 12 byte packets */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
56970d3a1944c7c073d66266cd52449835221badvboxsync p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
56970d3a1944c7c073d66266cd52449835221badvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return false;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* put signature */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* any LBA variant */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* LBA48 */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync iLBA = ((s->uATARegSelect & 0x0f) << 24) | (s->uATARegHCyl << 16) |
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors +
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync (s->uATARegSelect & 0x0f) * s->PCHSGeometry.cSectors +
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic void ataSetSector(ATADevState *s, uint64_t iLBA)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* any LBA variant */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* LBA48 */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | (iLBA >> 24);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync cyl = iLBA / (s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync r = iLBA % (s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | ((r / s->PCHSGeometry.cSectors) & 0x0f);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync s->uATARegSector = (r % s->PCHSGeometry.cSectors) + 1;
23d8f7aff045c2bade1b168fee79a3e4749e2345vboxsyncstatic int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync STAM_REL_COUNTER_ADD(&s->StatBytesRead, cSectors * 512);
20f21077abf35d7b7b618acb159267933907407fvboxsyncstatic int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync rc = s->pDrvBlock->pfnWrite(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync STAM_REL_COUNTER_ADD(&s->StatBytesWritten, cSectors * 512);
56970d3a1944c7c073d66266cd52449835221badvboxsync false, "DevATA_DISKFULL",
56970d3a1944c7c073d66266cd52449835221badvboxsync N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
56970d3a1944c7c073d66266cd52449835221badvboxsyncstatic void ataWarningFileTooBig(PPDMDEVINS pDevIns)
56970d3a1944c7c073d66266cd52449835221badvboxsync false, "DevATA_FILETOOBIG",
56970d3a1944c7c073d66266cd52449835221badvboxsync N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
56970d3a1944c7c073d66266cd52449835221badvboxsync false, "DevATA_ISCSIDOWN",
56970d3a1944c7c073d66266cd52449835221badvboxsync N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
56970d3a1944c7c073d66266cd52449835221badvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
56970d3a1944c7c073d66266cd52449835221badvboxsync rc = ataReadSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
56970d3a1944c7c073d66266cd52449835221badvboxsync /* iSCSI connection abort (first error) or failure to reestablish
56970d3a1944c7c073d66266cd52449835221badvboxsync * connection (second error). Pause VM. On resume we'll retry. */
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk read error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
56970d3a1944c7c073d66266cd52449835221badvboxsync /** @todo implement redo for iSCSI */
56970d3a1944c7c073d66266cd52449835221badvboxsync return false;
56970d3a1944c7c073d66266cd52449835221badvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
56970d3a1944c7c073d66266cd52449835221badvboxsync rc = ataWriteSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
56970d3a1944c7c073d66266cd52449835221badvboxsync /* iSCSI connection abort (first error) or failure to reestablish
56970d3a1944c7c073d66266cd52449835221badvboxsync * connection (second error). Pause VM. On resume we'll retry. */
56970d3a1944c7c073d66266cd52449835221badvboxsync return true;
56970d3a1944c7c073d66266cd52449835221badvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk write error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
56970d3a1944c7c073d66266cd52449835221badvboxsync /** @todo implement redo for iSCSI */
56970d3a1944c7c073d66266cd52449835221badvboxsync return false;
56970d3a1944c7c073d66266cd52449835221badvboxsync | ((s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
56970d3a1944c7c073d66266cd52449835221badvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
56970d3a1944c7c073d66266cd52449835221badvboxsync memset(s->abATAPISense, '\0', sizeof(s->abATAPISense));
56970d3a1944c7c073d66266cd52449835221badvboxsyncstatic void atapiCmdError(ATADevState *s, const uint8_t *pabATAPISense, size_t cbATAPISense)
56970d3a1944c7c073d66266cd52449835221badvboxsync Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset(s->abATAPISense, '\0', sizeof(s->abATAPISense));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memcpy(s->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(s->abATAPISense)));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/** @todo deprecated function - doesn't provide enough info. Replace by direct
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * calls to atapiCmdError() with full data. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void atapiCmdErrorSimple(ATADevState *s, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdError(s, abATAPISense, sizeof(abATAPISense));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync /* @todo implement an algorithm for correctly determining the read and
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync * write sector size without sending additional commands to the drive.
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync * This should be doable by saving processing the configuration requests
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync * and replies. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (cmd == SCSI_WRITE_10 || cmd == SCSI_WRITE_12 || cmd == SCSI_WRITE_AND_VERIFY_10)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync aModeSenseCmd[1] = 0x08; /* disable block descriptor = 1 */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync aModeSenseCmd[2] = (SCSI_PAGECONTROL_CURRENT << 6) | SCSI_MODEPAGE_WRITE_PARAMETER;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aModeSenseCmd, PDMBLOCKTXDIR_FROM_DEVICE, aModeSenseResult, &cbTransfer, &uDummySense, 500);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_NONE);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Select sector size based on the current data block type. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync Log2(("%s: sector size %d\n", __FUNCTION__, s->cbATAPISector));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->cbIOBuffer);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, s->iATAPILBA));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTX_SUFF(pbIOBuffer), s->cbATAPISector * cSectors);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync /* sync bytes */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync STAM_REL_COUNTER_ADD(&s->StatBytesRead, s->cbATAPISector * cSectors);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* The initial buffer end value has been set up based on the total
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * transfer size. But the I/O buffer size limits what can actually be
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * done in one transfer, so set the actual value of the buffer end. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM read error, %d sectors at LBA %d\n", s->iLUN, cSectors, s->iATAPILBA));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_MEDIUM_ERROR, SCSI_ASC_READ_ERROR);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync Log3(("ATAPI PT data write (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Simple heuristics: if there is at least one sector of data
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * to transfer, it's worth updating the LEDs. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Linux accepts commands with up to 100KB of data, but expects
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * us to handle commands with up to 128KB of data. The usual
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * imbalance of powers. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync switch (s->aATAPICmd[0])
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cSectors = ataBE2H_U24(s->aATAPICmd + 6) / s->cbATAPISector;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cSectors = ataMSF2LBA(s->aATAPICmd + 6) - iATAPILBA;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", s->aATAPICmd[0]));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough split error\n", s->iLUN));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync memcpy(aATAPICmd, s->aATAPICmd, ATAPI_PACKET_SIZE);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync switch (s->aATAPICmd[0])
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, pbBuf, &cbCurrTX, abATAPISense, sizeof(abATAPISense), 30000 /**< @todo timeout */);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, s->aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, s->CTX_SUFF(pbIOBuffer), &cbTransfer, abATAPISense, sizeof(abATAPISense), 30000 /**< @todo timeout */);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Update the LEDs and the read/write statistics. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync STAM_REL_COUNTER_ADD(&s->StatBytesRead, cbTransfer);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync STAM_REL_COUNTER_ADD(&s->StatBytesWritten, cbTransfer);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Reply with the same amount of data as the real drive. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* The initial buffer end value has been set up based on the total
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * transfer size. But the I/O buffer size limits what can actually be
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * done in one transfer, so set the actual value of the buffer end. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Make sure that the real drive cannot be identified.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * Motivation: changing the VM configuration should be as
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * invisible as possible to the guest.
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * Exception: passthrough. Otherwise Windows will not detect
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync * CDR/CDRW burning capabilities */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Log3(("ATAPI PT inquiry data before (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ataSCSIPadStr(s->CTX_SUFF(pbIOBuffer) + 8, "VBOX", 8);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ataSCSIPadStr(s->CTX_SUFF(pbIOBuffer) + 16, "CD-ROM", 16);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ataSCSIPadStr(s->CTX_SUFF(pbIOBuffer) + 32, "1.0", 4);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Log3(("ATAPI PT data read (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTX_SUFF(pbIOBuffer)));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* don't log superflous errors */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync s->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync } while (0);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync atapiCmdError(s, abATAPISense, sizeof(abATAPISense));
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic bool atapiReadSectors(ATADevState *s, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ataStartTransfer(s, cSectors * cbSector, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ, true);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *s)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[5] = 1; /* first track number in last session (LSB) */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[6] = 1; /* last track number in last session (LSB) */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[7] = (0 << 7) | (0 << 6) | (1 << 5) | (0 << 2) | (0 << 0); /* disc id not valid, disc bar code not valid, unrestricted use, not dirty, not RW medium */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U32(pbBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U32(pbBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
f40cc8247b1da75ce42e73e6c557ec29b8f830a5vboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *s)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /* Accept address/number type of 1 only, and only track 1 exists. */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync if ((s->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&s->aATAPICmd[2]) != 1)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U32(pbBuf + 8, 0); /* track start address is 0 */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U32(pbBuf + 24, s->cTotalSectors); /* track size */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /* Accept valid request types only, and only starting feature 0. */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync if ((s->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&s->aATAPICmd[2]) != 0)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync * way to differentiate them right now is based on the image size). Also
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync * implement signalling "no current profile" if no medium is loaded. */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U16(pbBuf + 8, 0); /* feature 0: list of profiles supported */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /* The MMC-3 spec says that DVD-ROM read capability should be reported
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync * before CD-ROM read capability. */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U16(pbBuf + 12, 0x10); /* profile: read-only DVD */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync ataH2BE_U16(pbBuf + 16, 0x08); /* profile: read only CD */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync /* Other profiles we might want to add in the future: 0x40 (BD-ROM) and 0x50 (HDDVD-ROM) */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync#if 1/*ndef VBOX*/ /** @todo implement MESN + AENC. (async notification on removal and stuff.) */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync pbBuf[3] = 0x91; /* format 1, MESN=1, AENC=9 ??? */
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *s)
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync return false;
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *s)
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* The following claims we support audio play. This is obviously false,
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync * but the Linux generic CDROM support makes many features depend on this
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync * capability. If it's not set, this causes many things to be disabled. */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync pbBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync pbBuf[13] = 0x00; /* no subchannel reads supported */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync pbBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync pbBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[16], 5632); /* (obsolete) claim 32x speed support */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[18], 2); /* number of audio volume levels */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[20], s->cbIOBuffer / _1K); /* buffer size supported in Kbyte */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[22], 5632); /* (obsolete) current read speed 32x */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync pbBuf[25] = 0; /* reserved for digital audio (see idx 15) */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[26], 0); /* (obsolete) maximum write speed */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[28], 0); /* (obsolete) current write speed */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[30], 0); /* copy management revision supported 0=no CSS */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[36], 0); /* current write speed */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataH2BE_U16(&pbBuf[38], 0); /* number of write speed performance descriptors */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync return false;
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync memcpy(pbBuf, s->abATAPISense, RT_MIN(s->cbElementaryTransfer, sizeof(s->abATAPISense)));
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync return false;
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* no current LBA */
8f7ee9e453c60b3b699799538a45950b35266665vboxsync return false;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer), *q, iStartTrack;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return false;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync *q++ = 0; /* reserved */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync *q++ = 0; /* reserved */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* reserved */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* sector 0 */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* lead out track */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* reserved */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* reserved */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* reserved */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return false;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* multi session: only a single session defined */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/** @todo double-check this stuff against what a real drive says for a CD-ROM (not a CD-R) with only a single data session. Maybe solve the problem with "cdrdao read-toc" not being able to figure out whether numbers are in BCD or hex. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync pbBuf[6] = 1; /* first track in last complete session */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* sector 0 */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return false;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync uint8_t *pbBuf = s->CTX_SUFF(pbIOBuffer), *q, iStartTrack;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* track number */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* min */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* sec */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* frame */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync *q++ = 0; /* track number */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* min */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* sec */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* frame */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* track number */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* min */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* sec */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* frame */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* reserved */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *q++ = 0; /* track number */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* min */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* sec */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* frame */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync *q++ = 0; /* reserved */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* sector 0 */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return false;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void atapiParseCmdVirtualATAPI(ATADevState *s)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ataStartTransfer(s, RT_MIN(cbMax, 16), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, RT_MIN(cbMax, 40), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, RT_MIN(cbMax, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Rate limited logging, one log line per second. For
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * guests that insist on reading from places outside the
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * valid area this often generates too many release log
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * entries otherwise. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Rate limited logging, one log line per second. For
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * guests that insist on reading from places outside the
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync * valid area this often generates too many release log
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync * entries otherwise. */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /* nothing */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /* normal read */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /* read all data */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM sector format not supported\n", s->iLUN));
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Rate limited logging, one log line per second. For
d7cf060b16385dd6e5af7c74cd49c9ef8ffb3b22vboxsync * guests that insist on seeking to places outside the
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync * valid area this often generates too many release log
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * entries otherwise. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", s->iLUN, (uint64_t)iATAPILBA));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataSetStatus(s, ATA_STAT_SEEK); /* Linux expects this. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync case 0: /* 00 - Stop motor */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* This must be done from EMT. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (PFNRT)s->pDrvMount->pfnUnmount, 2, s->pDrvMount, false);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MECHANISM_STATUS, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * the other field is clear... */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_NORMAL, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, RT_MIN(cbMax, 12), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_MULTI, true);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_RAW, true);
56970d3a1944c7c073d66266cd52449835221badvboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ataStartTransfer(s, 8, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_CAPACITY, true);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync ataStartTransfer(s, RT_MIN(cbMax, 34), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_DISC_INFORMATION, true);
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION, true);
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync /* No media change stuff here, it can confuse Linux guests. */
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataStartTransfer(s, RT_MIN(cbMax, 32), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_CONFIGURATION, true);
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_INQUIRY, true);
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsync atapiCmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
4f4cb69bca6bfda8f4d911759d1f3c6f528a173dvboxsync * Parse ATAPI commands, passing them directly to the CD/DVD drive.
9540ab73f6cd0c76f44f6bbfe73f89ac145390b8vboxsyncstatic void atapiParseCmdPassthrough(ATADevState *s)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Disable this passthrough command. The guest should fallback to other means to
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * detect the disk status. We cannot emulate this command properly when in non-
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * passthrough mode. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
goto sendcmd;
case SCSI_PLAY_AUDIO_12:
goto sendcmd;
case SCSI_PLAY_AUDIO_MSF:
goto sendcmd;
goto sendcmd;
case SCSI_READ_10:
goto sendcmd;
case SCSI_READ_12:
goto sendcmd;
case SCSI_READ_BUFFER:
goto sendcmd;
goto sendcmd;
case SCSI_READ_CAPACITY:
goto sendcmd;
case SCSI_READ_CD:
goto sendcmd;
case SCSI_READ_CD_MSF:
cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
goto sendcmd;
goto sendcmd;
case SCSI_READ_DVD_STRUCTURE:
goto sendcmd;
goto sendcmd;
case SCSI_READ_SUBCHANNEL:
goto sendcmd;
case SCSI_READ_TOC_PMA_ATIP:
goto sendcmd;
goto sendcmd;
case SCSI_REPAIR_TRACK:
goto sendcmd;
case SCSI_REPORT_KEY:
goto sendcmd;
case SCSI_REQUEST_SENSE:
ataStartTransfer(s, RT_MIN(cbTransfer, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
goto sendcmd;
case SCSI_RESERVE_TRACK:
goto sendcmd;
case SCSI_SCAN:
goto sendcmd;
case SCSI_SEEK_10:
goto sendcmd;
case SCSI_SEND_CUE_SHEET:
goto sendcmd;
case SCSI_SEND_DVD_STRUCTURE:
goto sendcmd;
case SCSI_SEND_EVENT:
goto sendcmd;
case SCSI_SEND_KEY:
goto sendcmd;
goto sendcmd;
case SCSI_SET_CD_SPEED:
goto sendcmd;
case SCSI_SET_READ_AHEAD:
goto sendcmd;
case SCSI_SET_STREAMING:
goto sendcmd;
case SCSI_START_STOP_UNIT:
goto sendcmd;
case SCSI_STOP_PLAY_SCAN:
goto sendcmd;
case SCSI_SYNCHRONIZE_CACHE:
goto sendcmd;
case SCSI_TEST_UNIT_READY:
goto sendcmd;
case SCSI_VERIFY_10:
goto sendcmd;
case SCSI_WRITE_10:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_12:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_AND_VERIFY_10:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_BUFFER:
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", s->iLUN));
goto sendcmd;
goto sendcmd;
case SCSI_REZERO_UNIT:
if (cbTransfer == 0)
ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
#ifdef DEBUG
Log(("%s: LUN#%d DMA=%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0], SCSICmdText(pbPacket[0])));
Log2(("%s: limit=%#x packet: %.*Vhxs\n", __FUNCTION__, s->uATARegLCyl | (s->uATARegHCyl << 8), ATAPI_PACKET_SIZE, pbPacket));
if (s->fATAPIPassthrough)
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
atapiParseCmd(s);
s->cNotifiedMediaChange = 0;
ataUnsetIRQ(s);
ataSetSignature(s);
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferPIODataStart = 0;
s->iIOBufferPIODataEnd = 0;
s->fATAPITransfer = false;
s->uATARegFeature = 0;
ataSetSignature(s);
if (s->fATAPI)
#ifdef DEBUG
s->fLBA48 = false;
s->fDMA = false;
if (s->u64CmdTS)
switch (cmd)
case ATA_IDENTIFY_DEVICE:
if (s->fATAPI)
ataSetSignature(s);
case ATA_RECALIBRATE:
case ATA_SET_MULTIPLE_MODE:
if ( s->uATARegNSector != 0
ataCmdOK(s, 0);
s->fLBA48 = true;
case ATA_READ_VERIFY_SECTORS:
ataCmdOK(s, 0);
case ATA_READ_SECTORS_EXT:
s->fLBA48 = true;
case ATA_READ_SECTORS:
if (!s->pDrvBlock)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_SECTORS_EXT:
s->fLBA48 = true;
case ATA_WRITE_SECTORS:
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
case ATA_READ_MULTIPLE_EXT:
s->fLBA48 = true;
case ATA_READ_MULTIPLE:
if (!s->cMultSectors)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_MULTIPLE_EXT:
s->fLBA48 = true;
case ATA_WRITE_MULTIPLE:
if (!s->cMultSectors)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
case ATA_READ_DMA_EXT:
s->fLBA48 = true;
case ATA_READ_DMA:
if (!s->pDrvBlock)
goto abort_cmd;
s->fDMA = true;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_DMA_EXT:
s->fLBA48 = true;
case ATA_WRITE_DMA:
if (!s->pDrvBlock)
goto abort_cmd;
s->fDMA = true;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
s->fLBA48 = true;
ataCmdOK(s, 0);
ataCmdOK(s, 0);
ataCmdOK(s, 0);
case ATA_CHECK_POWER_MODE:
ataCmdOK(s, 0);
case ATA_SET_FEATURES:
if (!s->pDrvBlock)
goto abort_cmd;
switch (s->uATARegFeature)
s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_MDMA_MODE_MAX);
s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_UDMA_MODE_MAX);
goto abort_cmd;
goto abort_cmd;
s->uATARegFeature = 0;
case ATA_FLUSH_CACHE_EXT:
case ATA_FLUSH_CACHE:
goto abort_cmd;
case ATA_STANDBY_IMMEDIATE:
ataCmdOK(s, 0);
case ATA_IDLE_IMMEDIATE:
ataAbortCurrentCommand(s, false);
if (s->fATAPI)
ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC, false);
case ATA_DEVICE_RESET:
if (!s->fATAPI)
goto abort_cmd;
ataAbortCurrentCommand(s, true);
case ATA_PACKET:
if (!s->fATAPI)
goto abort_cmd;
goto abort_cmd;
ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
switch (addr)
Log2(("%s: LUN#%d asserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
Log2(("%s: LUN#%d deasserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return VINF_SUCCESS;
bool fHOB;
if (!s->pDrvBlock)
val = 0;
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
val = 0;
static unsigned cBusy = 0;
if (!s->pDrvBlock)
val = 0;
#ifdef IN_RING3
cBusy = 0;
cBusy = 0;
return VINF_IOM_HC_IOPORT_READ;
cBusy = 0;
ataUnsetIRQ(s);
return VINF_SUCCESS;
val = 0;
return val;
#ifndef IN_RING3
#ifdef IN_RING3
LogRel(("PIIX3 ATA: Ctl#%d: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
#ifdef IN_RING3
Log2(("%s: LUN#%d asserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
Log2(("%s: LUN#%d deasserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
return VINF_SUCCESS;
#ifdef IN_RING3
ATADevState *s;
LogRel(("PIIX3 ATA: LUN#%d: %s data in the middle of a PIO transfer - VERY SLOW\n", s->iLUN, s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "loading" : "storing"));
bool fRedo;
s->iIOBufferCur = 0;
if (s->cbTotalTransfer)
if (s->fATAPITransfer)
Log2(("%s: Ctl#%d: suppressed continuing PIO transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
Log2(("%s: Ctl#%d: message to async I/O thread, continuing PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
if (s->cbTotalTransfer)
ataSetIRQ(s);
Log2(("%s: Ctl#%d: skipping message to async I/O thread, ending PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
uint8_t *p;
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return VINF_SUCCESS;
uint8_t *p;
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_READ;
return VINF_SUCCESS;
#ifdef IN_RING3
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
bool fRedo;
bool fLastDesc = false;
if (cbBuffer == 0)
iIOBufferCur = 0;
LogRel(("PIIX3 ATA: Ctl#%d: ABORT DMA%s\n", ATACONTROLLER_IDX(pCtl), pCtl->fReset ? " due to RESET" : ""));
if (fLastDesc)
int rc;
ATADevState *s;
Log2(("%s: Ctl#%d: state=%d, req=%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), pCtl->uAsyncIOState, ReqType));
AssertReleaseMsg(ReqType == ATA_AIO_RESET_ASSERTED || ReqType == ATA_AIO_RESET_CLEARED || ReqType == ATA_AIO_ABORT || pCtl->uAsyncIOState == ReqType, ("I/O state inconsistent: state=%d request=%d\n", pCtl->uAsyncIOState, ReqType));
switch (ReqType)
case ATA_AIO_NEW:
s->iIOBufferEnd = 0;
if (s->fATAPI)
if (s->fDMA)
if (s->fDMA)
s->iIOBufferCur = 0;
bool fRedo;
ataCmdOK(s, 0);
if (s->fDMA)
if (s->cbTotalTransfer)
Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer immediately\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
ataSetIRQ(s);
if (s->cbTotalTransfer)
ataSetIRQ(s);
Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
if (!s->fATAPITransfer)
ataSetIRQ(s);
case ATA_AIO_DMA:
s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
ATAFNSS iOriginalSourceSink = (ATAFNSS)s->iSourceSink; /* Used by the hack below, but gets reset by then. */
&& s->cbTotalTransfer == 0
if (s->fATAPITransfer)
Log2(("%s: Ctl#%d: interrupt reason %#04x\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegNSector));
s->fATAPITransfer = false;
ataSetIRQ(s);
case ATA_AIO_PIO:
s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
bool fRedo;
s->iIOBufferCur = 0;
if (s->cbTotalTransfer)
ataSetIRQ(s);
&& !s->fATAPITransfer
ataSetIRQ(s);
case ATA_AIO_RESET_ASSERTED:
case ATA_AIO_RESET_CLEARED:
case ATA_AIO_ABORT:
ataResetDevice(s);
ataSetIRQ(s);
Log(("%s: Ctl#%d: LUN#%d finished I/O transaction in %d microseconds\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), pCtl->aIfs[pCtl->iAIOIf].iLUN, (uint32_t)(uWait)));
LogRel(("PIIX3 ATA: execution time for ATA command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].uATARegCommand, uWait / (1000 * 1000)));
LogRel(("PIIX3 ATA: execution time for ATAPI command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].aATAPICmd[0], uWait / (1000 * 1000)));
return rc;
return val;
#ifdef IN_RING3
Log2(("%s: Ctl#%d: suppressed continuing DMA transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
return val;
return val;
PDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
int rc;
return rc;
return VERR_IOM_IOPORT_UNUSED;
return rc;
PDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
int rc;
return rc;
#ifndef IN_RING3
default: AssertMsgFailed(("%s: Unsupported write to port %x size=%d val=%x\n", __FUNCTION__, Port, cb, u32)); break;
return rc;
#ifdef IN_RING3
static DECLCALLBACK(int) ataBMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
return rc;
static DECLCALLBACK(void *) ataStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_LED_PORTS:
return NULL;
static DECLCALLBACK(int) ataStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
switch (iLUN)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_BLOCK_PORT:
return NULL;
PDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return rc;
return rc;
PDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return rc;
return rc;
#ifndef IN_RING0
PDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
return rc;
#ifndef IN_RING3
#ifdef IN_GC
MMGCRamWriteNoTrapHandler((char *)GCDst + i, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, cb);
rc = PGMPhysWriteGCPtrDirty(PDMDevHlpGetVM(pDevIns), GCDst, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
#ifdef IN_RING3
return rc;
PDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
int rc;
return rc;
#ifndef IN_RING3
#ifdef IN_GC
MMGCRamReadNoTrapHandler(s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, (char *)GCSrc + i, cb);
rc = PGMPhysReadGCPtr(PDMDevHlpGetVM(pDevIns), s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
#ifdef IN_RING3
return rc;
PDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
int rc;
return VINF_SUCCESS;
return rc;
return rc;
PDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
int rc;
return VERR_IOM_IOPORT_UNUSED;
return rc;
return VINF_SUCCESS;
#ifdef IN_RING3
bool fVMLocked;
bool fAllIdle = false;
if (fVMLocked)
fAllIdle = true;
if (!fAllIdle)
if ( fAllIdle
if (fVMLocked)
if (!fAllIdle)
return fAllIdle;
if (s->pbIOBufferR3)
int rc;
return VINF_SUCCESS;
unsigned iController;
unsigned iInterface;
AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
int rc;
return VERR_PDM_MISSING_INTERFACE;
pIf->pDrvBlockBios = (PDMIBLOCKBIOS *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
return VERR_PDM_MISSING_INTERFACE;
AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd-rom. enmType=%d\n", pIf->iLUN, enmType));
return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
return VERR_INTERNAL_ERROR;
rc = MMHyperAlloc(pVM, pIf->cbIOBuffer, 1, MM_TAG_PDM_DEVICE_USER, (void **)&pIf->pbIOBufferR3); /** @todo rainy day: change to MMR3HyperAllocOnceNoRel */
return VERR_NO_MEMORY;
LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
LogRel(("PIIX3 ATA: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n", pIf->iLUN, pIf->PCHSGeometry.cCylinders, pIf->PCHSGeometry.cHeads, pIf->PCHSGeometry.cSectors, pIf->cTotalSectors));
return VINF_SUCCESS;
int rc;
unsigned iController;
unsigned iInterface;
AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
return rc;
int rc;
return VERR_SSM_IDE_ASYNC_TIMEOUT;
return VINF_SUCCESS;
SSMR3PutMem(pSSMHandle, &pThis->aCts[i].aIfs[j].aATAPICmd, sizeof(pThis->aCts[i].aIfs[j].aATAPICmd));
SSMR3PutMem(pSSMHandle, &pThis->aCts[i].aIfs[j].abATAPISense, sizeof(pThis->aCts[i].aIfs[j].abATAPISense));
SSMR3PutMem(pSSMHandle, pThis->aCts[i].aIfs[j].CTX_SUFF(pbIOBuffer), pThis->aCts[i].aIfs[j].cbIOBuffer);
static DECLCALLBACK(int) ataLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
int rc;
return rc;
SSMR3GetMem(pSSMHandle, &pThis->aCts[i].aIfs[j].aATAPICmd, sizeof(pThis->aCts[i].aIfs[j].aATAPICmd));
SSMR3GetMem(pSSMHandle, pThis->aCts[i].aIfs[j].abATAPISense, sizeof(pThis->aCts[i].aIfs[j].abATAPISense));
SSMR3GetMem(pSSMHandle, pThis->aCts[i].aIfs[j].CTX_SUFF(pbIOBuffer), pThis->aCts[i].aIfs[j].cbIOBuffer);
return VERR_SSM_LOAD_CONFIG_MISMATCH;
while (cbLeft-- > 0)
return rc;
if (u32 != ~0U)
return rc;
return VINF_SUCCESS;
int rc;
bool fGCEnabled;
bool fR0Enabled;
PCIDevSetCommand( &pThis->dev, PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER);
PCIDevSetClassProg( &pThis->dev, 0x8a); /* programming interface = PCI_IDE bus master is supported */
if (fGCEnabled)
if (fR0Enabled)
if (fGCEnabled)
if (fR0Enabled)
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATADMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA DMA transfers.", "/Devices/ATA%d/Unit%d/DMA", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA PIO transfers.", "/Devices/ATA%d/Unit%d/PIO", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI DMA transfers.", "/Devices/ATA%d/Unit%d/AtapiDMA", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI PIO transfers.", "/Devices/ATA%d/Unit%d/AtapiPIO", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatReads, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the read operations.", "/Devices/ATA%d/Unit%d/Reads", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/ATA%d/Unit%d/ReadBytes", i, j);
#ifdef VBOX_INSTRUMENT_DMA_WRITES
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatInstrVDWrites,STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the VD DMA write operations.","/Devices/ATA%d/Unit%d/InstrVDWrites", i, j);
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatWrites, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the write operations.","/Devices/ATA%d/Unit%d/Writes", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/ATA%d/Unit%d/WrittenBytes", i, j);
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatFlushes, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the flush operations.","/Devices/ATA%d/Unit%d/Flushes", i, j);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatAsyncOps, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "The number of async operations.", "/Devices/ATA%d/Async/Operations", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatAsyncMinWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Minimum wait in microseconds.", "/Devices/ATA%d/Async/MinWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatAsyncMaxWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Maximum wait in microseconds.", "/Devices/ATA%d/Async/MaxWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatAsyncTimeUS, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Total time spent in microseconds.","/Devices/ATA%d/Async/TotalTimeUS", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatAsyncTime, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of async operations.", "/Devices/ATA%d/Async/Time", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aCts[i].StatLockWait, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of locks.", "/Devices/ATA%d/Async/LockWait", i);
pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
rc = RTThreadCreate(&pCtl->AsyncIOThread, ataAsyncIOLoop, (void *)pCtl, 128*1024, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ATA");
Assert(pCtl->AsyncIOThread != NIL_RTTHREAD && pCtl->AsyncIOSem != NIL_RTSEMEVENT && pCtl->SuspendIOSem != NIL_RTSEMEVENT && pCtl->AsyncIORequestMutex != NIL_RTSEMMUTEX);
Log(("%s: controller %d AIO thread id %#x; sem %p susp_sem %p mutex %p\n", __FUNCTION__, i, pCtl->AsyncIOThread, pCtl->AsyncIOSem, pCtl->SuspendIOSem, pCtl->AsyncIORequestMutex));
switch (rc)
case VERR_ACCESS_DENIED:
return rc;
s_apszDescs[i][j]);
return VINF_SUCCESS;
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
sizeof(PCIATAState),
NULL,
NULL,
NULL,
NULL,