DevATA.cpp revision 02231256307de4accd9cbe28fc13435d32a8cac9
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VBox storage devices:
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * ATA/ATAPI controller device (disk and cdrom).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Copyright (C) 2006 InnoTek Systemberatung GmbH
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * available from http://www.virtualbox.org. This file is free software;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * you can redistribute it and/or modify it under the terms of the GNU
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * General Public License as published by the Free Software Foundation,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * If you received this file as part of a commercial VirtualBox
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * distribution, then only the terms of your commercial VirtualBox
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * license agreement apply instead of the previous paragraph.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Header Files *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync*******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#endif /* IN_RING3 */
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync * Set to 1 to disable multi-sector read support. According to the ATA
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * specification this must be a power of 2 and it must fit in an 8 bit
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync * Fastest PIO mode supported by the drive.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Fastest MDMA mode supported by the drive.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Fastest UDMA mode supported by the drive.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The SSM saved state version.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/** The maximum number of release log entries per device. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct ATADevState {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Flag indicating whether the current command uses LBA48 mode. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Flag indicating whether this drive implements the ATAPI command set. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Set if this interface has asserted the IRQ. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Currently configured number of sectors in a multi-sector transfer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** LCHS disk geometry. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Number of sectors to transfer per IRQ. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Total number of sectors on this disk. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 1: feature (write-only). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 1: feature, high order byte. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 1: error (read-only). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 2: sector count (read/write). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 2: sector count, high order byte. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 3: sector, high order byte. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** ATA/ATAPI register 4: cylinder low (read/write). */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** ATA/ATAPI register 4: cylinder low, high order byte. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 5: cylinder high (read/write). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 5: cylinder high, high order byte. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 6: select drive/head (read/write). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 7: status (read-only). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI register 7: command (write-only). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI drive control register (write-only). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Current transfer direction. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Index of callback for begin transfer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Index of callback for source/sink of data. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Flag indicating whether the current command transfers data in DMA mode. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Set to indicate that ATAPI transfer semantics must be used. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Total ATA/ATAPI transfer size, shared PIO/DMA. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Elementary ATA/ATAPI transfer size, shared PIO/DMA. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** First element beyond end of valid buffer content, shared PIO/DMA. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI current PIO read/write buffer position. Not shared with DMA for safety reasons. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI current PIO read/write transfer position. Not shared with DMA for safety reasons. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATA/ATAPI current PIO read/write transfer end. Not shared with DMA for safety reasons. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** ATAPI current LBA position. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** ATAPI current sector size. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATAPI current command. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATAPI sense key. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** ATAPI additional sense code. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The status LED state for this drive. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Size of I/O buffer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the I/O buffer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the I/O buffer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * No data that is part of the saved state after this point!!!!!
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Statistics: number of read operations and the time spent reading. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Statistics: number of bytes read. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Statistics: number of write operations and the time spent writing. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Statistics: number of bytes written. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Statistics: number of flush operations and the time spend flushing. */
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync /** Enable passing through commands directly to the ATAPI drive. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Number of errors we've reported to the release log.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This is to prevent flooding caused by something going horribly wrong.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * this value against MAX_LOG_REL_ERRORS in places likely to cause floods
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * like the ones we currently seeing on the linux smoke tests (2006-11-10). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the attached driver's base interface. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the attached driver's block interface. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the attached driver's block bios interface. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the attached driver's mount interface.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This is NULL if the driver isn't a removable unit. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** The base interface. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** The block port interface. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** The mount notify interface. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** The LUN #. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** Pointer to device instance. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** Pointer to device instance. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** Pointer to controller instance. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** Pointer to controller instance. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsynctypedef enum
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** Begin a new transfer. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** Continue a DMA transfer. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** Continue a PIO transfer. */
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync /** Reset the drives on current controller, stop all transfer activity. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** Reset the drives on current controller, resume operation. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** Abort the current transfer of a particular drive. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct ATARequest
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** The base of the first I/O Port range. */
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync /** The base of the second I/O Port range. (0 if none) */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** The assigned IRQ. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Access critical section */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Selected drive. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /** The interface on which to handle async I/O. */
5ebbcc31dcb3fc3d11423fe2133930f74d2c0695vboxsync /** The state of the async I/O thread. */
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync /** Flag indicating whether the next transfer is part of the current command. */
5ebbcc31dcb3fc3d11423fe2133930f74d2c0695vboxsync /** Set when the reset processing is currently active on this controller. */
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync bool volatile fReset;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The BusMaster DMA state. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The ATA/ATAPI interfaces of this controller. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to device instance. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to device instance. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Set when the destroying the device instance and the thread must exit. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The async I/O thread handle. NIL_RTTHREAD if no thread. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The event semaphore the thread is waiting on for requests. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The request queue for the AIO thread. One element is always unused. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The position at which to insert a new request for the AIO thread. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The position at which to get a new request for the AIO thread. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The mutex protecting the request queue. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Magic delay before triggering interrupts in DMA mode. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /* Statistics */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct PCIATAState {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The controllers. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to device instance. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Status Port - Base interface. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Status Port - Leds interface. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Partner of ILeds. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Flag whether GC is enabled. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Flag whether R0 is enabled. */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync#define ATADEVSTATE_2_CONTROLLER(pIf) ( (pIf)->CTXSUFF(pController) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define ATADEVSTATE_2_DEVINS(pIf) ( (pIf)->CTXSUFF(pDevIns) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define CONTROLLER_2_DEVINS(pController) ( (pController)->CTXSUFF(pDevIns) )
dc33c504f9416c9620c5c2e327bce41f2aea63e8vboxsync#define PDMIBASE_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, IBase)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PDMILEDPORTS_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, ILeds)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PDMIBASE_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IBase)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PDMIBLOCKPORT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IPort)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PDMIMOUNT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMount)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PDMIMOUNTNOTIFY_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMountNotify)) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define PCIDEV_2_PCIATASTATE(pPciDev) ( (PCIATAState *)(pPciDev) )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#define ATACONTROLLER_IDX(pController) ( (pController) - PDMINS2DATA(CONTROLLER_2_DEVINS(pController), PCIATAState *)->aCts )
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Internal Functions *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, unsigned *pcTransfer, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsyncDECLINLINE(void) ataSetStatusValue(ATADevState *s, uint8_t stat)
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync /* Freeze status register contents while processing RESET. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncDECLINLINE(void) ataSetStatus(ATADevState *s, uint8_t stat)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /* Freeze status register contents while processing RESET. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
3a2aedd9e337c0cc515ce501a066359ba2f9505cvboxsyncDECLINLINE(void) ataUnsetStatus(ATADevState *s, uint8_t stat)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /* Freeze status register contents while processing RESET. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void ataExecuteDeviceDiagnosticSS(ATADevState *);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void atapiModeSenseErrorRecoverySS(ATADevState *);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void atapiModeSenseCDStatusSS(ATADevState *);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void atapiReadDiscInformationSS(ATADevState *);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void atapiReadTrackInformationSS(ATADevState *);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Begin of transfer function indexes for g_apfnBeginTransFuncs.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Array of end transfer functions, the index is ATAFNET.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Make sure ATAFNET and this array match!
8e2e6c9f8f2157e3ec6599f87343bdc453734c4cvboxsyncstatic const PBeginTransferFunc g_apfnBeginTransFuncs[ATAFN_BT_MAX] =
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Source/sink function indexes for g_apfnSourceSinkFuncs.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Array of source/sink functions, the index is ATAFNSS.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Make sure ATAFNSS and this array match!
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const PSourceSinkFunc g_apfnSourceSinkFuncs[ATAFN_SS_MAX] =
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const ATARequest ataDMARequest = { ATA_AIO_DMA, };
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const ATARequest ataPIORequest = { ATA_AIO_PIO, };
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const ATARequest ataResetARequest = { ATA_AIO_RESET_ASSERTED, };
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const ATARequest ataResetCRequest = { ATA_AIO_RESET_CLEARED, };
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void ataAsyncIOClearRequests(PATACONTROLLER pCtl)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsyncstatic void ataAsyncIOPutRequest(PATACONTROLLER pCtl, const ATARequest *pReq)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Assert((pCtl->AsyncIOReqHead + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests) != pCtl->AsyncIOReqTail);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync memcpy(&pCtl->aAsyncIORequests[pCtl->AsyncIOReqHead], pReq, sizeof(*pReq));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pCtl->AsyncIOReqHead %= RT_ELEMENTS(pCtl->aAsyncIORequests);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /* For some reason the lower-priority EMT can starve the async I/O
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * thread. We're holding the CritSect currently, so the async I/O
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * thread cannot immediately start processing, but it avoids the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * starvation. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#endif /* __LINUX__ */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic const ATARequest *ataAsyncIOGetCurrentRequest(PATACONTROLLER pCtl)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pReq = &pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail];
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Remove the request with the given type, as it's finished. The request
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * is not removed blindly, as this could mean a RESET request that is not
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * yet processed (but has cleared the request queue) is lost.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pCtl Controller for which to remove the request.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param ReqType Type of the request to remove.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void ataAsyncIORemoveCurrentRequest(PATACONTROLLER pCtl, ATAAIO ReqType)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail && pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail].ReqType == ReqType)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pCtl->AsyncIOReqTail %= RT_ELEMENTS(pCtl->aAsyncIORequests);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Dump the request queue for a particular controller. First dump the queue
8e2e6c9f8f2157e3ec6599f87343bdc453734c4cvboxsync * contents, then the already processed entries, as long as they haven't been
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * overwritten.
8e2e6c9f8f2157e3ec6599f87343bdc453734c4cvboxsync * @param pCtl Controller for which to dump the queue.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic void ataAsyncIODumpRequests(PATACONTROLLER pCtl)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync LogRel(("PIIX3 ATA: Ctl#%d: request queue dump (topmost is current):\n", ATACONTROLLER_IDX(pCtl)));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync LogRel(("PIIX3 ATA: Ctl#%d: processed requests (topmost is oldest):\n", ATACONTROLLER_IDX(pCtl)));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync 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));
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync LogRel(("abort request, iIf=%d fResetDrive=%d\n", pCtl->aAsyncIORequests[curr].u.a.iIf, pCtl->aAsyncIORequests[curr].u.a.fResetDrive));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync LogRel(("unknown request %d\n", pCtl->aAsyncIORequests[curr].ReqType));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync curr = (curr + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Checks whether the request queue for a particular controller is empty
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * or whether a particular controller is idle.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pCtl Controller for which to check the queue.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param fStrict If set then the controller is checked to be idle.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic bool ataAsyncIOIsIdle(PATACONTROLLER pCtl, bool fStrict)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync fIdle = (pCtl->AsyncIOReqHead == pCtl->AsyncIOReqTail);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Send a transfer request to the async I/O thread.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param s Pointer to the ATA device state data.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param cbTotalTransfer Data transfer size.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param uTxDir Data transfer direction.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param iBeginTransfer Index of BeginTransfer callback.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param iSourceSink Index of SourceSink callback.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param fChainedTransfer Whether this is a transfer that is part of the previous command/transfer.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataStartTransfer(ATADevState *s, uint32_t cbTotalTransfer, uint8_t uTxDir, ATAFNBT iBeginTransfer, ATAFNSS iSourceSink, bool fChainedTransfer)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* Do not issue new requests while the RESET line is asserted. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: Ctl#%d: suppressed new request as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* If the controller is already doing something else right now, ignore
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * the command that is being submitted. Some broken guests issue commands
b377a71756cce9f39d25b561f72bfa33ce8a39devboxsync * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync LogRel(("PIIX3 IDE: guest issued command %#04x while controller busy\n", s->uATARegCommand));
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync * Kick the worker thread into action.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, new request\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Send an abort command request to the async I/O thread.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param s Pointer to the ATA device state data.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param fResetDrive Whether to reset the drive or just abort a command.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataAbortCurrentCommand(ATADevState *s, bool fResetDrive)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* Do not issue new requests while the RESET line is asserted. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: Ctl#%d: suppressed aborting command as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, abort command on LUN#%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->iLUN));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: LUN#%d asserting IRQ\n", __FUNCTION__, s->iLUN));
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync /* Only actually set the IRQ line if updating the currently selected drive. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /** @todo experiment with adaptive IRQ delivery: for reads it is
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * better to wait for IRQ delivery, as it reduces latency. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif /* IN_RING3 */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: LUN#%d deasserting IRQ\n", __FUNCTION__, s->iLUN));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* Only actually unset the IRQ line if updating the currently selected drive. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataPIOTransferStart(ATADevState *s, uint32_t start, uint32_t size)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: LUN#%d start %d size %d\n", __FUNCTION__, s->iLUN, start, size));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataPIOTransferLimitATAPI(ATADevState *s)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Log2(("%s: byte count limit=%d\n", __FUNCTION__, cbLimit));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* byte count limit must be even if this case */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return 65536;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return s->uATARegNSectorHOB << 8 | s->uATARegNSector;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return 256;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferPIO = 0;
s->iIOBufferEnd = 0;
uint16_t *p;
int rc;
if (s->cMultSectors)
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
int rc;
ataCmdOK(s, 0);
uint16_t *p;
int rc;
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
if (s->fATAPI)
else if (s->pDrvBlock)
s->uATARegLCyl = 0;
s->uATARegHCyl = 0;
if (s->fLBA48)
s->uATARegSector;
return iLBA;
if (s->fLBA48)
int rc;
return rc;
static int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
int rc;
return rc;
ataCmdOK(s, 0);
int rc;
int rc;
if (!s->cbTotalTransfer)
s->uATARegError = 0;
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferEnd = 0;
s->iIOBufferPIO = 0;
s->fATAPITransfer = true;
atapiCmdOK(s);
int rc;
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aModeSenseCmd, PDMBLOCKTXDIR_FROM_DEVICE, aModeSenseResult, &cbTransfer, &uDummySense, 500);
s->cbATAPISector = 0;
if (s->cbTotalTransfer == 0)
atapiCmdBT(s);
switch (s->cbATAPISector)
rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTXSUFF(pbIOBuffer), s->cbATAPISector * cSectors);
atapiCmdOK(s);
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM read error, %d sectors at LBA %d\n", s->iLUN, cSectors, s->iATAPILBA));
switch (s->aATAPICmd[0])
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
cReqSectors = 0;
cReqSectors = i;
switch (s->aATAPICmd[0])
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, pbBuf, &cbCurrTX, &uATAPISenseKey, 30000 /**< @todo timeout */);
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, s->aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, s->CTXSUFF(pbIOBuffer), &cbTransfer, &uATAPISenseKey, 30000 /**< @todo timeout */);
Log3(("ATAPI PT inquiry data before (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
if (cbTransfer)
atapiCmdOK(s);
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command (%#04x) error %d\n", s->iLUN, s->aATAPICmd[0], uATAPISenseKey));
static void atapiReadSectors(ATADevState *s, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
ataStartTransfer(s, cSectors * cbSector, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ, true);
atapiCmdOK(s);
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 */
atapiCmdOK(s);
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 */
pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
atapiCmdOK(s);
if (((s->aATAPICmd[1] & 0x03) != 0 && (s->aATAPICmd[1] & 0x03) != 1) || ataBE2H_U16(&s->aATAPICmd[2]) != 0)
atapiCmdOK(s);
atapiCmdOK(s);
atapiCmdOK(s);
pbBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
pbBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
atapiCmdOK(s);
atapiCmdOK(s);
atapiCmdOK(s);
bool fMSF;
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
if (fMSF)
atapiCmdOK(s);
bool fMSF;
/** @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. */
if (fMSF)
atapiCmdOK(s);
bool fMSF;
if (fMSF)
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
atapiCmdOK(s);
switch (pbPacket[0])
case SCSI_TEST_UNIT_READY:
if (s->cNotifiedMediaChange > 0)
atapiCmdOK(s);
case SCSI_MODE_SENSE_10:
switch (uPageControl)
case SCSI_PAGECONTROL_CURRENT:
switch (uPageCode)
ataStartTransfer(s, RT_MIN(cbMax, 16), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY, true);
case SCSI_MODEPAGE_CD_STATUS:
ataStartTransfer(s, RT_MIN(cbMax, 40), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS, true);
goto error_cmd;
goto error_cmd;
case SCSI_PAGECONTROL_DEFAULT:
goto error_cmd;
case SCSI_PAGECONTROL_SAVED:
case SCSI_REQUEST_SENSE:
ataStartTransfer(s, RT_MIN(cbMax, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
atapiCmdOK(s);
case SCSI_READ_10:
case SCSI_READ_12:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
if (cSectors == 0)
atapiCmdOK(s);
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
case SCSI_READ_CD:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
if (cSectors == 0)
atapiCmdOK(s);
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
atapiCmdOK(s);
case SCSI_SEEK_10:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", s->iLUN, (uint64_t)iATAPILBA));
atapiCmdOK(s);
case SCSI_START_STOP_UNIT:
atapiCmdOK(s);
case SCSI_MECHANISM_STATUS:
ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MECHANISM_STATUS, true);
case SCSI_READ_TOC_PMA_ATIP:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
switch (format)
ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_NORMAL, true);
ataStartTransfer(s, RT_MIN(cbMax, 12), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_MULTI, true);
ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_RAW, true);
case SCSI_READ_CAPACITY:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
ataStartTransfer(s, 8, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_CAPACITY, true);
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
ataStartTransfer(s, RT_MIN(cbMax, 34), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_DISC_INFORMATION, true);
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION, true);
case SCSI_GET_CONFIGURATION:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
ataStartTransfer(s, RT_MIN(cbMax, 32), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_CONFIGURATION, true);
case SCSI_INQUIRY:
ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_INQUIRY, true);
switch (pbPacket[0])
case SCSI_BLANK:
goto sendcmd;
case SCSI_CLOSE_TRACK_SESSION:
goto sendcmd;
case SCSI_ERASE_10:
goto sendcmd;
case SCSI_FORMAT_UNIT:
goto sendcmd;
case SCSI_GET_CONFIGURATION:
goto sendcmd;
goto sendcmd;
case SCSI_GET_PERFORMANCE:
goto sendcmd;
case SCSI_INQUIRY:
goto sendcmd;
case SCSI_LOAD_UNLOAD_MEDIUM:
goto sendcmd;
case SCSI_MECHANISM_STATUS:
goto sendcmd;
case SCSI_MODE_SELECT_10:
goto sendcmd;
case SCSI_MODE_SENSE_10:
goto sendcmd;
case SCSI_PAUSE_RESUME:
goto sendcmd;
case SCSI_PLAY_AUDIO_10:
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], g_apszSCSICmdNames[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);
#ifdef DEBUG
s->fLBA48 = false;
s->fDMA = false;
switch (cmd)
case ATA_IDENTIFY_DEVICE:
if (s->fATAPI)
ataSetSignature(s);
case ATA_RECALIBRATE:
case ATA_SET_MULTIPLE_MODE:
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);
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)
#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;
if (!s->pDrvBlock)
val = 0;
ataUnsetIRQ(s);
#ifdef IN_RING3
val = 0;
return val;
#ifndef IN_RING3
#ifdef IN_RING3
#ifdef IN_RING3
return VINF_SUCCESS;
#ifdef IN_RING3
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)));
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
static int ataGuessDiskLCHS(ATADevState *s, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
int rc;
return VERR_INVALID_PARAMETER;
return rc;
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
ATADevState *s;
} prd;
bool fLastPRD = false;
iOriginalSourceSink = (ATAFNSS)s->iSourceSink; /* Used by the hack below, but gets reset by then. */
iIOBufferDMA = 0;
for (cur_addr = bm->pvAddr; cur_addr + sizeof(prd) <= RT_ALIGN_32(bm->pvAddr + 1, _4K); cur_addr += sizeof(prd))
iIOBufferDMA = 0;
if (fLastPRD)
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 ? "storing" : "loading"));
s->iIOBufferPIO = 0;
if (s->cbTotalTransfer)
if (s->fATAPITransfer)
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;
s->iIOBufferPIO = 0;
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 */
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 */
s->iIOBufferPIO = 0;
if (s->cbTotalTransfer)
ataSetIRQ(s);
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, unsigned *pcTransfer, unsigned cb)
return rc;
#ifndef IN_RING3
#ifdef IN_GC
MMGCRamWriteNoTrapHandler((char *)GCDst + i, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, cb);
rc = PGMPhysWriteGCPtrDirty(pDevIns->pDevHlp->pfnGetVM(pDevIns), GCDst, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
#ifdef IN_RING3
return rc;
PDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb)
int rc;
return rc;
#ifndef IN_RING3
#ifdef IN_GC
MMGCRamReadNoTrapHandler(s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, (char *)GCSrc + i, cb);
rc = PGMPhysReadGCPtr(pDevIns->pDevHlp->pfnGetVM(pDevIns), s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(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)
return fAllIdle;
if (s->pbIOBufferHC)
bool fAllDone;
fAllDone = true;
if ( fAllDone
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(pDevIns->pDevHlp->pfnGetVM(pDevIns), pIf->cbIOBuffer, 1, MM_TAG_PDM_DEVICE_USER, (void **)&pIf->pbIOBufferHC);
return VERR_NO_MEMORY;
rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
if (VBOX_SUCCESS(rc) && pIf->cCHSHeads <= 16 /* if cCHSHeads > 16, it means that a BIOS LBA translation was active, so the default hardware geometry is OK. */
pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
LogRel(("PIIX3 ATA: LUN#%d: disk, CHS=%d/%d/%d, total number of sectors %Ld\n", pIf->iLUN, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors, 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;
return VERR_SSM_IDE_ASYNC_TIMEOUT;
return VINF_SUCCESS;
SSMR3PutMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
SSMR3PutMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
static DECLCALLBACK(int) ataLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
int rc;
return rc;
SSMR3GetMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
SSMR3GetMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
return rc;
if (u32 != ~0U)
return rc;
return VINF_SUCCESS;
int rc;
bool fGCEnabled;
bool fR0Enabled;
fGCEnabled = true;
fR0Enabled = true;
DelayIRQMillies = 0;
pData->aCts[i].aIfs[j].pControllerGC = MMHyperHC2GC(pDevIns->pDevHlp->pfnGetVM(pDevIns), &pData->aCts[i]);
if (fGCEnabled)
if (fR0Enabled)
if (fGCEnabled)
if (fR0Enabled)
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);
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);
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, &pData->aCts[i].StatAsyncOps, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "The number of async operations.", "/Devices/ATA%d/Async/Operations", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncMinWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Minimum wait in microseconds.", "/Devices/ATA%d/Async/MinWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncMaxWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Maximum wait in microseconds.", "/Devices/ATA%d/Async/MaxWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncTimeUS, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Total time spent in microseconds.","/Devices/ATA%d/Async/TotalTimeUS", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncTime, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of async operations.", "/Devices/ATA%d/Async/Time", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatLockWait, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of locks.", "/Devices/ATA%d/Async/LockWait", i);
pData->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
rc = RTThreadCreate(&pCtl->AsyncIOThread, ataAsyncIOLoop, (void *)pCtl, 128*1024, RTTHREADTYPE_IO, 0, "ATA");
Log(("%s: controller %d AIO thread id %#x; sem %p mutex %p\n", __FUNCTION__, i, pCtl->AsyncIOThread, pCtl->AsyncIOSem, pCtl->AsyncIORequestMutex));
switch (rc)
case VERR_ACCESS_DENIED:
return rc;
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,
NULL,