DevATA.cpp revision 94b9fffbd2877518c6e88b2ae3489c64dd4a770a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * VBox storage devices:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA/ATAPI controller device (disk and cdrom).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Copyright (C) 2006-2007 innotek GmbH
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * available from http://www.virtualbox.org. This file is free software;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * General Public License as published by the Free Software Foundation,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Header Files *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Set to 1 to disable multi-sector read support. According to the ATA
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * specification this must be a power of 2 and it must fit in an 8 bit
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest PIO mode supported by the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest MDMA mode supported by the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest UDMA mode supported by the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The SSM saved state version.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** The maximum number of release log entries per device. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct ATADevState {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether the current command uses LBA48 mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether this drive implements the ATAPI command set. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Set if this interface has asserted the IRQ. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Currently configured number of sectors in a multi-sector transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** PCHS disk geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Total number of sectors on this disk. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Number of sectors to transfer per IRQ. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: feature (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: feature, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: error (read-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 2: sector count (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 2: sector count, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 3: sector, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 4: cylinder low (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 4: cylinder low, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 5: cylinder high (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 5: cylinder high, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 6: select drive/head (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 7: status (read-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 7: command (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI drive control register (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Current transfer direction. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Index of callback for begin transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Index of callback for source/sink of data. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether the current command transfers data in DMA mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Set to indicate that ATAPI transfer semantics must be used. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Total ATA/ATAPI transfer size, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Elementary ATA/ATAPI transfer size, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Current read/write buffer position, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** First element beyond end of valid buffer content, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI current PIO read/write transfer position. Not shared with DMA for safety reasons. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI current PIO read/write transfer end. Not shared with DMA for safety reasons. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current LBA position. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current sector size. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current command. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI sense key. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI additional sense code. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The status LED state for this drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Size of I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPTR Aligmnent0; /**< Align the statistics at an 8-byte boundrary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * No data that is part of the saved state after this point!!!!!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATA DMA commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATA PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATAPI PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATAPI PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of read operations and the time spent reading. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of bytes read. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of write operations and the time spent writing. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of bytes written. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of flush operations and the time spend flushing. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Enable passing through commands directly to the ATAPI drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Number of errors we've reported to the release log.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is to prevent flooding caused by something going horribly wrong.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this value against MAX_LOG_REL_ERRORS in places likely to cause floods
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * like the ones we currently seeing on the linux smoke tests (2006-11-10). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Timestamp of last started command. 0 if no command pending. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's base interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's block interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's block bios interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's mount interface.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is NULL if the driver isn't a removable unit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The base interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The block port interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The mount notify interface. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The LUN #. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTUINT Alignment2; /**< Align pDevInsHC correctly. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to controller instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to controller instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef enum
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Begin a new transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Continue a DMA transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Continue a PIO transfer. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Reset the drives on current controller, stop all transfer activity. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Reset the drives on current controller, resume operation. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Abort the current transfer of a particular drive. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsynctypedef struct ATARequest
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The base of the first I/O Port range. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The base of the second I/O Port range. (0 if none) */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The assigned IRQ. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Access critical section */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Selected drive. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The interface on which to handle async I/O. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The state of the async I/O thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag indicating whether the next transfer is part of the current command. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Set when the reset processing is currently active on this controller. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the current transfer needs to be redone. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the redo suspend has been finished. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the DMA operation to be redone is the final transfer. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The BusMaster DMA state. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to first DMA descriptor. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to last DMA descriptor. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to current DMA buffer (for redo operations). */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Size of current DMA buffer (for redo operations). */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The ATA/ATAPI interfaces of this controller. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to device instance. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to device instance. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Set when the destroying the device instance and the thread must exit. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The async I/O thread handle. NIL_RTTHREAD if no thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The event semaphore the thread is waiting on for requests. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The request queue for the AIO thread. One element is always unused. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The position at which to insert a new request for the AIO thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The position at which to get a new request for the AIO thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t Alignment3[2]; /**< Explicit padding of the 2 byte gap. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Magic delay before triggering interrupts in DMA mode. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The mutex protecting the request queue. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The event semaphore the thread is waiting on during suspended I/O. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Statistics */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct PCIATAState {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The controllers. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Status Port - Base interface. */
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync /** Status Port - Leds interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Partner of ILeds. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag whether GC is enabled. */
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync /** Flag whether R0 is enabled. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether PIIX4 or PIIX3 is being emulated. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool Alignment0[HC_ARCH_BITS == 64 ? 6 : 2]; /**< Align the struct size. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATADEVSTATE_2_CONTROLLER(pIf) ( (pIf)->CTXSUFF(pController) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATADEVSTATE_2_DEVINS(pIf) ( (pIf)->CTXSUFF(pDevIns) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define CONTROLLER_2_DEVINS(pController) ( (pController)->CTXSUFF(pDevIns) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBASE_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, IBase)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMILEDPORTS_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, ILeds)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBASE_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IBase)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBLOCKPORT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IPort)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIMOUNT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMount)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIMOUNTNOTIFY_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMountNotify)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PCIDEV_2_PCIATASTATE(pPciDev) ( (PCIATAState *)(pPciDev) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATACONTROLLER_IDX(pController) ( (pController) - PDMINS2DATA(CONTROLLER_2_DEVINS(pController), PCIATAState *)->aCts )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Internal Functions *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ******************************************************************************/
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, unsigned *pcTransfer, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataSetStatusValue(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataSetStatus(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataUnsetStatus(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataExecuteDeviceDiagnosticSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Begin of transfer function indexes for g_apfnBeginTransFuncs.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Array of end transfer functions, the index is ATAFNET.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Make sure ATAFNET and this array match!
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const PBeginTransferFunc g_apfnBeginTransFuncs[ATAFN_BT_MAX] =
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Source/sink function indexes for g_apfnSourceSinkFuncs.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Array of source/sink functions, the index is ATAFNSS.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Make sure ATAFNSS and this array match!
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const PSourceSinkFunc g_apfnSourceSinkFuncs[ATAFN_SS_MAX] =
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataDMARequest = { ATA_AIO_DMA, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataPIORequest = { ATA_AIO_PIO, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataResetARequest = { ATA_AIO_RESET_ASSERTED, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataResetCRequest = { ATA_AIO_RESET_CLEARED, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIOClearRequests(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIOPutRequest(PATACONTROLLER pCtl, const ATARequest *pReq)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert((pCtl->AsyncIOReqHead + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests) != pCtl->AsyncIOReqTail);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memcpy(&pCtl->aAsyncIORequests[pCtl->AsyncIOReqHead], pReq, sizeof(*pReq));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqHead %= RT_ELEMENTS(pCtl->aAsyncIORequests);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogBird(("ata: %x: signalling\n", pCtl->IOPortBase1));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogBird(("ata: %x: schedule failed, rc=%Vrc\n", pCtl->IOPortBase1, rc));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest *ataAsyncIOGetCurrentRequest(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pReq = &pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail];
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Remove the request with the given type, as it's finished. The request
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * is not removed blindly, as this could mean a RESET request that is not
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * yet processed (but has cleared the request queue) is lost.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pCtl Controller for which to remove the request.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param ReqType Type of the request to remove.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIORemoveCurrentRequest(PATACONTROLLER pCtl, ATAAIO ReqType)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail && pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail].ReqType == ReqType)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqTail %= RT_ELEMENTS(pCtl->aAsyncIORequests);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Dump the request queue for a particular controller. First dump the queue
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * contents, then the already processed entries, as long as they haven't been
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * overwritten.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pCtl Controller for which to dump the queue.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIODumpRequests(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("PIIX3 ATA: Ctl#%d: request queue dump (topmost is current):\n", ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("PIIX3 ATA: Ctl#%d: processed requests (topmost is oldest):\n", ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync 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));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync LogRel(("abort request, iIf=%d fResetDrive=%d\n", pCtl->aAsyncIORequests[curr].u.a.iIf, pCtl->aAsyncIORequests[curr].u.a.fResetDrive));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync LogRel(("unknown request %d\n", pCtl->aAsyncIORequests[curr].ReqType));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync curr = (curr + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Checks whether the request queue for a particular controller is empty
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * or whether a particular controller is idle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCtl Controller for which to check the queue.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fStrict If set then the controller is checked to be idle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataAsyncIOIsIdle(PATACONTROLLER pCtl, bool fStrict)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync fIdle = (pCtl->AsyncIOReqHead == pCtl->AsyncIOReqTail);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Send a transfer request to the async I/O thread.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param s Pointer to the ATA device state data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cbTotalTransfer Data transfer size.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param uTxDir Data transfer direction.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iBeginTransfer Index of BeginTransfer callback.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iSourceSink Index of SourceSink callback.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fChainedTransfer Whether this is a transfer that is part of the previous command/transfer.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsyncstatic void ataStartTransfer(ATADevState *s, uint32_t cbTotalTransfer, uint8_t uTxDir, ATAFNBT iBeginTransfer, ATAFNSS iSourceSink, bool fChainedTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not issue new requests while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed new request as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* If the controller is already doing something else right now, ignore
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the command that is being submitted. Some broken guests issue commands
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 IDE: guest issued command %#04x while controller busy\n", s->uATARegCommand));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Kick the worker thread into action.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, new request\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Send an abort command request to the async I/O thread.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param s Pointer to the ATA device state data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fResetDrive Whether to reset the drive or just abort a command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataAbortCurrentCommand(ATADevState *s, bool fResetDrive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not issue new requests while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed aborting command as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, abort command on LUN#%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ\n", __FUNCTION__, s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if the interrupt
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * line is asserted. It monitors the line for a rising edge. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only actually set the IRQ line if updating the currently selected drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo experiment with adaptive IRQ delivery: for reads it is
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * better to wait for IRQ delivery, as it reduces latency. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ\n", __FUNCTION__, s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only actually unset the IRQ line if updating the currently selected drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransferStart(ATADevState *s, uint32_t start, uint32_t size)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d start %d size %d\n", __FUNCTION__, s->iLUN, start, size));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransferLimitATAPI(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: byte count limit=%d\n", __FUNCTION__, cbLimit));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->iIOBufferEnd - s->iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* byte count limit must be even if this case */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 65536;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return s->uATARegNSectorHOB << 8 | s->uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 256;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsyncstatic void ataCmdOK(ATADevState *s, uint8_t status)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = 0; /* Not needed by ATA spec, but cannot hurt. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataCmdError(ATADevState *s, uint8_t uErrorCode)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Generate a predictable serial for drives which don't have a UUID. */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[1] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Block size; obsolete, but required for the BIOS. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 27), "VBOX HARDDISK", 40); /* model */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[54] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[57] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[58] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report maximum number of sectors possible with LBA28 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 12); /* supports FLUSH CACHE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[86] = RT_H2LE_U16(1 << 12); /* enabled FLUSH CACHE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Generate a predictable serial for drives which don't have a UUID. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Removable CDROM, 50us response, 12 byte packets */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* put signature */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* any LBA variant */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA48 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iLBA = ((s->uATARegSelect & 0x0f) << 24) | (s->uATARegHCyl << 16) |
e6ad2e18e663b076aeabfec994947514566a7accvboxsync iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->cCHSHeads * s->cCHSSectors +
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSetSector(ATADevState *s, uint64_t iLBA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* any LBA variant */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA48 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | (iLBA >> 24);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | ((r / s->cCHSSectors) & 0x0f);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesRead, cSectors * 512);
e6ad2e18e663b076aeabfec994947514566a7accvboxsyncstatic int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
e6ad2e18e663b076aeabfec994947514566a7accvboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnWrite(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesWritten, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_DISKFULL",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataWarningFileTooBig(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_FILETOOBIG",
e6ad2e18e663b076aeabfec994947514566a7accvboxsync N_("Host system reported that the file size limit has been exceeded. VM execution is suspended. You need to move the file to a filesystem which allows bigger files"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_ISCSIDOWN",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataReadSectors(s, iLBA, s->CTXSUFF(pbIOBuffer), cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* iSCSI connection abort (first error) or failure to reestablish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * connection (second error). Pause VM. On resume we'll retry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk read error (rc=%Vrc iSector=%#RX64 cSectors=%#RX32)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement redo for iSCSI */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataWriteSectors(s, iLBA, s->CTXSUFF(pbIOBuffer), cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* iSCSI connection abort (first error) or failure to reestablish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * connection (second error). Pause VM. On resume we'll retry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk write error (rc=%Vrc iSector=%#RX64 cSectors=%#RX32)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement redo for iSCSI */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | ((s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiCmdError(ATADevState *s, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: sense=%#x asc=%#x\n", __FUNCTION__, uATAPISenseKey, uATAPIASC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* @todo implement an algorithm for correctly determining the read and
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * write sector size without sending additional commands to the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This should be doable by saving processing the configuration requests
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * and replies. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cmd == SCSI_WRITE_10 || cmd == SCSI_WRITE_12 || cmd == SCSI_WRITE_AND_VERIFY_10)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[1] = 0x08; /* disable block descriptor = 1 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[2] = (SCSI_PAGECONTROL_CURRENT << 6) | SCSI_MODEPAGE_WRITE_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aModeSenseCmd, PDMBLOCKTXDIR_FROM_DEVICE, aModeSenseResult, &cbTransfer, &uDummySense, 500);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_NONE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Select sector size based on the current data block type. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: sector size %d\n", __FUNCTION__, s->cbATAPISector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, s->iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTXSUFF(pbIOBuffer), s->cbATAPISector * cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sync bytes */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesRead, s->cbATAPISector * cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The initial buffer end value has been set up based on the total
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer size. But the I/O buffer size limits what can actually be
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * done in one transfer, so set the actual value of the buffer end. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM read error, %d sectors at LBA %d\n", s->iLUN, cSectors, s->iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_MEDIUM_ERROR, SCSI_ASC_READ_ERROR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("ATAPI PT data write (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Simple heuristics: if there is at least one sector of data
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * to transfer, it's worth updating the LEDs. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Linux accepts commands with up to 100KB of data, but expects
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * us to handle commands with up to 128KB of data. The usual
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * imbalance of powers. */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync switch (s->aATAPICmd[0])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U24(s->aATAPICmd + 6) / s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataMSF2LBA(s->aATAPICmd + 6) - iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", s->aATAPICmd[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough split error\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(aATAPICmd, s->aATAPICmd, ATAPI_PACKET_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (s->aATAPICmd[0])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, pbBuf, &cbCurrTX, &uATAPISenseKey, 30000 /**< @todo timeout */);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, s->aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, s->CTXSUFF(pbIOBuffer), &cbTransfer, &uATAPISenseKey, 30000 /**< @todo timeout */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Update the LEDs and the read/write statistics. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesWritten, cbTransfer);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Reply with the same amount of data as the real drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The initial buffer end value has been set up based on the total
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * transfer size. But the I/O buffer size limits what can actually be
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * done in one transfer, so set the actual value of the buffer end. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Make sure that the real drive cannot be identified.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Motivation: changing the VM configuration should be as
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * invisible as possible to the guest. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log3(("ATAPI PT inquiry data before (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 8, "VBOX", 8);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 16, "CD-ROM", 16);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 32, "1.0", 4);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log3(("ATAPI PT data read (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* don't log superflous errors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command (%#04x) error %d %Vrc\n", s->iLUN, u8Cmd, uATAPISenseKey, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync } while (0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This is a drive-reported error. atapiCmdError() sets both the error
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * error code in the ATA error register and in s->uATAPISenseKey. The
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * former is correct, the latter is not. Otherwise the drive would not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * get the next REQUEST SENSE command which is necessary to clear the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * error status of the drive. Easy fix: clear s->uATAPISenseKey. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadSectors(ATADevState *s, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cSectors * cbSector, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 1; /* first track number in last session (LSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[6] = 1; /* last track number in last session (LSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(pbBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(pbBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *s)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Accept address/number type of 1 only, and only track 1 exists. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ((s->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&s->aATAPICmd[2]) != 1)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync 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 */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(pbBuf + 8, 0); /* track start address is 0 */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(pbBuf + 24, s->cTotalSectors); /* track size */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Accept valid request types only, and only starting feature 0. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ((s->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&s->aATAPICmd[2]) != 0)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * way to differentiate them right now is based on the image size). Also
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * implement signalling "no current profile" if no medium is loaded. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U16(pbBuf + 8, 0); /* feature 0: list of profiles supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The MMC-3 spec says that DVD-ROM read capability should be reported
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * before CD-ROM read capability. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf + 12, 0x10); /* profile: read-only DVD */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf + 16, 0x08); /* profile: read only CD */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Other profiles we might want to add in the future: 0x40 (BD-ROM) and 0x50 (HDDVD-ROM) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if 1/*ndef VBOX*/ /** @todo implement MESN + AENC. (async notification on removal and stuff.) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0x91; /* format 1, MESN=1, AENC=9 ??? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *s)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync /* The following claims we support audio play. This is obviously false,
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * but the Linux generic CDROM support makes many features depend on this
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * capability. If it's not set, this causes many things to be disabled. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[13] = 0x00; /* no subchannel reads supported */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ataH2BE_U16(&pbBuf[16], 5632); /* (obsolete) claim 32x speed support */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[18], 2); /* number of audio volume levels */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[20], s->cbIOBuffer / _1K); /* buffer size supported in Kbyte */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[22], 5632); /* (obsolete) current read speed 32x */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[25] = 0; /* reserved for digital audio (see idx 15) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[26], 0); /* (obsolete) maximum write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[28], 0); /* (obsolete) current write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[30], 0); /* copy management revision supported 0=no CSS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[36], 0); /* current write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[38], 0); /* number of write speed performance descriptors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* no current LBA */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer), *q, iStartTrack;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* lead out track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return false;
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync /* multi session: only a single session defined */
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync/** @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. */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[6] = 1; /* first track in last complete session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return false;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer), *q, iStartTrack;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *q++ = 0; /* frame */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiParseCmdVirtualATAPI(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync ataStartTransfer(s, RT_MIN(cbMax, 16), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 40), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync /* Rate limited logging, one log line per second. For
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync * guests that insist on reading from places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Rate limited logging, one log line per second. For
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * guests that insist on reading from places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* nothing */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* normal read */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* read all data */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM sector format not supported\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Rate limited logging, one log line per second. For
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * guests that insist on seeking to places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", s->iLUN, (uint64_t)iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_SEEK); /* Linux expects this. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: /* 00 - Stop motor */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This must be done from EMT. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (PFNRT)s->pDrvMount->pfnUnmount, 2, s->pDrvMount, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MECHANISM_STATUS, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the other field is clear... */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_NORMAL, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 12), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_MULTI, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_RAW, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync ataStartTransfer(s, 8, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_CAPACITY, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 34), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_DISC_INFORMATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* No media change stuff here, it can confuse Linux guests. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 32), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_CONFIGURATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_INQUIRY, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Parse ATAPI commands, passing them directly to the CD/DVD drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiParseCmdPassthrough(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo do not forget to unlock when a VM is shut down */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6) / s->cbATAPISector * s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbTransfer, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* The sector size is determined by the async I/O thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* Preliminary, will be corrected once the sector size is known. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The sector size is determined by the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Preliminary, will be corrected once the sector size is known. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The sector size is determined by the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Preliminary, will be corrected once the sector size is known. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x07: /* download microcode with offsets and save */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x0e: /* download microcode with offsets and defer activation */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Obsolete command used by cdrecord. What else would one expect?
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This command is not sent to the drive, it is handled internally,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * as the Linux kernel doesn't like it (message "scsi: unknown
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * opcode 0x01" in syslog) and replies with a sense code of 0,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * which sends cdrecord to an endless loop. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync LogRel(("PIIX3 ATA: LUN#%d: passthrough unimplemented for command %#x\n", s->iLUN, pbPacket[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Send a command to the drive, passing data in/out as required. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d DMA=%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0], g_apszSCSICmdNames[pbPacket[0]]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !DEBUG */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d DMA=%d CMD=%#04x\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !DEBUG */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync Log2(("%s: limit=%#x packet: %.*Vhxs\n", __FUNCTION__, s->uATARegLCyl | (s->uATARegHCyl << 8), ATAPI_PACKET_SIZE, pbPacket));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(s->aATAPICmd, s->CTXSUFF(pbIOBuffer), ATAPI_PACKET_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Called when a media is mounted.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataMountNotify(PPDMIMOUNTNOTIFY pInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIMOUNTNOTIFY_2_ATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: changing LUN#%d\n", __FUNCTION__, pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Ignore the call if we're called while being attached. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report media changed in TEST UNIT and other (probably incorrect) places. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Called when a media is unmounted
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIMOUNTNOTIFY_2_ATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * present and 2 in which it is changed.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = ATA_MODE_UDMA | 2; /* PIIX3 supports only up to UDMA2 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataExecuteDeviceDiagnosticSS(ATADevState *s)
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync ataSetStatusValue(s, 0); /* NOTE: READY is _not_ set */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataParseCmd(ATADevState *s, uint8_t cmd)
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, cmd, g_apszATACmdNames[cmd]));
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync#else /* !DEBUG */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d CMD=%#04x\n", __FUNCTION__, s->iLUN, cmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !DEBUG */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->fDMA = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Detect Linux timeout recovery, first tries IDLE IMMEDIATE (which
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * would overwrite the failing command unfortunately), then RESET. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: IDLE IMMEDIATE, CmdIf=%#04x (%d usec ago)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_NULL, ATAFN_SS_IDENTIFY, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || (s->uATARegNSector & (s->uATARegNSector - 1)) != 0))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: set multi sector count to %d\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* do sector number check ? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSector(s, RT_MIN(s->cTotalSectors, 1 << 28) - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = 0xff; /* drive active or idle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: feature=%#x\n", __FUNCTION__, s->uATARegFeature));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: read look-ahead enable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: read look-ahead disable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0xcc: /* reverting to power-on defaults enable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: revert to power-on defaults enable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x66: /* reverting to power-on defaults disable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: revert to power-on defaults disable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* As per the ATA/ATAPI-6 specs, a write cache disable
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * command MUST flush the write buffers to disc. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_FLUSH, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: transfer mode %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_MDMA_MODE_MAX);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_UDMA_MODE_MAX);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * OS/2 workarond:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The OS/2 IDE driver from MCP2 appears to rely on the feature register being
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reset here. According to the specification, this is a driver bug as the register
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * contents are undefined after the call. This means we can just as well reset it.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_FLUSH, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: aborting current command\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* ATAPI commands */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_NULL, ATAFN_SS_ATAPI_IDENTIFY, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: performing device RESET\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* overlapping commands not supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Waits for a particular async I/O thread to complete whatever it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * is doing at the moment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns true on success.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns false when the thread is still processing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pData Pointer to the controller data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cMillies How long to wait (total).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for any pending async operation to finish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataIOPortWriteU8(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: write addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* NOTE: data is written to the two drives */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegFeatureHOB = pCtl->aIfs[0].uATARegFeature;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegFeatureHOB = pCtl->aIfs[1].uATARegFeature;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegNSectorHOB = pCtl->aIfs[0].uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegNSectorHOB = pCtl->aIfs[1].uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegSectorHOB = pCtl->aIfs[0].uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegSectorHOB = pCtl->aIfs[1].uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegLCylHOB = pCtl->aIfs[0].uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegLCylHOB = pCtl->aIfs[1].uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegHCylHOB = pCtl->aIfs[0].uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegHCylHOB = pCtl->aIfs[1].uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegSelect = (val & ~0x10) | 0xa0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* select another drive */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The IRQ line is multiplexed between the two drives, so
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * update the state when switching to another drive. Only need
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * to update interrupt line if it is enabled and there is a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * state change. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( !(pCtl->aIfs[pCtl->iSelectedIf].uATARegDevCtl & ATA_DEVCTL_DISABLE_IRQ)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the interrupt line is asserted. It monitors the line
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * for a rising edge. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* ignore commands to non existant slave */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->iSelectedIf && !pCtl->aIfs[pCtl->iSelectedIf].pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Don't do anything complicated in GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataIOPortReadU8(PATACONTROLLER pCtl, uint32_t addr, uint32_t *pu32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: /* data register */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The ATA specification is very terse when it comes to specifying
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the precise effects of reading back the error/feature register.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The error register (read-only) shares the register number with
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the feature register (write-only), so it seems that it's not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * necessary to support the usual HOB readback here. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This register must always work as long as there is at least
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * one drive attached to the controller. It is common between
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * both drives anyway (completely identical content). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pCtl->aIfs[0].pDrvBlock && !pCtl->aIfs[1].pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Counter for number of busy status seen in GC in a row. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static unsigned cBusy = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Give the async I/O thread an opportunity to make progress,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * don't let it starve by guests polling frequently. EMT has a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * lower priority than the async I/O thread, but sometimes the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * host OS doesn't care. With some guests we are only allowed to
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * be busy for about 5 milliseconds in some situations. Note that
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this is no guarantee for any other VBox thread getting
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * scheduled, so this just lowers the CPU load a bit when drives
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are busy. It cannot help with timing problems. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Cannot yield CPU in guest context. And switching to host
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * context for each and every busy status is too costly,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * especially on SMP systems where we don't gain much by
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * yielding the CPU to someone else. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataStatusRead(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((!pCtl->aIfs[0].pDrvBlock && !pCtl->aIfs[1].pDrvBlock) ||
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataControlWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((val ^ pCtl->aIfs[0].uATARegDevCtl) & ATA_DEVCTL_RESET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_IOM_HC_IOPORT_WRITE; /* The RESET stuff is too complicated for GC. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* RESET is common for both drives attached to a controller. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(pCtl->aIfs[0].uATARegDevCtl & ATA_DEVCTL_RESET) &&
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Software RESET low to high */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uCmdWait0 = (uNow - pCtl->aIfs[0].u64CmdTS) / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uCmdWait1 = (uNow - pCtl->aIfs[1].u64CmdTS) / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER_IDX(pCtl), pCtl->iSelectedIf, pCtl->iAIOIf,
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* Everything must be done after the reset flag is set, otherwise
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync * there are unavoidable races with the currently executing request
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * (which might just finish in the mean time). */
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pCtl->aIfs); i++)
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* The following cannot be done using ataSetStatusValue() since the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reset flag is already set, which suppresses all status changes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[i].uATARegStatus = ATA_STAT_BUSY | ATA_STAT_SEEK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, pCtl->aIfs[i].iLUN, pCtl->aIfs[i].uATARegStatus));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, resetA\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("RESET handling is too complicated for GC\n"));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#endif /* IN_RING3 */
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync else if ((pCtl->aIfs[0].uATARegDevCtl & ATA_DEVCTL_RESET) &&
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* Software RESET high to low */
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, resetC\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("RESET handling is too complicated for GC\n"));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Change of interrupt disable flag. Update interrupt line if interrupt
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * is pending on the current interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((val ^ pCtl->aIfs[0].uATARegDevCtl) & ATA_DEVCTL_DISABLE_IRQ
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * interrupt line is asserted. It monitors the line for a rising
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), 0, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), pCtl->irq, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), 0, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), pCtl->irq, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cbTotalTransfer && s->iIOBufferCur > s->iIOBufferEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Any guest OS that triggers this case has a pathetic ATA driver.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * In a real system it would block the CPU via IORDY, here we do it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * very similarly by not continuing with the current instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * until the transfer to/from the storage medium is completed. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: calling source/sink function\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE && s->cbElementaryTransfer > s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: %s tx_size=%d elem_tx_size=%d index=%d end=%d\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync __FUNCTION__, s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "T2I" : "I2T",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStart(s, s->iIOBufferCur, s->cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE && s->cbElementaryTransfer > s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataPIOTransferFinish(PATACONTROLLER pCtl, ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not interfere with RESET processing if the PIO transfer finishes
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed continuing PIO transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Need to continue the transfer in the async I/O thread. This is
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the case for write operations or generally for not yet finished
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfers (some data might need to be read). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Either everything finished (though some data might still be pending)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * or some data is pending before the next read is due. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Continue a previously started transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* There is more to transfer, happens usually for large ATAPI
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * reads - the protocol limits the chunk size to 65534 bytes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: skipping message to async I/O thread, ending PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finish PIO transfer. */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataDataWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p = s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* All but the last transfer unit is simple enough for GC, but
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * sending a request to the async IO thread is too complicated. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#else /* IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* !IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
87150caf549846b0edba30c50dabe5092df70b5fvboxsyncstatic int ataDataRead(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, uint8_t *pbBuf)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync p = s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync /* All but the last transfer unit is simple enough for GC, but
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * sending a request to the async IO thread is too complicated. */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#else /* IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * record (partition table). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataGuessDiskLCHS(ATADevState *s, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iEndHead, iEndSector, cCHSCylinders, cCHSHeads, cCHSSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, 0, aMBR, 1 * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Test MBR magic number. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Figure out the start of a partition table entry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Assumption: partition terminates on a cylinder boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cCHSCylinders = s->cTotalSectors / (cCHSHeads * cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cCHSCylinders, cCHSHeads, cCHSSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Perform the entire DMA transfer in one go (unless a source/sink operation
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * has to be redone or a RESET comes in between). Unlike the PIO counterpart
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this function cannot handle empty transfers.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param pCtl Controller for which to perform the transfer.
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync bool fLastDesc = false;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync /* The DMA loop is designed to hold the lock only when absolutely
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync * necessary. This avoids long freezes should the guest access the
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync * ATA registers etc. for some reason. */
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync Log2(("%s: %s tx_size=%d elem_tx_size=%d index=%d end=%d\n",
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync __FUNCTION__, uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "T2I" : "I2T",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (pDesc = pCtl->pFirstDMADesc; pDesc <= pCtl->pLastDMADesc; pDesc += sizeof(BMDMADesc))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysRead(pDevIns, pDesc, &DMADesc, sizeof(BMDMADesc));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync while (RT_UNLIKELY(fRedo) || (cbBuffer && cbTotalTransfer))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync dmalen = RT_MIN(cbBuffer, iIOBufferEnd - iIOBufferCur);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Log2(("%s: DMA desc %#010x: addr=%#010x size=%#010x\n", __FUNCTION__,
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysWrite(pDevIns, pBuffer, s->CTXSUFF(pbIOBuffer) + iIOBufferCur, dmalen);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysRead(pDevIns, pBuffer, s->CTXSUFF(pbIOBuffer) + iIOBufferCur, dmalen);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync && (uTxDir == PDMBLOCKTXDIR_TO_DEVICE || cbTotalTransfer))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (uTxDir == PDMBLOCKTXDIR_FROM_DEVICE && cbElementaryTransfer > cbTotalTransfer)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync /* The RESET handler could have cleared the DMA transfer
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * state (since we didn't hold the lock until just now
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * the guest can continue in parallel). If so, the state
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * is already set up so the loop is exited immediately. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Log2(("%s: calling source/sink function\n", __FUNCTION__));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (uTxDir == PDMBLOCKTXDIR_TO_DEVICE && cbElementaryTransfer > cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This forces the loop to exit immediately. */
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync /* end of transfer */
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync if (!(pCtl->BmDma.u8Cmd & BM_CMD_START) || pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: ABORT DMA%s\n", ATACONTROLLER_IDX(pCtl), pCtl->fReset ? " due to RESET" : ""));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This forces the loop to exit immediately. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Suspend I/O operations on a controller. Also suspends EMT, because it's
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * waiting for I/O to make progress. The next attempt to perform an I/O
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * operation will be made when EMT is resumed up again (as the resume
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * callback below restarts I/O).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCtl Controller for which to suspend I/O.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (PFNRT)pDevIns->pDevHlp->pfnVMSuspend, 1, pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** Asynch I/O thread for an interface. Once upon a time this was readable
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * code with several loops and a different semaphore for each purpose. But
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * then came the "how can one save the state in the middle of a PIO transfer"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * question. The solution was to use an ASM, which is what's there now. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataAsyncIOLoop(RTTHREAD ThreadSelf, void *pvUser)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Keep this thread from doing anything as long as EMT is suspended. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventWait(pCtl->SuspendIOSem, RT_INDEFINITE_WAIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Wait for work. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: going to sleep...\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventWait(pCtl->AsyncIOSem, RT_INDEFINITE_WAIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: waking up\n", pCtl->IOPortBase1));
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync Log2(("%s: Ctl#%d: state=%d, req=%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), pCtl->uAsyncIOState, ReqType));
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync /* The new state is not the state that was expected by the normal
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * state changes. This is either a RESET/ABORT or there's something
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync * really strange going on. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if ( (pCtl->uAsyncIOState == ATA_AIO_PIO || pCtl->uAsyncIOState == ATA_AIO_DMA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (ReqType == ATA_AIO_PIO || ReqType == ATA_AIO_DMA))
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* Incorrect sequence of PIO/DMA states. Dump request queue. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do our work. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogBird(("ata: %x: entering critsect\n", pCtl->IOPortBase1));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogBird(("ata: %x: entered\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->uAsyncIOState == ATA_AIO_NEW && !pCtl->fChainedTransfer)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only count the actual transfers, not the PIO
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer of the ATAPI command bytes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: calling begin transfer function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: Ctl#%d: calling source/sink function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Operation failed at the initial transfer, restart
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * everything from scratch by resending the current
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * request. Occurs very rarely, not worth optimizing. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("%s: Ctl#%d: redo entire operation\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Do not go into the transfer phase if RESET is asserted.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * The CritSect is released while waiting for the host OS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * to finish the I/O, thus RESET is possible here. Most
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * important: do not change uAsyncIOState. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* If BMDMA is already started, do the transfer now. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer immediately\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finish DMA transfer. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->fATAPITransfer || s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE || s->iSourceSink != ATAFN_SS_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Write operations and not yet finished transfers
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * must be completed in the async I/O thread. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finished read operation can be handled inline
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * in the end of PIO transfer handling code. Linux
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * depends on this, as it waits only briefly for
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * devices to become ready after incoming data
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * transfer. Cannot find anything in the ATA spec
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * that backs this assumption, but as all kernels
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * are affected (though most of the time it does
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * not cause any harm) this must work. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finish PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATAFNSS iOriginalSourceSink = (ATAFNSS)s->iSourceSink; /* Used by the hack below, but gets reset by then. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The specs say that the descriptor table must not cross a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * 4K boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->pLastDMADesc = RT_ALIGN_32(bm->pvAddr + 1, _4K) - sizeof(BMDMADesc);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogRel(("PIIX3 ATA: Ctl#%d: redo DMA operation\n", ATACONTROLLER_IDX(pCtl)));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* The infamous delay IRQ hack. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* Delay IRQ for writing. Required to get the Win2K
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * installation work reliably (otherwise it crashes,
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * usually during component install). So far no better
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * solution has been found. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Log2(("%s: Ctl#%d: interrupt reason %#04x\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegNSector));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Log2(("%s: Ctl#%d: calling source/sink function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogRel(("PIIX3 ATA: Ctl#%d: redo PIO operation\n", ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Continue a previously started transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* It is possible that the drives on this controller get RESET
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * during the above call to the source/sink function. If that's
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the case, don't restart the transfer and don't finish it the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * usual way. RESET handling took care of all that already.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Most important: do not change uAsyncIOState. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE || s->iSourceSink != ATAFN_SS_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Write operations and not yet finished transfers
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * must be completed in the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finished read operation can be handled inline
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * in the end of PIO transfer handling code. Linux
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * depends on this, as it waits only briefly for
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * devices to become ready after incoming data
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer. Cannot find anything in the ATA spec
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * that backs this assumption, but as all kernels
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are affected (though most of the time it does
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * not cause any harm) this must work. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finish PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not change the DMA registers, they are not affected by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA controller reset logic. It should be sufficient to issue a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * new command, which is now possible as the state is cleared. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: finished processing RESET\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pCtl->aIfs); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(&pCtl->aIfs[i], 0); /* NOTE: READY is _not_ set */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ataSetStatusValue(&pCtl->aIfs[i], ATA_STAT_READY | ATA_STAT_SEEK);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* Abort the current command only if it operates on the same interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not change the DMA registers, they are not affected by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA controller reset logic. It should be sufficient to issue a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * new command, which is now possible as the state is cleared. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetStatus(s, ATA_STAT_BUSY | ATA_STAT_DRQ | ATA_STAT_SEEK | ATA_STAT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Undefined async I/O state %d\n", pCtl->uAsyncIOState));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->uAsyncIOState == ATA_AIO_NEW && !pCtl->fChainedTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Mark command as finished. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Release logging of command execution times depends on the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * command type. ATAPI commands often take longer (due to CD/DVD
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * spin up time etc.) so the threshold is different.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[pCtl->iAIOIf].uATARegCommand != ATA_PACKET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Command took longer than 8 seconds. This is close
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * enough or over the guest's command timeout, so place
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * an entry in the release log to allow tracking such
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * timing errors (which are often caused by the host).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: execution time for ATA command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].uATARegCommand, uWait / (1000 * 1000)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Command took longer than 20 seconds. This is close
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * enough or over the guest's command timeout, so place
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * an entry in the release log to allow tracking such
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * timing errors (which are often caused by the host).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: execution time for ATAPI command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].aATAPICmd[0], uWait / (1000 * 1000)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (uWait < pCtl->StatAsyncMinWait || !pCtl->StatAsyncMinWait)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: leaving critsect\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Cleanup the state. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not destroy request mutex yet, still needed for proper shutdown. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This must be last, as it also signals thread exit to EMT. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: return %Vrc\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMACmdReadB(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMACmdWriteB(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Cmd = val & (BM_CMD_START | BM_CMD_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check whether the guest OS wants to change DMA direction in
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * mid-flight. Not allowed, according to the PIIX3 specs. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!(pCtl->BmDma.u8Status & BM_STATUS_DMAING) || !((val ^ pCtl->BmDma.u8Cmd) & 0x04));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Cmd = val & (BM_CMD_START | BM_CMD_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not continue DMA transfers while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed continuing DMA transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not start DMA transfers if there's a PIO transfer going on. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[pCtl->iAIOIf].uATARegStatus & ATA_STAT_DRQ)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("DMA START handling is too complicated for GC\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMAStatusReadB(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAStatusWriteB(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status = (val & (BM_STATUS_D0DMA | BM_STATUS_D1DMA))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (pCtl->BmDma.u8Status & ~val & (BM_STATUS_ERROR | BM_STATUS_INT));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMAAddrReadL(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteL(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteLowWord(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.pvAddr = (pCtl->BmDma.pvAddr & 0xFFFF0000) | RT_LOWORD(val & ~3);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteHighWord(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->BmDma.pvAddr = (RT_LOWORD(val) << 16) | RT_LOWORD(pCtl->BmDma.pvAddr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define VAL(port, size) ( ((port) & 7) | ((size) << 3) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for bus master DMA IN operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTIN for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(0, 1): *pu32 = ataBMDMACmdReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(0, 2): *pu32 = ataBMDMACmdReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 1): *pu32 = ataBMDMAStatusReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 2): *pu32 = ataBMDMAStatusReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 4): *pu32 = ataBMDMAAddrReadL(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("%s: Unsupported read from port %x size=%d\n", __FUNCTION__, Port, cb));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for bus master DMA OUT operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUT for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 1): ataBMDMAStatusWriteB(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 4): ataBMDMAAddrWriteL(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 2): ataBMDMAAddrWriteLowWord(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(6, 2): ataBMDMAAddrWriteHighWord(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default: AssertMsgFailed(("%s: Unsupported write to port %x size=%d val=%x\n", __FUNCTION__, Port, cb, u32)); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Callback function for mapping an PCI I/O region.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @return VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iRegion The region number.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * I/O port, else it's a physical address.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This address is *NOT* relative to pci_mem_base like earlier!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmType One of the PCI_ADDRESS_SPACE_* values.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataBMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PCIDEV_2_PCIATASTATE(pPciDev);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Register the port range. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2 = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTHCPTR)i, ataBMDMAIOPortWrite, ataBMDMAIOPortRead, NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = PDMDevHlpIOPortRegisterGC(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTGCPTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead", NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTR0PTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead", NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Reset notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataReset(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report that both drives present on the bus are in DMA mode. This
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * pretends that there is a BIOS that has set it up. Normal reset
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * default is 0x00. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].BmDma.u8Status = (pData->aCts[i].aIfs[0].pDrvBase != NULL ? BM_STATUS_D0DMA : 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (pData->aCts[i].aIfs[1].pDrvBase != NULL ? BM_STATUS_D1DMA : 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, reset controller\n", __FUNCTION__, i));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(&pData->aCts[i], &ataResetARequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(&pData->aCts[i], &ataResetCRequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!ataWaitForAsyncIOIsIdle(&pData->aCts[i], 30000))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsgFailed(("Async I/O thread busy after reset\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- PCIATAState::IBase -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Queries an interface to the driver.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Pointer to interface.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns NULL if the interface was not supported by the device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to ATADevState::IBase.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmInterface The requested interface identification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void *) ataStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMIBASE_2_PCIATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- PCIATAState::ILeds -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Gets the pointer to the status LED of a unit.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The unit which status LED we desire.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppLed Where to store the LED pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMILEDPORTS_2_PCIATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: *ppLed = &pData->aCts[0].aIfs[0].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1: *ppLed = &pData->aCts[0].aIfs[1].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2: *ppLed = &pData->aCts[1].aIfs[0].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3: *ppLed = &pData->aCts[1].aIfs[1].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- ATADevState::IBase -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Queries an interface to the driver.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns Pointer to interface.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns NULL if the interface was not supported by the device.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param pInterface Pointer to ATADevState::IBase.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param enmInterface The requested interface identification.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncstatic DECLCALLBACK(void *) ataQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIBASE_2_ATASTATE(pInterface);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#endif /* IN_RING3 */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync/* -=-=-=-=-=- Wrappers -=-=-=-=-=- */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range OUT operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTOUT for details.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = ataDataWrite(pCtl, Port, cb, (const uint8_t *)&u32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("ataIOPortWrite1: unsupported write to port %x val=%x size=%d\n", Port, u32, cb));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range IN operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTIN for details.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("ataIOPortRead1: unsupported read from port %x size=%d\n", Port, cb));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range IN string operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTINSTRING for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, unsigned *pcTransfer, unsigned cb)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cTransAvailable, cTransfer = *pcTransfer, cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * They are not performance-critical and generally shouldn't occur at all. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMGCRamWriteNoTrapHandler((char *)GCDst + i, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysWriteGCPtrDirty(PDMDevHlpGetVM(pDevIns), GCDst, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pGCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCDst + cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for primary port range OUT string operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUTSTRING for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cTransAvailable, cTransfer = *pcTransfer, cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * They are not performance-critical and generally shouldn't occur at all. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMGCRamReadNoTrapHandler(s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, (char *)GCSrc + i, cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysReadGCPtr(PDMDevHlpGetVM(pDevIns), s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pGCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCSrc + cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for secondary port range OUT operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUT for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for secondary port range IN operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTIN for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Waits for all async I/O threads to complete whatever they
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are doing at the moment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns true on success.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns false when one or more threads is still processing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pData Pointer to the instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cMillies How long to wait (total).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, unsigned cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fAllIdle = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The only way to deal cleanly with the VM lock is to check whether
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * it is owned now (it always is owned by EMT, which is the current
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * thread). Since this function is called several times during VM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * shutdown, and the VM lock is only held for the first call (which
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * can be either from ataPowerOff or ataSuspend), there is no other
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reasonable solution. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fVMLocked = VMMR3LockIsOwner(PDMDevHlpGetVM(pDevIns));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for any pending async operation to finish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check all async I/O threads. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER_IDX(pCtl), pCtl->iSelectedIf, pCtl->iAIOIf,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegCommand, pCtl->aIfs[1].uATARegCommand));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataRelocBuffer(PPDMDEVINS pDevIns, ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->pbIOBufferGC = MMHyperHC2GC(PDMDevHlpGetVM(pDevIns), s->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @copydoc FNPDMDEVRELOCATE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Destroy a driver instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * resources can be freed correctly.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataDestruct(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Terminate all async helper threads
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for them to complete whatever they are doing and then
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * for them to terminate.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* check */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts) && fAllDone; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fAllDone &= (pData->aCts[i].AsyncIOThread == NIL_RTTHREAD);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(fAllDone, ("Some of the async I/O threads are still running!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Now the request mutexes are no longer needed. Free resources.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSemMutexDestroy(pData->aCts[i].AsyncIORequestMutex);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].AsyncIORequestMutex = NIL_RTSEMEVENT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Detach notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The DVD drive has been unplugged.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The logical unit which is being detached.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataDetach(PPDMDEVINS pDevIns, unsigned iLUN)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pThis = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Locate the controller and stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iController = iLUN / RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iInterface = iLUN % RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Zero some important members.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Configure a LUN.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pIf The ATA unit state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataConfigLun(PPDMDEVINS pDevIns, ATADevState *pIf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Query Block, Bios and Mount interfaces.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlock = (PDMIBLOCK *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement the BIOS invisible code path. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios = (PDMIBLOCKBIOS *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvMount = (PDMIMOUNT *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_MOUNT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Validate type.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync enmType = pIf->pDrvBlock->pfnGetType(pIf->pDrvBlock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd-rom. enmType=%d\n", pIf->iLUN, enmType));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Internal error: cdrom without a mountable interface, WTF???!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->fATAPI = enmType == PDMBLOCKTYPE_DVD || enmType == PDMBLOCKTYPE_CDROM;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->fATAPIPassthrough = pIf->fATAPI ? (pIf->pDrvBlock->pfnSendCmd != NULL) : false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Allocate I/O buffer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Buffer is (probably) already allocated. Validate the fields,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * because memory corruption can also overwrite pIf->cbIOBuffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(pIf->cbIOBuffer == ATA_MAX_MULT_SECTORS * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pIf->pbIOBufferGC == MMHyperHC2GC(pVM, pIf->pbIOBufferHC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = MMHyperAlloc(pVM, pIf->cbIOBuffer, 1, MM_TAG_PDM_DEVICE_USER, (void **)&pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pbIOBufferGC = MMHyperHC2GC(pVM, pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Init geometry.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_NONE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Image contains no geometry information, detect geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataGuessDiskLCHS(pIf, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Caution: the above function returns LCHS, but the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * disk must report proper PCHS values for disks bigger
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * than approximately 512MB. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->cCHSSectors == 63 && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk CHS translation mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_LBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk geometry information. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Flag geometry as invalid, will be replaced below by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * default geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* If there is no geometry, use standard physical disk geometry.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This uses LCHS to LBA translation in the BIOS (which selects
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the logical sector count 63 and the logical head count to be
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the smallest of 16,32,64,128,255 which makes the logical
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * cylinder count smaller than 1024 - if that's not possible, it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * uses 255 heads, so up to about 8 GByte maximum with the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * standard int13 interface, which supports 1024 cylinders). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = (uint32_t)RT_MAX(cCHSCylinders, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk geometry information. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Use the official LBA physical CHS geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = RT_MAX((uint32_t)RT_MIN(cCHSCylinders, 16383), 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* DO NOT write back the disk geometry information. This
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * intentionally sets the ATA geometry only. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Attach command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is called when we change block driver for the DVD drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The logical unit which is being detached.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataAttach(PPDMDEVINS pDevIns, unsigned iLUN)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pThis = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Locate the controller and stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iController = iLUN / RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iInterface = iLUN % RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* the usual paranoia */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Try attach the block device and get the interfaces,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * required as well as optional.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpDriverAttach(pDevIns, pIf->iLUN, &pIf->IBase, &pIf->pDrvBase, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Failed to attach LUN#%d. rc=%Vrc\n", pIf->iLUN, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Suspend notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataSuspend(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Resume notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataResume(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].fRedo && pData->aCts[i].fRedoIdle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventSignal(pData->aCts[i].SuspendIOSem);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Power Off notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataPowerOff(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Prepare state save and load operation.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns Device instance of the device which registered the data unit.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSM SSM operation handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataSaveLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sanity - the suspend notification will wait on the async stuff. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Saves a state of the ATA device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSMHandle The handle to save the state to.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].iSelectedIf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].uAsyncIOState);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fChainedTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fRedoIdle);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fRedoDMALastDesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].BmDma, sizeof(pData->aCts[i].BmDma));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pFirstDMADesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pLastDMADesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].cbRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fLBA48);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fATAPI);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fIrqPending);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].cMultSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSCylinders);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cSectorsPerIRQ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU64(pSSMHandle, pData->aCts[i].aIfs[j].cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegFeature);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegFeatureHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegError);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegNSector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegNSectorHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSectorHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegLCyl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegLCylHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegHCyl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegHCylHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSelect);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegStatus);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegCommand);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegDevCtl);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATATransferMode);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uTxDir);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].iBeginTransfer);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].iSourceSink);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fDMA);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fATAPITransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbTotalTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferPIODataStart);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferPIODataEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbATAPISector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATAPISenseKey);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATAPIASC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].cNotifiedMediaChange);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].aIfs[j].Led, sizeof(pData->aCts[i].aIfs[j].Led));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer) == NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Loads a saved ATA device state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSMHandle The handle to the saved state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param u32Version The data unit version number.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Restore valid parts of the PCIATAState structure
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync /* integrity check */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync AssertMsgFailed(("Async I/O for controller %d is active\n", i));
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].iSelectedIf);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].uAsyncIOState);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].fChainedTransfer);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fReset);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedo);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedoIdle);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedoDMALastDesc);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].BmDma, sizeof(pData->aCts[i].BmDma));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pFirstDMADesc);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pLastDMADesc);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].cbRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fLBA48);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fATAPI);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fIrqPending);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].cMultSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSCylinders);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cSectorsPerIRQ);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU64(pSSMHandle, &pData->aCts[i].aIfs[j].cTotalSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegFeature);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegFeatureHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegError);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegNSector);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegNSectorHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSector);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSectorHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegLCyl);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegLCylHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegHCyl);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegHCylHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSelect);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegStatus);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegCommand);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegDevCtl);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATATransferMode);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uTxDir);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].iBeginTransfer);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].iSourceSink);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fDMA);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fATAPITransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbTotalTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferEnd);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferPIODataStart);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferPIODataEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbATAPISector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATAPISenseKey);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATAPIASC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].cNotifiedMediaChange);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].aIfs[j].Led, sizeof(pData->aCts[i].aIfs[j].Led));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* skip the buffer if we're loading for the debugger / animator. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (cbLeft-- > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer) == NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (u32 != ~0U)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * Construct a device instance for a VM.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @returns VBox status.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param pDevIns The device instance data.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * If the registration structure is needed, pDevIns->pDevReg points to it.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param iInstance Instance number. Use this to figure out which registers and such to use.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * The device number is also found in pDevIns->iInstance, but since it's
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * likely to be freqently used PDM passes it as parameter.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * of the device instance. It's also found in pDevIns->pCfgHandle, but like
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * iInstance it's expected to be used a bit in this function.
09f4b412099acda62997fd82c8608075c453b3ebvboxsyncstatic DECLCALLBACK(int) ataConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
db31571ec38a249cccfa0712989d810a68a9300fvboxsync * Validate and read configuration.
db31571ec38a249cccfa0712989d810a68a9300fvboxsync if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0IRQDelay\0R0Enabled\0PIIX4\0"))
db31571ec38a249cccfa0712989d810a68a9300fvboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
db31571ec38a249cccfa0712989d810a68a9300fvboxsync N_("PIIX3 configuration error: unknown option specified."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read GCEnabled as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read R0Enabled as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryU32(pCfgHandle, "IRQDelay", &DelayIRQMillies);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read IRQDelay as integer."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: DelayIRQMillies=%d\n", __FUNCTION__, DelayIRQMillies));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "PIIX4", &pData->fPIIX4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read PIIX4 as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fPIIX4=%d\n", __FUNCTION__, pData->fPIIX4));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Initialize data (most of it anyway).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Status LUN. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->IBase.pfnQueryInterface = ataStatus_QueryInterface;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->ILeds.pfnQueryStatusLed = ataStatus_QueryStatusLed;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x00] = 0x86; /* Vendor: Intel */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x02] = 0x11; /* Device: PIIX4 IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x08] = 0x01; /* Revision: PIIX4E */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x02] = 0x10; /* Device: PIIX3 IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x09] = 0x8a; /* programming interface = PCI_IDE bus master is supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x0a] = 0x01; /* class_sub = PCI_IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x0b] = 0x01; /* class_base = PCI_mass_storage */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].DelayIRQMillies = (uint32_t)DelayIRQMillies;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].iLUN = i * RT_ELEMENTS(pData->aCts) + j;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].pControllerHC = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[j].pControllerGC = MMHyperHC2GC(PDMDevHlpGetVM(pDevIns), &pData->aCts[i]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[j].IBase.pfnQueryInterface = ataQueryInterface;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].IMountNotify.pfnMountNotify = ataMountNotify;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].IMountNotify.pfnUnmountNotify = ataUnmountNotify;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].Led.u32Magic = PDMLED_MAGIC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Register the PCI device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * N.B. There's a hack in the PIIX3 PCI bridge device to assign this
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * device the slot next to itself.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(pData->dev.devfn == 9 || iInstance != 0, ("pData->dev.devfn=%d\n", pData->dev.devfn));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ataBMDMAIORangeMap);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 cannot register PCI I/O region for BMDMA."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Register the I/O ports.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The ports are all hardcoded and enforced by the PIIX3 host bridge controller.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTHCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataIOPortWrite1, ataIOPortRead1, ataIOPortWriteStr1, ataIOPortReadStr1, "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register I/O handlers."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTGCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", "ataIOPortWriteStr1", "ataIOPortReadStr1", "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register I/O handlers (GC)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", NULL, NULL, "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", "ataIOPortWriteStr1", "ataIOPortReadStr1", "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, "PIIX3 cannot register I/O handlers (R0).");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTHCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataIOPortWrite2, ataIOPortRead2, NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTGCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (GC)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (R0)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATADMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA DMA transfers.", "/Devices/ATA%d/Unit%d/DMA", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA PIO transfers.", "/Devices/ATA%d/Unit%d/PIO", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI DMA transfers.", "/Devices/ATA%d/Unit%d/AtapiDMA", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI PIO transfers.", "/Devices/ATA%d/Unit%d/AtapiPIO", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_STATISTICS /** @todo release too. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/ATA%d/Unit%d/ReadBytes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/ATA%d/Unit%d/WrittenBytes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync 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);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_STATISTICS /** @todo release too. */
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");
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;
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,