DevAHCI.cpp revision 06f6bbecfdf6438a87a4f4b327cf701c9a83860f
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VBox storage devices: AHCI controller device (disk and cdrom).
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Implements the AHCI standard 1.1
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * available from http://www.virtualbox.org. This file is free software;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * General Public License (GPL) as published by the Free Software
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * additional information or have any questions.
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This component implements an AHCI serial ATA controller. The device is split
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * into two parts. The first part implements the register interface for the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * guest and the second one does the data transfer.
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync * The guest can access the controller in two ways. The first one is the native
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * way implementing the registers described in the AHCI specification and is
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * the preferred one. The second implements the I/O ports used for booting from
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * the hard disk and for guests which don't have an AHCI SATA driver.
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * The data is transfered in an asychronous way using one thread per implemented
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * port or using the new async completion interface which is still under
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * development. [not quite up to date]
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*******************************************************************************
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync* Header Files *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync//#define DEBUG
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The current saved state version. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The saved state version use in VirtualBox 3.0 and earlier.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This was before the config was added and ahciIOTasks was dropped. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Set to 1 to disable multi-sector read support. According to the ATA
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * specification this must be a power of 2 and it must fit in an 8 bit
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Fastest PIO mode supported by the drive.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Fastest MDMA mode supported by the drive.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Fastest UDMA mode supported by the drive.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Length of the configurable VPD data (without termination)
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync/* Command Header. */
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsynctypedef struct
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Description Information. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command status. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command Table Base Address. */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync /** Command Table Base Address - upper 32-bits. */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync /** Reserved */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync/* Defines for the command header. */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the command FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines that are used in the first double word. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* For D2H FIS */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Scatter gather list entry data.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag whether the buffer in the list is from the guest or an
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * allocated temporary buffer because the segments in the guest
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * are not sector aligned.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag dependent data. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Data to handle direct mappings of guest buffers. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** The page lock. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** Data to handle temporary buffers. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** The first segment in the guest which is not sector aligned. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** Number of unaligned buffers in the guest. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** Pointer to the start of the buffer. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync} AHCIPORTTASKSTATESGENTRY, *PAHCIPORTTASKSTATESGENTRY;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync/** Pointer to a pointer of a scatter gather list entry. */
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsynctypedef PAHCIPORTTASKSTATESGENTRY *PPAHCIPORTTASKSTATESGENTRY;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync/** Pointer to a task state. */
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsynctypedef struct AHCIPORTTASKSTATE *PAHCIPORTTASKSTATE;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Data processing callback
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * @returns VBox status.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pAhciPortTaskState The task state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIPORTTASKSTATE pAhciPortTaskState);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a FNAHCIPOSTPROCESS() function. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * A task state.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Tag of the task. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Command is queued. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** The command header for this task. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The command Fis for this task. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The ATAPI comnmand data. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Physical address of the command header. - GC */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Data direction. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Start offset. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of bytes to transfer. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** ATA error register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** ATA status register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** How many entries would fit into the sg list. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync /** Number of used SG list entries. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the first entry of the scatter gather list. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of scatter gather list entries. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Total number of bytes the guest reserved for this request.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Sum of all SG entries. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Pointer to the first mapping information entry. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Size of the temporary buffer for unaligned guest segments. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the temporary buffer. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Number of times in a row the scatter gather list was too big. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Post processing callback.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * If this is set we will use a buffer for the data
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync * and the callback copies the data to the destination. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Notifier queue item.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The core part owned by the queue manager. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** On which port the async io thread should be put into action. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Which task to process. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag whether the task is queued. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct AHCIPort
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - HC ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - R0 ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - RC ptr. */
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync /** Pointer to the parent AHCI structure - R3 ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the parent AHCI structure - R0 ptr. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Pointer to the parent AHCI structure - RC ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command List Base Address. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command List Base Address upper bits. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** FIS Base Address. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** FIS Base Address upper bits. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Interrupt Status. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Interrupt Enable. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Command. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Task File Data. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Signature */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Serial ATA Status. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Serial ATA Control. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Serial ATA Error. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Serial ATA Active. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command Issue. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command List Base Address */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** FIS Base Address */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** If we use the new async interface. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Async IO Thread. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Request semaphore. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Task queue. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync volatile uint8_t ahciIOTasks[2*AHCI_NR_COMMAND_SLOTS];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Actual write position. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Actual read position. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Actual number of active tasks. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Device is powered on. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Device has spun up. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** First D2H FIS was send. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Attached device is a CD/DVD drive. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Device specific settings. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Pointer to the attached driver's base interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Pointer to the attached driver's block interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Pointer to the attached driver's async block interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Pointer to the attached driver's block bios interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Pointer to the attached driver's mount interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The base interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The block port interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The optional block async port interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The mount notify interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Physical geometry of this image. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The status LED state for this drive. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of total sectors. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Currently configured number of sectors in a multi-sector transfer. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** ATAPI sense key. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** ATAPI additional sens code. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The LUN. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag if we are in a device reset. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Bitmask for finished tasks. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Bitmask for finished queued tasks. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Array of cached tasks. The tag number is the index value.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Only used with the async interface.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync R3PTRTYPE(PAHCIPORTTASKSTATE) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Release statistics: number of DMA commands. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Release statistics: number of bytes written. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Release statistics: number of bytes read. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Release statistics: Number of I/O requests processed per second. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Statistics: Time to complete one request. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Statistics: Time to map requests into R3. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Statistics: Amount of time to read/write data. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Statistics: Amount of time to destroy a list. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif /* VBOX_WITH_STATISTICS */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag whether a notification was already send to R3. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag whether this port is in a reset state. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync volatile bool fPortReset;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Flag whether the I/O thread idles. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The serial numnber to use for IDENTIFY DEVICE commands. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The firmware revision to use for IDENTIFY DEVICE commands. */
067712a8118321d460f98b437ecafb6b8dbce301vboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The model number to use for IDENTIFY DEVICE commands. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** The vendor identification string for SCSI INQUIRY commands. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The product identification string for SCSI INQUIRY commands. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The revision string for SCSI INQUIRY commands. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Main AHCI device state.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsynctypedef struct AHCI
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The PCI device structure. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - R3 ptr */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Pointer to the device instance - R0 ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - RC ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The base interface */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Status Port - Leds interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Partner of ILeds. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync /** Base address of the MMIO region. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync /** Global Host Control register of the HBA */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** HBA Capabilities - Readonly */
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync /** HBA Control */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Interrupt Status */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Ports Implemented - Readonly */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** AHCI Version - Readonly */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Command completion coalescing control */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync /** Command completion coalescing ports */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Countdown timer for command completion coalescing - R3 ptr */
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync /** Countdown timer for command completion coalescing - R0 ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Countdown timer for command completion coalescing - RC ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Queue to send tasks to R3. - HC ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Queue to send tasks to R3. - HC ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Queue to send tasks to R3. - RC ptr */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Which port number is used to mark an CCC interrupt */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Timeout value */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Number of completions used to assert an interrupt */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Current number of completed commands */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Register structure per port */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Needed values for the emulated ide channels. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** The critical section. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Semaphore that gets set when fSignalIdle is set. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Bitmask of ports which asserted an interrupt. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Device is in a reset state. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Supports 64bit addressing */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** GC enabled. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** R0 enabled. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** If the new async interface is used if available. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Indicates that hEvtIdle should be signalled when a port is entering the
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync * idle state. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync bool volatile fSignalIdle;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Number of usable ports on this controller. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** At which number of I/O requests per second we consider having high I/O load. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** How many milliseconds to sleep. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync/* Scatter gather list entry. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsynctypedef struct
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Data Base Address. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Data Base Address - Upper 32-bits. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Reserved */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Description information. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/** Defines for a scatter gather list entry. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the global host control registers for the HBA. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the HBA Capabilities - Readonly */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
3614117c1132a61599e6190939e775cafe549411vboxsync#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the HBA Control register - Read/Write */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the command completion coalescing control register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the port registers. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_FB_RESERVED 0x7fffff00 /* For masking out the reserved bits. */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync/* Signatures for attached storage devices. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
07f038fb9d3d3080465ba0ba2065a4208e53e0f6vboxsync * regFB points to the base of this area.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Every FIS type has an offset where it is posted in this area.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_TASK_SET(tag, queued) (((tag) << 1) | (queued))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * AHCI register operator.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsynctypedef struct ahci_opreg
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync const char *pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * AHCI port register operator.
009d969fa3276b108ddb99a9c1a7a26c003438a7vboxsync const char *pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int (*pfnRead )(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int (*pfnWrite)(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncPDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void ahciScatterGatherListGetTotalBufferSize(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsyncstatic int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)(Lo) )
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync# define ahciLog(a) \
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync# define ahciLog(a) \
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define ahciLog(a) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Update PCI IRQ levels
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 0);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Reset command completion coalescing state. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync /* If only the bit of the actual port is set assert an interrupt
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * because the interrupt status register was already read by the guest
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * and we need to send a new notification.
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync * Otherwise an interrupt is still pending.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync PDMDevHlpPCISetIrqNoWait(pAhci->CTX_SUFF(pDevIns), 0, 1);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * Assert irq when an CCC timeout occurs
23603ed361f22874964e3a841add2c58ec2bb1eavboxsyncDECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Update the CI register first. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_ST) && (u32Value > 0))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Mark the tasks set in the value as used. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync for (uint8_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Queue task if bit is set in written value and not already in progress. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if (((u32Value >> i) & 0x01) && !(pAhciPort->regCI & (1 << i)))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Put the tag number of the task into the FIFO. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint8_t uTag = AHCI_TASK_SET(i, ((pAhciPort->regSACT & (1 << i)) ? 1 : 0));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ASMAtomicWriteU8(&pAhciPort->ahciIOTasks[pAhciPort->uActWritePos], uTag);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync ahciLog(("%s: Before uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: After uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync bool fNotificationSend = ASMAtomicXchgBool(&pAhciPort->fNotificationSend, true);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Send new notification. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pItem->fQueued = !!(pAhciPort->regSACT & (1 << i)); /* Mark if the task is queued. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync else if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT && pAhciPort->pDrvBase &&
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Reset queue. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Signature for SATA device. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (0x03 << 0); /* Device detected and communication established. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Use the maximum allowed speed.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * (Not that it changes anything really)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* We received a COMINIT from the device. Tell the guest. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3614117c1132a61599e6190939e775cafe549411vboxsync ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsyncstatic int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync * Read from the port command register.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, (pAhciPort->regCMD & AHCI_PORT_CMD_CCS) >> 8,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Write to the port command register.
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * This is the register where all the data transfer is started
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync ahciLog(("%s: ICC=%d ASP=%d ALPE=%d DLAE=%d ATAPI=%d CPD=%d ISP=%d HPCP=%d PMA=%d CPS=%d CR=%d FR=%d ISS=%d CCS=%d FRE=%d CLO=%d POD=%d SUD=%d ST=%d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: Command list override requested\n", __FUNCTION__));
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /* Clear the CLO bit. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** Set engine state to running. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Clear command issue register. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /** Clear current command slot. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: Power on the device\n", __FUNCTION__));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Set states in the Port Signature and SStatus registers.
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (0x03 << 0); /* Device detected and communication established. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: Spin up the device\n", __FUNCTION__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /* Send the first D2H FIS only if it wasn't already send. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Read from the port interrupt enable register.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Write to the port interrupt enable register.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: CPDE=%d TFEE=%d HBFE=%d HBDE=%d IFE=%d INFE=%d OFE=%d IPME=%d PRCE=%d DIE=%d PCE=%d DPE=%d UFE=%d SDBE=%d DSE=%d PSE=%d DHRE=%d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pAhciPort->regIE = (u32Value & AHCI_PORT_IE_READONLY);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Check if some a interrupt status bit changed*/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
return VINF_SUCCESS;
ahciLog(("%s: CPDS=%d TFES=%d HBFS=%d HBDS=%d IFS=%d INFS=%d OFS=%d IPMS=%d PRCS=%d DIS=%d PCS=%d DPS=%d UFS=%d SDBS=%d DSS=%d PSS=%d DHRS=%d\n",
__FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
int rc;
return rc;
if (u32Value > 0)
bool fClear = true;
if (fClear)
fClear = false;
if (fClear)
Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
* We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
return VINF_SUCCESS;
int rc;
return rc;
Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
#ifdef LOG_ENABLED
return VINF_SUCCESS;
return VINF_SUCCESS;
__FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
return VINF_SUCCESS;
"%s: S64A=%d SNCQ=%d SIS=%d SSS=%d SALP=%d SAL=%d SCLO=%d ISS=%d SNZO=%d SAM=%d SPM=%d PMD=%d SSC=%d PSC=%d NCS=%d NP=%d\n",
__FUNCTION__, (ahci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (ahci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
return VINF_SUCCESS;
return VINF_SUCCESS;
__FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(ahci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(ahci->regHbaCccCtl),
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef LOG_ENABLED
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef IN_RING3
for (unsigned i = 0; i < cPorts; i++)
return uPortsImplemented;
PDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
return rc;
* If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
switch (cb)
AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
return rc;
PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
return rc;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
return rc;
PDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
PDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
PDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
PDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
PDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return VINF_SUCCESS;
PDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return VINF_SUCCESS;
#ifndef IN_RING0
PDMBOTHCBDECL(int) ahciIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
PDMBOTHCBDECL(int) ahciIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
#ifdef IN_RING3
static DECLCALLBACK(int) ahciMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
return rc;
return rc;
return rc;
return rc;
static DECLCALLBACK(int) ahciLegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
return rc;
return rc;
return rc;
return rc;
static DECLCALLBACK(int) ahciStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
static DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_LED_PORTS:
return NULL;
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_BLOCK_PORT:
return NULL;
uint32_t i;
#ifdef DEBUG
case AHCI_CMDFIS_TYPE_H2D:
ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
case AHCI_CMDFIS_TYPE_D2H:
case AHCI_CMDFIS_TYPE_DATA:
ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
unsigned cbFis = 0;
switch (uFisType)
case AHCI_CMDFIS_TYPE_D2H:
ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
return rc;
pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
static void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
if (*pbSrc)
if (*pbSrc)
uint16_t *p;
ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
return VINF_SUCCESS;
typedef enum ATAPIFN
ATAFN_SS_NULL = 0,
} ATAPIFN;
NULL,
static int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
int rc;
ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
return VINF_SUCCESS;
static int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
return VINF_SUCCESS;
static int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
aBuf[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 */
return VINF_SUCCESS;
static int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
return VINF_SUCCESS;
aBuf[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 */
aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
return VINF_SUCCESS;
static int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
static int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
return VINF_SUCCESS;
static int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
return VINF_SUCCESS;
static int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
return VINF_SUCCESS;
static int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
return VINF_SUCCESS;
static int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
bool fMSF;
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
return VINF_SUCCESS;
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
if (fMSF)
return VINF_SUCCESS;
static int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
bool fMSF;
/** @todo double-check this stuff against what a real drive says for a CD-ROM (not a CD-R) with only a single data session. Maybe solve the problem with "cdrdao read-toc" not being able to figure out whether numbers are in BCD or hex. */
if (fMSF)
return VINF_SUCCESS;
static int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
bool fMSF;
if (fMSF)
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
return VINF_SUCCESS;
static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
int cbTransfered;
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
return rcSourceSink;
return VINF_SUCCESS;
static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
switch (cbSector)
return VINF_SUCCESS;
switch (pbPacket[0])
case SCSI_TEST_UNIT_READY:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
case SCSI_MODE_SENSE_10:
switch (uPageControl)
case SCSI_PAGECONTROL_CURRENT:
switch (uPageCode)
case SCSI_MODEPAGE_CD_STATUS:
goto error_cmd;
goto error_cmd;
case SCSI_PAGECONTROL_DEFAULT:
goto error_cmd;
case SCSI_PAGECONTROL_SAVED:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
case SCSI_REQUEST_SENSE:
case SCSI_READ_10:
case SCSI_READ_12:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
if (cSectors == 0)
LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
case SCSI_READ_CD:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
if (cSectors == 0)
LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
case SCSI_SEEK_10:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
case SCSI_START_STOP_UNIT:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
case SCSI_MECHANISM_STATUS:
case SCSI_READ_TOC_PMA_ATIP:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
switch (format)
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
case SCSI_READ_CAPACITY:
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
case SCSI_GET_CONFIGURATION:
case SCSI_INQUIRY:
return rc;
static void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
/* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis, bool fInterrupt)
bool fAssertIntr = false;
fAssertIntr = true;
if (fInterrupt)
fAssertIntr = true;
if (fAssertIntr)
static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
bool fAssertIntr = false;
sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
fAssertIntr = true;
if (fInterrupt)
fAssertIntr = true;
if (fAssertIntr)
if (fLBA48)
if (fLBA48)
iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
return iLBA;
return uLBA;
static void ahciScatterGatherListGetTotalBufferSize(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
unsigned cActualSGEntry;
SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
unsigned cSGLEntriesGCRead;
GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
} while (cSGLEntriesGCLeft);
static int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
return VERR_NO_MEMORY;
pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
return VERR_NO_MEMORY;
return VERR_NO_MEMORY;
#ifdef DEBUG
memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
return VINF_SUCCESS;
static int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
pSGInfoCurr++;
return VERR_NO_MEMORY;
return VERR_NO_MEMORY;
pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
return VERR_NO_MEMORY;
return VERR_NO_MEMORY;
pAhciPortTaskState->paSGEntries[0].u.temp.cUnaligned = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
return VINF_SUCCESS;
static int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly)
unsigned cActualSGEntry;
SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
unsigned cSGLEntriesGCRead;
bool fDoMapping = false;
* We need to calculate the number of SG list entries in R3 first because the data buffers in the guest don't need to be
* In the first pass we calculate the number of segments in R3 and in the second pass we map the guest segments into R3.
GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
fUnaligned = false;
cbUnaligned = 0;
cUnaligned = 0;
if (fDoMapping)
cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
if (!fUnaligned)
fUnaligned = true;
cSGEntriesR3++;
cUnaligned++;
if (fUnaligned)
fUnaligned = false;
if (fDoMapping)
pSGInfoCurr++;
pSGEntryCurr++;
cUnaligned++;
GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntry[cActualSGEntry].u32DBAUp, aSGLEntry[cActualSGEntry].u32DBA);
if (!fUnaligned)
fUnaligned = true;
cSGEntriesR3++;
ahciLog(("%s: Guest segment is sector aligned but crosses a page boundary cb=%d\n", __FUNCTION__, cbDataToTransfer));
cUnaligned++;
if (fDoMapping)
if (fReadonly)
0, (const void **)&pbMapping,
0, (void **)&pbMapping,
if ((pbMapping + (GCPhysAddrDataBase - GCPhysBufferPageAligned) == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryCurr->cbSeg)))
pSGEntryCurr++;
pSGInfoCurr++;
cSGEntriesR3++;
else if (fDoMapping)
if (!fUnaligned)
while (cbDataToTransfer)
if (fDoMapping)
void *pvMapping;
if (fReadonly)
rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysAddrDataBase, 0, (const void **)&pvMapping, &pSGInfoCurr->u.direct.PageLock);
rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrDataBase, 0, &pvMapping, &pSGInfoCurr->u.direct.PageLock);
pSGEntryCurr++;
pSGInfoCurr++;
cSGEntriesR3++;
} while (cSGLEntriesGCLeft);
fDoMapping = true;
if (fUnaligned)
return rc;
int rc;
for (unsigned cActualSGEntry = 0; cActualSGEntry < pAhciPortTaskState->cSGEntries; cActualSGEntry++)
pSGInfoCurr++;
return VINF_SUCCESS;
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
} while (cSGEntriesLeft);
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
} while (cSGEntriesLeft);
static int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf)
unsigned cSGEntry = 0;
int cbCopied = 0;
if (!cbBuf)
pSGEntry++;
cSGEntry++;
return cbCopied;
#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
if (!cOutstandingTasks)
return VINF_SUCCESS;
return rc;
static int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
bool fLBA48 = false;
AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
case ATA_IDENTIFY_DEVICE:
pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
case ATA_SET_FEATURES:
pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
case ATA_FLUSH_CACHE_EXT:
case ATA_FLUSH_CACHE:
case ATA_PACKET:
case ATA_SET_MULTIPLE_MODE:
case ATA_STANDBY_IMMEDIATE:
case ATA_CHECK_POWER_MODE:
case ATA_IDLE_IMMEDIATE:
case ATA_RECALIBRATE:
case ATA_NOP:
case ATA_READ_VERIFY_SECTORS:
case ATA_READ_DMA_EXT:
fLBA48 = true;
case ATA_READ_DMA:
case ATA_WRITE_DMA_EXT:
fLBA48 = true;
case ATA_WRITE_DMA:
case ATA_READ_FPDMA_QUEUED:
case ATA_WRITE_FPDMA_QUEUED:
case ATA_SECURITY_FREEZE_LOCK:
case ATA_SMART:
case ATA_NV_CACHE:
return rc;
AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
pAhciPortTaskState->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciPortTaskState->uTag * sizeof(CmdHdr);
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
#ifdef DEBUG
GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr);
AssertMsg((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->aATAPICmd[0], ATAPI_PACKET_SIZE);
* We need to send a FIS which clears the busy bit if this is a queued command so that the guest can queue other commands.
#ifdef DEBUG
RTGCPHYS GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
ahciLog(("PRDT address %RGp number of entries %u\n", GCPhysAddrPRDTLEntryStart, AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf)));
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrPRDTLEntryStart, &SGEntry, sizeof(SGLEntry));
int iTxDir;
/* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
return VINF_SUCCESS;
if (!pAhciPortTaskState)
return VERR_NO_MEMORY;
if (!u64StartTime)
&& (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) )
#ifdef DEBUG
while ( (cTasksToProcess > 0)
int iTxDir;
AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number!!\n", __FUNCTION__));
/* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
while (cbTransfer)
AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
pSegCurr++;
pSGInfoCurr++;
#ifdef DEBUG
if (!cTasksToProcess)
uQueuedTasksFinished = 0;
ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
u64StartTime = 0;
uIORequestsProcessed = 0;
return rc;
unsigned iActPort = 0;
return rc;
pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
return VERR_PDM_MISSING_INTERFACE;
pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
return VERR_PDM_MISSING_INTERFACE;
pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
return VERR_INTERNAL_ERROR;
LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
return rc;
bool fAllFinished;
fAllFinished = true;
if (!fAllFinished)
if ( fAllFinished
return fAllFinished;
int rc;
return rc;
return VINF_SUCCESS;
int rc;
return rc;
return VINF_SUCCESS;
static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
return VINF_SSM_DONT_CALL_AGAIN;
uint32_t i;
int rc;
for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
return rc;
static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
uint32_t i;
int rc;
return VERR_SSM_LOAD_CONFIG_MISMATCH;
bool fInUse;
return VERR_SSM_LOAD_CONFIG_MISMATCH;
static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
return VERR_SSM_LOAD_CONFIG_MISMATCH;
for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
return rc;
return rc;
return VINF_SUCCESS;
int rcThread;
AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
int rc;
rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
return rc;
rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
return rc;
return rc;
bool fGCEnabled = false;
bool fR0Enabled = false;
rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
return rc;
* No guest should access them anyway because the controller is marked as AHCI in the Programming interface
* and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
return rc;
return rc;
rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
return rc;
for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
"Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
"Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
"Amount of time to map the guest buffers into R3.", "/Devices/SATA%d/Port%d/ProfileMapIntoR3", iInstance, i);
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
"Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
"Amount of time to destroy the scatter gather list and free associated ressources.", "/Devices/SATA%d/Port%d/ProfileDestroyScatterGatherList", iInstance, i);
rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
return rc;
rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
szSerial);
rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
#ifdef DEBUG
pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
rc = ataControllerInit(pDevIns, pCtl, pThis->ahciPort[iPortMaster].pDrvBase, pThis->ahciPort[iPortSlave].pDrvBase,
&cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led, &pThis->ahciPort[iPortMaster].StatBytesRead,
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
return rc;
return rc;
sizeof(AHCI),
NULL,
NULL,
NULL,
NULL,
NULL,