DevAHCI.cpp revision 24ca3d27f14cf8a03b8448f6d0898110e915d46a
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * DevAHCI - AHCI controller device (disk and cdrom).
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Implements the AHCI standard 1.1
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Copyright (C) 2006-2013 Oracle Corporation
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * available from http://www.virtualbox.org. This file is free software;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * you can redistribute it and/or modify it under the terms of the GNU
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * General Public License (GPL) as published by the Free Software
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * This component implements an AHCI serial ATA controller. The device is split
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * into two parts. The first part implements the register interface for the
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * guest and the second one does the data transfer.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * The guest can access the controller in two ways. The first one is the native
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * way implementing the registers described in the AHCI specification and is
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * the preferred one. The second implements the I/O ports used for booting from
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * the hard disk and for guests which don't have an AHCI SATA driver.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * The data is transferred in an asynchronous way using one thread per implemented
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * port or using the new async completion interface which is still under
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * development. [not quite up to date]
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/*******************************************************************************
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync* Header Files *
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync*******************************************************************************/
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync//#define DEBUG
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync && defined(IN_RING3) \
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define VBOXDD_AHCI_REQ_SUBMIT(a,b,c,d) do { } while (0)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(a,b) do { } while (0)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define VBOXDD_AHCI_REQ_COMPLETED(a,b,c,d,e) do { } while (0)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(a,b) do { } while (0)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Maximum number of ports available.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Spec defines 32 but we have one allocated for command completion coalescing
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * and another for a reserved future feature.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Maximum number of command slots available. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The current saved state version. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Saved state version before legacy ATA emulation was dropped. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Saved state version before ATAPI support was added. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The saved state version use in VirtualBox 3.0 and earlier.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * This was before the config was added and ahciIOTasks was dropped. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* for Older ATA state Read handling */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The maximum number of release log entries per device. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Set to 1 to disable multi-sector read support. According to the ATA
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * specification this must be a power of 2 and it must fit in an 8 bit
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Fastest PIO mode supported by the drive.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Fastest MDMA mode supported by the drive.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Fastest UDMA mode supported by the drive.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Length of the configurable VPD data (without termination)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* MediaEventStatus */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_EVENT_STATUS_UNCHANGED 0 /**< medium event status not changed */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_EVENT_STATUS_MEDIA_NEW 1 /**< new medium inserted */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_EVENT_STATUS_MEDIA_REMOVED 2 /**< medium removed */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_EVENT_STATUS_MEDIA_CHANGED 3 /**< medium was removed + new medium was inserted */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED 4 /**< medium eject requested (eject button pressed) */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* Media track type */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** ATAPI sense info size. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Command Header.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsynctypedef struct
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Description Information. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command status. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command Table Base Address. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command Table Base Address - upper 32-bits. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Reserved */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* Defines for the command header. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* Defines for the command FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* Defines that are used in the first double word. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/* For D2H FIS */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Pointer to a task state. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Data processing callback
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @returns VBox status.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @param pAhciReq The task state.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @param ppvProc Where to store the pointer to the buffer holding the processed data on success.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Must be freed with RTMemFree().
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @param pcbProc Where to store the size of the buffer on success.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc);
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Pointer to a FNAHCIPOSTPROCESS() function. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Transfer type.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Invalid */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** None */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Read */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Write */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flush */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Trim */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Task state.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Invalid. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Task is not active. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Task is active */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Task was canceled but the request didn't completed yet. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** 32bit hack. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Task encountered a buffer overflow. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Request is a PIO data command, if this flag is not set it either is
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * a command which does not transfer data or a DMA command based on the transfer size. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** The request has the SACT register set. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** FLag whether the request is queued. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * A task state.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsynctypedef struct AHCIREQ
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Task state. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Start timestamp of the request. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Tag of the task. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The command header for this task. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The command Fis for this task. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The ATAPI command data. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Size of one sector for the ATAPI transfer. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Physical address of the command header. - GC */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Physical address if the PRDT */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Number of entries in the PRDTL. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Data direction. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Start offset. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Number of bytes to transfer. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** ATA error register */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** ATA status register */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flags for this task. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Additional memory allocation for this task. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Siize of the allocation. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Number of times we had too much memory allocated for the request. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Data dependent on the transfer direction. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Data for an I/O request. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Data segment. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Post processing callback.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * If this is set we will use a buffer for the data
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * and the callback returns a buffer with the final data. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Data for a trim request. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the array of ranges to trim. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Number of entries in the array. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Notifier queue item.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The core part owned by the queue manager. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The port to process. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @implements PDMIBASE
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @implements PDMIBLOCKPORT
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @implements PDMIBLOCKASYNCPORT
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * @implements PDMIMOUNTNOTIFY
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsynctypedef struct AHCIPort
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the device instance - HC ptr */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the device instance - R0 ptr */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the device instance - RC ptr. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the parent AHCI structure - R3 ptr. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the parent AHCI structure - R0 ptr. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the parent AHCI structure - RC ptr. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command List Base Address. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command List Base Address upper bits. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** FIS Base Address. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** FIS Base Address upper bits. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Interrupt Status. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Interrupt Enable. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Task File Data. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Signature */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Serial ATA Status. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Serial ATA Control. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Serial ATA Error. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Serial ATA Active. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command Issue. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Command List Base Address */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** FIS Base Address */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Current number of active tasks. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Device is powered on. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Device has spun up. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** First D2H FIS was send. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Attached device is a CD/DVD drive. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Passthrough SCSI commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flag whether this port is in a reset state. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync volatile bool fPortReset;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** If we use the new async interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flag if we are in a device reset. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flag whether the I/O thread idles. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Flag whether the port is in redo task mode. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync volatile bool fRedo;
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Number of total sectors. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Currently configured number of sectors in a multi-sector transfer. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** ATAPI sense data. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Exponent of logical sectors in a physical sector, number of logical sectors is 2^exp. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The same for GET_EVENT_STATUS for mechanism */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Media type if known. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The LUN. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Bitmap for finished tasks (R3 -> Guest). */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Bitmap for finished queued tasks (R3 -> Guest). */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Bitmap for new queued tasks (Guest -> R3). */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Current command slot processed.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Accessed by the guest by reading the CMD register.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Holds the command slot of the command processed at the moment. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Device specific settings (R3 only stuff). */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the attached driver's base interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the attached driver's block interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the attached driver's async block interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the attached driver's block bios interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Pointer to the attached driver's mount interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The base interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The block port interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The optional block async port interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The mount notify interface. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Physical geometry of this image. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The status LED state for this drive. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Async IO Thread. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Request semaphore. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Array of cached tasks. The tag number is the index value.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync * Only used with the async interface.
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync R3PTRTYPE(PAHCIREQ) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** First task throwing an error. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The current tracklist of the loaded medium if passthrough is used. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Release statistics: number of DMA commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Release statistics: number of bytes written. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Release statistics: number of bytes read. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Release statistics: Number of I/O requests processed per second. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Statistics: Time to complete one request. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Statistics: Amount of time to read/write data. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync#endif /* VBOX_WITH_STATISTICS */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The serial numnber to use for IDENTIFY DEVICE commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The firmware revision to use for IDENTIFY DEVICE commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The model number to use for IDENTIFY DEVICE commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The vendor identification string for SCSI INQUIRY commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The product identification string for SCSI INQUIRY commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** The revision string for SCSI INQUIRY commands. */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync /** Error counter */
74fe172698ba936102e120dae998c9ebd09cfbdfvboxsync/** Pointer to the state of an AHCI port. */
typedef struct AHCI
bool fReset;
bool f64BitAddr;
bool fGCEnabled;
bool fR0Enabled;
bool volatile fSignalIdle;
bool fBootable;
volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
} AHCI;
} SGLEntry;
#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
#define AHCI_PORT_SCTL_DET_NINIT 0
typedef struct ahci_opreg
const char *pszName;
} AHCIOPREG;
typedef struct pAhciPort_opreg
const char *pszName;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#ifdef IN_RING3
#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
#define PDMIBLOCKPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
#ifdef IN_RING3
# ifdef LOG_USE_C99
# define ahciLog(a) \
# define ahciLog(a) \
# ifdef LOG_USE_C99
# define ahciLog(a) \
# define ahciLog(a) \
# ifdef LOG_USE_C99
# define ahciLog(a) \
# define ahciLog(a) \
return rc;
return VINF_SUCCESS;
#ifdef IN_RING3
&& u32Value > 0)
PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
bool fAllTasksCanceled;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
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",
__FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
return VINF_SUCCESS;
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",
if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
#ifndef IN_RING3
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;
int 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;
PDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
return rc;
return rc;
Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
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: PDMDevHlpPCIPhysWrite 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 */
/* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
&& 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),
case SCSI_SEND_CUE_SHEET:
case SCSI_READ_TOC_PMA_ATIP:
case SCSI_SYNCHRONIZE_CACHE:
if (cbTransfer)
*pcbData = 0;
if (pvBuf)
return VINF_SUCCESS;
static int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
&cbTransfered);
PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
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:
case SCSI_READ_CD_MSF:
pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
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:
case SCSI_WRITE_AND_VERIFY_10:
pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
goto sendcmd;
case SCSI_WRITE_12:
pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
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;
bool fCanceled = false;
case AHCITXDIR_READ:
case AHCITXDIR_WRITE:
case AHCITXDIR_FLUSH:
case AHCITXDIR_TRIM:
if (fXchg)
if (!fRedo)
PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
if (!fRedo)
fCanceled = true;
if (fFreeReq)
return fCanceled;
static DECLCALLBACK(int) ahciR3TransferCompleteNotify(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. */
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
bool fReqCanceled = false;
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
if (fReqCanceled)
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;
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 = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
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;
return rc;
bool fGCEnabled = false;
bool fR0Enabled = false;
rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
#ifdef VBOX_WITH_MSI_DEVICES
for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
return rc;
return rc;
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;
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->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);
rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
return rc;
return rc;
rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
return rc;
sizeof(AHCI),
NULL,
NULL,
NULL,
NULL,
NULL,