DevAHCI.cpp revision b32cbfd89d5d933a6c86fc4d24ffae4d27976af3
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VBox storage devices: AHCI controller device (disk and cdrom).
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Implements the AHCI standard 1.1
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Copyright (C) 2006-2012 Oracle Corporation
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/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This component implements an AHCI serial ATA controller. The device is split
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * into two parts. The first part implements the register interface for the
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync * guest and the second one does the data transfer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * The guest can access the controller in two ways. The first one is the native
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * 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
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * the hard disk and for guests which don't have an AHCI SATA driver.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * The data is transferred in an asynchronous way using one thread per implemented
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * port or using the new async completion interface which is still under
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * development. [not quite up to date]
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*******************************************************************************
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync* Header Files *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync//#define DEBUG
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync/** Maximum number of ports available.
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * Spec defines 32 but we have one allocated for command completion coalescing
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * and another for a reserved future feature.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Maximum number of command slots available. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The current saved state version. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Saved state version before legacy ATA emulation was dropped. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Saved state version before ATAPI support was added. */
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/* for Older ATA state Read handling */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The maximum number of release log entries per device. */
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.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Fastest MDMA mode supported by the drive.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Fastest UDMA mode supported by the drive.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Length of the configurable VPD data (without termination)
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync/* MediaEventStatus */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_EVENT_STATUS_UNCHANGED 0 /**< medium event status not changed */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_EVENT_STATUS_MEDIA_NEW 1 /**< new medium inserted */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_EVENT_STATUS_MEDIA_REMOVED 2 /**< medium removed */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_EVENT_STATUS_MEDIA_CHANGED 3 /**< medium was removed + new medium was inserted */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED 4 /**< medium eject requested (eject button pressed) */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync/* Media track type */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define ATA_MEDIA_TYPE_CDDA 2 /**< CD-DA (audio) CD type */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync/** ATAPI sense info size. */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * Command Header.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Description Information. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command status. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command Table Base Address. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command Table Base Address - upper 32-bits. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Reserved */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the command header. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync/* 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. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# 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. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync/* For D2H FIS */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync/** Pointer to a task state. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * Data processing callback
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pAhciReq The task state.
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * @param ppvProc Where to store the pointer to the buffer holding the processed data on success.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Must be freed with RTMemFree().
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pcbProc Where to store the size of the buffer on success.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a FNAHCIPOSTPROCESS() function. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Transfer type.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Invalid */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** None */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Read */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Write */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flush */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Trim */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Task state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Invalid. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Task is not active. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync /** Task is active */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Task was canceled but the request didn't completed yet. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** 32bit hack. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Task encountered a buffer overflow. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync/** Request is a PIO data command, if this flag is not set it either is
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * a command which does not transfer data or a DMA command based on the transfer size. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The request has the SACT register set. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync/** FLag whether the request is queued. */
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync * A task state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct AHCIREQ
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Task state. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Tag of the task. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The command header for this task. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The command Fis for this task. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The ATAPI command data. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Size of one sector for the ATAPI transfer. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Physical address of the command header. - GC */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Physical address if the PRDT */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Number of entries in the PRDTL. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Data direction. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Start offset. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of bytes to transfer. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** ATA error register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** ATA status register */
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync /** Flags for this task. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Additional memory allocation for this task. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Siize of the allocation. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of times we had too much memory allocated for the request. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Data dependent on the transfer direction. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Data for an I/O request. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Data segment. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Post processing callback.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * If this is set we will use a buffer for the data
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * and the callback returns a buffer with the final data. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Data for a trim request. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the array of ranges to trim. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Number of entries in the array. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Notifier queue item.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The core part owned by the queue manager. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The port to process. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * @implements PDMIBASE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @implements PDMIBLOCKPORT
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @implements PDMIBLOCKASYNCPORT
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * @implements PDMIMOUNTNOTIFY
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct AHCIPort
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Pointer to the device instance - HC ptr */
3956d0151065a11e49d2213b38a5efdad46807e0vboxsync /** Pointer to the device instance - R0 ptr */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Pointer to the device instance - RC ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the parent AHCI structure - R3 ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the parent AHCI structure - R0 ptr. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the parent AHCI structure - RC ptr. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Command List Base Address. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command List Base Address upper bits. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** FIS Base Address. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** FIS Base Address upper bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Interrupt Status. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Interrupt Enable. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Command. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Task File Data. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Signature */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Serial ATA Status. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Serial ATA Control. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Serial ATA Error. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Serial ATA Active. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command Issue. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Command List Base Address */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** FIS Base Address */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Current number of active tasks. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Device is powered on. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Device has spun up. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** First D2H FIS was send. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Attached device is a CD/DVD drive. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Passthrough SCSI commands. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Flag whether this port is in a reset state. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync volatile bool fPortReset;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** If we use the new async interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag if we are in a device reset. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Flag whether the I/O thread idles. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Flag whether the port is in redo task mode. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync volatile bool fRedo;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** 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 data. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The same for GET_EVENT_STATUS for mechanism */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Media type if known. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The LUN. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Bitmap for finished tasks (R3 -> Guest). */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Bitmap for finished queued tasks (R3 -> Guest). */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Bitmap for new queued tasks (Guest -> R3). */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Current command slot processed.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Accessed by the guest by reading the CMD register.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Holds the command slot of the command processed at the moment. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Device specific settings (R3 only stuff). */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Pointer to the attached driver's base interface. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Pointer to the attached driver's block interface. */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** Pointer to the attached driver's async block interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the attached driver's block bios interface. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Pointer to the attached driver's mount interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The base interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The block port interface. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync /** The optional block async port interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** The mount notify interface. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Physical geometry of this image. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The status LED state for this drive. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Async IO Thread. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Request semaphore. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Array of cached tasks. The tag number is the index value.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Only used with the async interface.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync R3PTRTYPE(PAHCIREQ) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** First task throwing an error. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Release statistics: number of DMA commands. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Release statistics: number of bytes written. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Release statistics: number of bytes read. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync /** Release statistics: Number of I/O requests processed per second. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Statistics: Time to complete one request. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync /** Statistics: Time to map requests into R3. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Statistics: Amount of time to read/write data. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Statistics: Amount of time to destroy a list. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif /* VBOX_WITH_STATISTICS */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync /** The serial numnber to use for IDENTIFY DEVICE commands. */
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** The firmware revision to use for IDENTIFY DEVICE commands. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The model number to use for IDENTIFY DEVICE commands. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The vendor identification string for SCSI INQUIRY commands. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The product identification string for SCSI INQUIRY commands. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The revision string for SCSI INQUIRY commands. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Error counter */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync/** Pointer to the state of an AHCI port. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * Main AHCI device state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @implements PDMILEDPORTS
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsynctypedef struct AHCI
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The PCI device structure. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance - R3 ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Pointer to the device instance - R0 ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Pointer to the device instance - RC ptr. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Status LUN: The base interface. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Status LUN: Leds interface. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Status LUN: Partner of ILeds. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Status LUN: Media Notifys. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Base address of the MMIO region. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Base address of the I/O port region for Idx/Data. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Global Host Control register of the HBA */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** HBA Capabilities - Readonly */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** HBA Control */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Interrupt Status */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Ports Implemented - Readonly */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** AHCI Version - Readonly */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Command completion coalescing control */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Command completion coalescing ports */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Index register for BIOS access. */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Countdown timer for command completion coalescing - R3 ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Countdown timer for command completion coalescing - R0 ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Countdown timer for command completion coalescing - RC ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Queue to send tasks to R3. - HC ptr */
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync /** Queue to send tasks to R3. - HC ptr */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Queue to send tasks to R3. - RC ptr */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Which port number is used to mark an CCC interrupt */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Timeout value */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of completions used to assert an interrupt */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Current number of completed commands */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Register structure per port */
3614117c1132a61599e6190939e775cafe549411vboxsync /** The critical section. */
3614117c1132a61599e6190939e775cafe549411vboxsync /** Bitmask of ports which asserted an interrupt. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Device is in a reset state. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Supports 64bit addressing */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** GC enabled. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** R0 enabled. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** If the new async interface is used if available. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * a port is entering the idle state. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync bool volatile fSignalIdle;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Flag whether the controller has BIOS access enabled. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of usable ports on this controller. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Number of usable command slots for each port. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/** Pointer to the state of an AHCI device. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Scatter gather list entry.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Data Base Address. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Data Base Address - Upper 32-bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Reserved */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /** Description information. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Defines for a scatter gather list entry. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the global host control registers for the HBA. */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync/* Defines for the HBA Capabilities - Readonly */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#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 */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the HBA Control register - Read/Write */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the command completion coalescing control register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#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)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/* Defines for the port registers. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#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))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#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))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#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.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * regFB points to the base of this area.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Every FIS type has an offset where it is posted in this area.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#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 */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync/** Mask to get the LBA value from a LBA range. */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_RANGE_LBA_MASK UINT64_C(0xffffffffffff)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/** Mas to get the length value from a LBA range. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define AHCI_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/** Returns the length of the range in sectors. */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync#define AHCI_RANGE_LENGTH_GET(val) (((val) & AHCI_RANGE_LENGTH_MASK) >> 48)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * AHCI register operator.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsynctypedef struct ahci_opreg
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync const char *pszName;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * AHCI port register operator.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync 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);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic bool ahciCancelActiveTasks(PAHCIPort pAhciPort);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#define PDMIBLOCKPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#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) )
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync# define ahciLog(a) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync# define ahciLog(a) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync# define ahciLog(a) \
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync# define ahciLog(a) \
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Update PCI IRQ levels
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Reset command completion coalescing state. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync /* If only the bit of the actual port is set assert an interrupt
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * because the interrupt status register was already read by the guest
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * and we need to send a new notification.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * 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__));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Assert irq when an CCC timeout occurs
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncDECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Update the CI register first. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Clear all tasks which are already marked as busy. The guest
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * shouldn't write already busy tasks actually.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync u32Tasks = ASMAtomicReadU32(&pAhciPort->u32TasksNew);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Send a notification to R3 if u32TasksNew was before our write. */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
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);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
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));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Cancel all tasks first. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync LogRel(("AHCI#%d: Port %d reset\n", ahci->CTX_SUFF(pDevIns)->iInstance,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT && pAhciPort->pDrvBase &&
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Signature for SATA device. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync (0x03 << 0); /* Device detected and communication established. */
3956d0151065a11e49d2213b38a5efdad46807e0vboxsync * Use the maximum allowed speed.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * (Not that it changes anything really)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /* We received a COMINIT from the device. Tell the guest. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsyncstatic int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsyncstatic 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__,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * Read from the port command register.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsyncstatic int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync 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",
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Write to the port command register.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * 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));
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__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (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,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: Command list override requested\n", __FUNCTION__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /* Clear the CLO bit. */
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync /* Set engine state to running if there is a device attached. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Clear command issue register. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Clear current command slot. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ahciLog(("%s: Power on the device\n", __FUNCTION__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Set states in the Port Signature and SStatus registers.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (0x03 << 0); /* Device detected and communication established. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync 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__));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Send the first D2H FIS only if it wasn't already send. */
return VINF_IOM_R3_MMIO_WRITE;
return VINF_SUCCESS;
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",
__FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
return VINF_SUCCESS;
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",
return rc;
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;
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
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
bool fAllTasksCanceled;
for (unsigned i = 0; i < cPorts; i++)
return uPortsImplemented;
* 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)
return rc;
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) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
return rc;
return rc;
PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
return rc;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
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;
PDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
if (iReg == 0)
return rc;
PDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
if (iReg == 0)
return rc;
#ifdef IN_RING3
static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
return rc;
rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
return rc;
rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
return rc;
return rc;
static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(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) ahciR3IdxDataIORangeMap(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) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
return NULL;
return NULL;
static DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIBLOCKPORT pInterface, const char **ppcszController,
return VINF_SUCCESS;
#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;
static void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
static void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
if (*pbSrc)
if (*pbSrc)
size_t i;
for (i = 0; i < count; i++)
u8Sum += *p++;
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 */
&& pAhciPort->pDrvBlockAsync->pfnStartDiscard)) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
p[75] = RT_H2LE_U16(pAhciPort->CTX_SUFF(pAhci)->cCmdSlotsAvail-1); /* Number of commands we support, 0's based */
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,
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(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
return VINF_SUCCESS;
static int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *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(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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 size_t atapiGetConfigurationFillFeatureListProfiles(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureCore(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureMorphing(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureRemovableMedium(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureRandomReadable(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureCDRead(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeaturePowerManagement(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static size_t atapiGetConfigurationFillFeatureTimeout(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
static int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
return VINF_SUCCESS;
return VINF_SUCCESS;
static int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
return VINF_SUCCESS;
switch (OldStatus)
return VINF_SUCCESS;
return VINF_SUCCESS;
static int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
return VINF_SUCCESS;
static int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *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(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
return VINF_SUCCESS;
static int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
return VINF_SUCCESS;
static int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
bool fMSF;
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *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(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
bool fMSF;
if (fMSF)
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
return VINF_SUCCESS;
static int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
if (cbTransfer)
if (!pvBuf)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
return VINF_SUCCESS;
cReqSectors = 0;
cReqSectors = i;
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
&cbCurrTX,
sizeof(abATAPISense),
sizeof(abATAPISense),
if (cbTransfer)
*pcbData = 0;
if (pvBuf)
return VINF_SUCCESS;
static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
&cbTransfered);
return rcSourceSink;
return VERR_NO_MEMORY;
return VINF_SUCCESS;
static int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
switch (cbSector)
return VINF_SUCCESS;
switch (pbPacket[0])
case SCSI_TEST_UNIT_READY:
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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:
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
case SCSI_REQUEST_SENSE:
case SCSI_READ_10:
case SCSI_READ_12:
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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));
case SCSI_READ_CD:
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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));
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
case SCSI_SEEK_10:
atapiCmdErrorSimple(pAhciPort, pAhciReq, 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));
case SCSI_START_STOP_UNIT:
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
case SCSI_MECHANISM_STATUS:
case SCSI_READ_TOC_PMA_ATIP:
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
switch (format)
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
case SCSI_READ_CAPACITY:
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
case SCSI_GET_CONFIGURATION:
case SCSI_INQUIRY:
return rc;
switch (pbPacket[0])
case SCSI_BLANK:
goto sendcmd;
case SCSI_CLOSE_TRACK_SESSION:
goto sendcmd;
case SCSI_ERASE_10:
goto sendcmd;
case SCSI_FORMAT_UNIT:
cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
goto sendcmd;
case SCSI_GET_CONFIGURATION:
goto sendcmd;
atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
goto sendcmd;
case SCSI_GET_PERFORMANCE:
cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
goto sendcmd;
case SCSI_INQUIRY:
goto sendcmd;
case SCSI_LOAD_UNLOAD_MEDIUM:
goto sendcmd;
case SCSI_MECHANISM_STATUS:
goto sendcmd;
case SCSI_MODE_SELECT_10:
goto sendcmd;
case SCSI_MODE_SENSE_10:
goto sendcmd;
case SCSI_PAUSE_RESUME:
goto sendcmd;
case SCSI_PLAY_AUDIO_10:
goto sendcmd;
case SCSI_PLAY_AUDIO_12:
goto sendcmd;
case SCSI_PLAY_AUDIO_MSF:
goto sendcmd;
goto sendcmd;
case SCSI_READ_10:
goto sendcmd;
case SCSI_READ_12:
goto sendcmd;
case SCSI_READ_BUFFER:
goto sendcmd;
goto sendcmd;
case SCSI_READ_CAPACITY:
goto sendcmd;
case SCSI_READ_CD:
goto sendcmd;
case SCSI_READ_CD_MSF:
cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
goto sendcmd;
goto sendcmd;
case SCSI_READ_DVD_STRUCTURE:
goto sendcmd;
goto sendcmd;
case SCSI_READ_SUBCHANNEL:
goto sendcmd;
case SCSI_READ_TOC_PMA_ATIP:
goto sendcmd;
goto sendcmd;
case SCSI_REPAIR_TRACK:
goto sendcmd;
case SCSI_REPORT_KEY:
goto sendcmd;
case SCSI_REQUEST_SENSE:
goto sendcmd;
case SCSI_RESERVE_TRACK:
goto sendcmd;
case SCSI_SCAN:
goto sendcmd;
case SCSI_SEEK_10:
goto sendcmd;
case SCSI_SEND_CUE_SHEET:
goto sendcmd;
case SCSI_SEND_DVD_STRUCTURE:
goto sendcmd;
case SCSI_SEND_EVENT:
goto sendcmd;
case SCSI_SEND_KEY:
goto sendcmd;
goto sendcmd;
case SCSI_SET_CD_SPEED:
goto sendcmd;
case SCSI_SET_READ_AHEAD:
goto sendcmd;
case SCSI_SET_STREAMING:
goto sendcmd;
case SCSI_START_STOP_UNIT:
goto sendcmd;
case SCSI_STOP_PLAY_SCAN:
goto sendcmd;
case SCSI_SYNCHRONIZE_CACHE:
goto sendcmd;
case SCSI_TEST_UNIT_READY:
goto sendcmd;
case SCSI_VERIFY_10:
goto sendcmd;
case SCSI_WRITE_10:
goto sendcmd;
case SCSI_WRITE_12:
goto sendcmd;
case SCSI_WRITE_AND_VERIFY_10:
goto sendcmd;
case SCSI_WRITE_BUFFER:
LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
goto sendcmd;
goto sendcmd;
case SCSI_REZERO_UNIT:
LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
if (cbTransfer == 0)
return AHCITXDIR_NONE;
#ifdef DEBUG
Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
return enmTxDir;
int rc;
/* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
bool fInterrupt)
bool fAssertIntr = false;
if (fInterrupt)
fAssertIntr = true;
if (fAssertIntr)
static void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
bool fAssertIntr = false;
fAssertIntr = true;
else if (fInterrupt)
fAssertIntr = true;
if (fAssertIntr)
bool fAssertIntr = false;
sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
sdbFis[0] = 0;
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;
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
return cbCopied;
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
return cbCopied;
return VERR_NO_MEMORY;
return VINF_SUCCESS;
bool fCopyToGuest)
&& fCopyToGuest)
bool fXchg = false;
if (fXchg)
return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
unsigned cRangesMax;
unsigned cRanges = 0;
AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
if (!cPrdtlEntries)
return VINF_SUCCESS;
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
cRanges++;
} while (cPrdtlEntries);
return VERR_BUFFER_OVERFLOW;
RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
idxRange++;
return rc;
bool fXchg = false;
bool fRedo = false;
if (fXchg)
if (!fRedo)
if (!fRedo)
if (fFreeReq)
return VINF_SUCCESS;
static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
return rc;
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:
int rc2;
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_DEVICE_RESET:
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_SLEEP:
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_READ_LOG_EXT:
LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
switch (iPage)
if (pTaskErr)
case ATA_DATA_SET_MANAGEMENT:
case ATA_SECURITY_FREEZE_LOCK:
case ATA_SMART:
case ATA_NV_CACHE:
case ATA_IDLE:
return rc;
AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
#ifdef DEBUG
GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
AssertMsg((pAhciReq->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, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->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.
pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
#ifdef DEBUG
ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
unsigned idx = 0;
while (idx)
idx--;
bool fXchg;
/* 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. */
pAhciReq);
rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
pAhciReq);
pAhciReq);
unsigned idx = 0;
return VINF_SUCCESS;
if (!pAhciReq)
return VERR_NO_MEMORY;
if (!u64StartTime)
while ( idx
idx--;
AssertMsg(pAhciReq->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number %u!!\n", __FUNCTION__, pAhciReq->uTag));
bool fXchg;
/* 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. */
AssertMsg(!(cbTransfer % 512), ("Number of bytes to process is not sector aligned %lu\n", cbTransfer));
#ifdef DEBUG
ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
u64StartTime = 0;
uIORequestsProcessed = 0;
return VINF_SUCCESS;
bool fFinished;
if (!fFinished)
return VINF_SUCCESS;
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++)
int rc;
if (u32IOBuffer)
return rc;
if (u32 != ~0U)
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
int rc;
uVersion++;
bool fInUse;
N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
return rc;
return rc;
return VINF_SUCCESS;
uint32_t i;
unsigned iActPort = 0;
return rc;
switch (OldStatus)
LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
return VERR_PDM_MISSING_INTERFACE;
return VERR_PDM_MISSING_INTERFACE;
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;
pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
return rc;
PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
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),
return rc;
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 = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
return rc;
return rc;
return VINF_SUCCESS;
bool fGCEnabled = false;
bool fR0Enabled = false;
rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
#ifdef VBOX_WITH_MSI_DEVICES
return rc;
#ifdef VBOX_WITH_MSI_DEVICES
* 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
return rc;
return rc;
return rc;
for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, 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_USED, 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_USED, 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_USED, 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_USED, STAMUNIT_NS_PER_CALL,
"Amount of time to destroy the scatter gather list and free associated resources.", "/Devices/SATA%d/Port%d/ProfileDestroyScatterGatherList", iInstance, i);
rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
return rc;
return rc;
rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
return rc;
sizeof(AHCI),
NULL,
NULL,
NULL,
NULL,
NULL,