DevAHCI.cpp revision 6453ab7aee83b53063ef339e594e5499de3f607c
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * DevAHCI - AHCI controller device (disk and cdrom).
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * Implements the AHCI standard 1.1
ef0576b151f3ad77ecefe5f4641d5d7f0caedafcvboxsync * Copyright (C) 2006-2013 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * This component implements an AHCI serial ATA controller. The device is split
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * into two parts. The first part implements the register interface for the
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * guest and the second one does the data transfer.
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * The guest can access the controller in two ways. The first one is the native
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * way implementing the registers described in the AHCI specification and is
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * the preferred one. The second implements the I/O ports used for booting from
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * the hard disk and for guests which don't have an AHCI SATA driver.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * The data is transferred in an asynchronous way using one thread per implemented
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * port or using the new async completion interface which is still under
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * development. [not quite up to date]
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync && defined(IN_RING3) \
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync# define VBOXDD_AHCI_REQ_SUBMIT(a,b,c,d) do { } while (0)
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync# define VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(a,b) do { } while (0)
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync# define VBOXDD_AHCI_REQ_COMPLETED(a,b,c,d,e) do { } while (0)
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync# define VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(a,b) do { } while (0)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync/** Maximum number of ports available.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * Spec defines 32 but we have one allocated for command completion coalescing
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * and another for a reserved future feature.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync/** Maximum number of command slots available. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/** The current saved state version. */
f20f7cf8c2a0f141965d11345d910cc8e65c1fb3vboxsync/** The saved state version before changing the port reset logic in an incompatible way. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync#define AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES 7
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync/** Saved state version before the per port hotplug port was added. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync/** Saved state version before legacy ATA emulation was dropped. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync/** Saved state version before ATAPI support was added. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/** The saved state version use in VirtualBox 3.0 and earlier.
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * This was before the config was added and ahciIOTasks was dropped. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync/* for Older ATA state Read handling */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
f11eaffbbd9153a62d2c6eb3ec1810947c956802vboxsync/** The maximum number of release log entries per device. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set to 1 to disable multi-sector read support. According to the ATA
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * specification this must be a power of 2 and it must fit in an 8 bit
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest PIO mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest MDMA mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest UDMA mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Length of the configurable VPD data (without termination)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/* MediaEventStatus */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATA_EVENT_STATUS_UNCHANGED 0 /**< medium event status not changed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATA_EVENT_STATUS_MEDIA_NEW 1 /**< new medium inserted */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATA_EVENT_STATUS_MEDIA_REMOVED 2 /**< medium removed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATA_EVENT_STATUS_MEDIA_CHANGED 3 /**< medium was removed + new medium was inserted */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED 4 /**< medium eject requested (eject button pressed) */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync/* Media track type */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/** ATAPI sense info size. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Command Header.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Description Information. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command status. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Table Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Table Base Address - upper 32-bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command header. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines that are used in the first double word. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_H2D 0x27 /* Register - Host to Device FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_H2D_SIZE 20 /* Five double words. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_D2H 0x34 /* Register - Device to Host FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_D2H_SIZE 20 /* Five double words. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS 0xa1 /* Set Device Bits - Device to Host FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE 8 /* Two double words. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H 0x39 /* DMA Activate - Device to Host FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE 4 /* One double word. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_DMASETUP 0x41 /* DMA Setup - Bidirectional FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_DMASETUP_SIZE 28 /* Seven double words. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP 0x5f /* PIO Setup - Device to Host FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_PIOSETUP_SIZE 20 /* Five double words. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_TYPE_DATA 0x46 /* Data - Bidirectional FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_BITS 1 /* Interrupt and Update bit. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_C RT_BIT(7) /* Host to device. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_I RT_BIT(6) /* Device to Host. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_CTL_SRST RT_BIT(2) /* Reset device. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_CMDFIS_CTL_NIEN RT_BIT(1) /* Assert or clear interrupt. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* For D2H FIS */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/** Pointer to a task state. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Data processing callback
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * @returns VBox status.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The task state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param ppvProc Where to store the pointer to the buffer holding the processed data on success.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Must be freed with RTMemFree().
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pcbProc Where to store the size of the buffer on success.
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/** Pointer to a FNAHCIPOSTPROCESS() function. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync * Transfer type.
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Invalid */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** None */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Read */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Write */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Flush */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync /** Trim */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Task state.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Invalid. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task is not active. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task is active */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task was canceled but the request didn't completed yet. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** 32bit hack. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync/** Task encountered a buffer overflow. */
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync/** Request is a PIO data command, if this flag is not set it either is
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * a command which does not transfer data or a DMA command based on the transfer size. */
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync/** The request has the SACT register set. */
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync/** FLag whether the request is queued. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * A task state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef struct AHCIREQ
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task state. */
3b5486d99a3b391015873e5524bb1974d6dd3935vboxsync /** Start timestamp of the request. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Tag of the task. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The command header for this task. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The command Fis for this task. */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** The ATAPI command data. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** Size of one sector for the ATAPI transfer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Physical address of the command header. - GC */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Physical address if the PRDT */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Number of entries in the PRDTL. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data direction. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Start offset. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of bytes to transfer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATA error register */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATA status register */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Flags for this task. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Additional memory allocation for this task. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Siize of the allocation. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Number of times we had too much memory allocated for the request. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data dependent on the transfer direction. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data for an I/O request. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data segment. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Post processing callback.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * If this is set we will use a buffer for the data
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * and the callback returns a buffer with the final data. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data for a trim request. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Pointer to the array of ranges to trim. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Number of entries in the array. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Notifier queue item.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The core part owned by the queue manager. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The port to process. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBASE
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBLOCKPORT
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBLOCKASYNCPORT
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIMOUNTNOTIFY
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCIPort
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - RC ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - R3 ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - R0 ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - RC ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address upper bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address upper bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Status. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Enable. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Task File Data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Signature */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Status. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Control. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Error. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Issue. */
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync /** Current number of active tasks. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device is powered on. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device has spun up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** First D2H FIS was send. */
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Attached device is a CD/DVD drive. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** Passthrough SCSI commands. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag whether this port is in a reset state. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile bool fPortReset;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** If we use the new async interface. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag if we are in a device reset. */
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync /** Flag whether this port is hot plug capable. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag whether the port is in redo task mode. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile bool fRedo;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync /** Flag whether the worker thread is sleeping. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Number of total sectors. */
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync /** Size of one sector. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Currently configured number of sectors in a multi-sector transfer. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** ATAPI sense data. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync /** Exponent of logical sectors in a physical sector, number of logical sectors is 2^exp. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The same for GET_EVENT_STATUS for mechanism */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Media type if known. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The LUN. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for finished tasks (R3 -> Guest). */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for finished queued tasks (R3 -> Guest). */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for new queued tasks (Guest -> R3). */
3d40799173fcdd842291c870033d85379d731a4avboxsync /** Bitmap of tasks which must be redone because of a non fatal error. */
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /** Current command slot processed.
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * Accessed by the guest by reading the CMD register.
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * Holds the command slot of the command processed at the moment. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Device specific settings (R3 only stuff). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's base interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's block interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's async block interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's block bios interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's mount interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The base interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The block port interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The optional block async port interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The mount notify interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Physical geometry of this image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The status LED state for this drive. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Async IO Thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Array of cached tasks. The tag number is the index value.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only used with the async interface.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync R3PTRTYPE(PAHCIREQ) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /** First task throwing an error. */
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync /** The current tracklist of the loaded medium if passthrough is used. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync /** The event semaphore the processing thread waits on. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of DMA commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of bytes written. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of bytes read. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: Number of I/O requests processed per second. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Time to complete one request. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Amount of time to read/write data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* VBOX_WITH_STATISTICS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The serial numnber to use for IDENTIFY DEVICE commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The firmware revision to use for IDENTIFY DEVICE commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1]; /** < one extra byte for termination */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The model number to use for IDENTIFY DEVICE commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1]; /** < one extra byte for termination */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync /** The vendor identification string for SCSI INQUIRY commands. */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync char szInquiryVendorId[AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH+1];
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync /** The product identification string for SCSI INQUIRY commands. */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync char szInquiryProductId[AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH+1];
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync /** The revision string for SCSI INQUIRY commands. */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync char szInquiryRevision[AHCI_ATAPI_INQUIRY_REVISION_LENGTH+1];
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync /** Error counter */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/** Pointer to the state of an AHCI port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Main AHCI device state.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMILEDPORTS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCI
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The PCI device structure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R3 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - RC ptr. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: The base interface. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: Leds interface. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: Partner of ILeds. */
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync /** Status LUN: Media Notifys. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Base address of the MMIO region. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /** Base address of the I/O port region for Idx/Data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Global Host Control register of the HBA */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HBA Capabilities - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HBA Control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Status */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Ports Implemented - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** AHCI Version - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command completion coalescing control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command completion coalescing ports */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /** Index register for BIOS access. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - R3 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - RC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - RC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Which port number is used to mark an CCC interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Timeout value */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of completions used to assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Current number of completed commands */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Register structure per port */
8b82f5ce032cb07de31804c998483b0988530aebvboxsync /** The critical section. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Bitmask of ports which asserted an interrupt. */
c4e862df22b8c582055b945e086a51957e913e6bvboxsync /** Number of I/O threads currently active - used for async controller reset handling. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device is in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Supports 64bit addressing */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** GC enabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** R0 enabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** If the new async interface is used if available. */
9083f76e8c5709604766d0215a380de516e781eevboxsync /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
9083f76e8c5709604766d0215a380de516e781eevboxsync * a port is entering the idle state. */
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync bool volatile fSignalIdle;
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync /** Flag whether the controller has BIOS access enabled. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync /** Flag whether the legacy port reset method should be used to make it work with saved states. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of usable ports on this controller. */
3649373f921ada8549bf86c6edb03b340f2d214avboxsync /** Number of usable command slots for each port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync /** The support driver session handle. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/** Pointer to the state of an AHCI device. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Scatter gather list entry.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data Base Address - Upper 32-bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Description information. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Defines for a scatter gather list entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the global host control registers for the HBA. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Capabilities - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_ISS (RT_BIT(23) | RT_BIT(22) | RT_BIT(21) | RT_BIT(20))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_HBA_CAP_ISS_SHIFT(x) (((x) << 20) & AHCI_HBA_CAP_ISS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_NCS (RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_NCS_SET(x) (((x-1) << 8) & AHCI_HBA_CAP_NCS) /* 0's based */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_NP (RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_NP_SET(x) ((x-1) & AHCI_HBA_CAP_NP) /* 0's based */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Control register - Read/Write */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command completion coalescing control register */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the port registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
b8d7fd85fc9270b7ad49b0e1af2cafec0b9ec818vboxsync#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ASP RT_BIT(27) /* Not supported - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ALPE RT_BIT(26) /* Not supported - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CCS (RT_BIT(8) | RT_BIT(9) | RT_BIT(10) | RT_BIT(11) | RT_BIT(12))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CCS_SHIFT(x) (x << 8) /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_IPM (RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_IPM_GET(x) ((x & AHCI_PORT_SCTL_IPM) >> 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_SPD (RT_BIT(7) | RT_BIT(6) | RT_BIT(5) | RT_BIT(4))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_SPD_GET(x) ((x & AHCI_PORT_SCTL_SPD) >> 4)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_DET (RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SSTS_DET_GET(x) (x & AHCI_PORT_SCTL_DET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Signatures for attached storage devices. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The AHCI spec defines an area of memory where the HBA posts received FIS's from the device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * regFB points to the base of this area.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Every FIS type has an offset where it is posted in this area.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RECFIS_DSFIS_OFFSET 0x00 /* DMA Setup FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RECFIS_PSFIS_OFFSET 0x20 /* PIO Setup FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RECFIS_RFIS_OFFSET 0x40 /* D2H Register FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RECFIS_SDBFIS_OFFSET 0x58 /* Set Device Bits FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RECFIS_UFIS_OFFSET 0x60 /* Unknown FIS type */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync/** Mask to get the LBA value from a LBA range. */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync#define AHCI_RANGE_LBA_MASK UINT64_C(0xffffffffffff)
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync/** Mas to get the length value from a LBA range. */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync#define AHCI_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000)
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync/** Returns the length of the range in sectors. */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync#define AHCI_RANGE_LENGTH_GET(val) (((val) & AHCI_RANGE_LENGTH_MASK) >> 48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * AHCI register operator.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct ahci_opreg
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pszName;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int (*pfnRead )(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int (*pfnWrite)(PAHCI ahci, uint32_t iReg, uint32_t u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * AHCI port register operator.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const char *pszName;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int (*pfnRead )(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int (*pfnWrite)(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsyncstatic bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PCIDEV_2_PAHCI(pPciDev) ( (PAHCI)(pPciDev) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIMOUNT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMount)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IMountNotify)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIBASE_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IBase)) )
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync#define PDMIBLOCKPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCIPort, IPort)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIBASE_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, IBase)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMILEDPORTS_2_PAHCI(pInterface) ( (PAHCI)((uintptr_t)(pInterface) - RT_OFFSETOF(AHCI, ILeds)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Update PCI IRQ levels
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsyncstatic int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset command completion coalescing state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If only the bit of the actual port is set assert an interrupt
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * because the interrupt status register was already read by the guest
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and we need to send a new notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Otherwise an interrupt is still pending.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Assert irq when an CCC timeout occurs
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
051b18f951bde6348786628efc9298a2595e3494vboxsync * Finishes the port reset of the given port.
051b18f951bde6348786628efc9298a2595e3494vboxsync * @returns nothing.
051b18f951bde6348786628efc9298a2595e3494vboxsync * @param pAhciPort The port to finish the reset on.
051b18f951bde6348786628efc9298a2595e3494vboxsyncstatic void ahciPortResetFinish(PAHCIPort pAhciPort)
051b18f951bde6348786628efc9298a2595e3494vboxsync /* Cancel all tasks first. */
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync bool fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort, NULL);
051b18f951bde6348786628efc9298a2595e3494vboxsync /* Signature for SATA device. */
051b18f951bde6348786628efc9298a2595e3494vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
051b18f951bde6348786628efc9298a2595e3494vboxsync (0x03 << 0); /* Device detected and communication established. */
051b18f951bde6348786628efc9298a2595e3494vboxsync * Use the maximum allowed speed.
051b18f951bde6348786628efc9298a2595e3494vboxsync * (Not that it changes anything really)
051b18f951bde6348786628efc9298a2595e3494vboxsync switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
051b18f951bde6348786628efc9298a2595e3494vboxsync pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
051b18f951bde6348786628efc9298a2595e3494vboxsync pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
051b18f951bde6348786628efc9298a2595e3494vboxsync /* We received a COMINIT from the device. Tell the guest. */
051b18f951bde6348786628efc9298a2595e3494vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
051b18f951bde6348786628efc9298a2595e3494vboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
051b18f951bde6348786628efc9298a2595e3494vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
051b18f951bde6348786628efc9298a2595e3494vboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
051b18f951bde6348786628efc9298a2595e3494vboxsync * Kicks the I/O thread from RC or R0.
051b18f951bde6348786628efc9298a2595e3494vboxsync * @returns nothing.
051b18f951bde6348786628efc9298a2595e3494vboxsync * @param pAhci The AHCI controller instance.
051b18f951bde6348786628efc9298a2595e3494vboxsync * @param pAhciPort The port to kick.
051b18f951bde6348786628efc9298a2595e3494vboxsyncstatic void ahciIoThreadKick(PAHCI pAhci, PAHCIPort pAhciPort)
051b18f951bde6348786628efc9298a2595e3494vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
051b18f951bde6348786628efc9298a2595e3494vboxsync AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
051b18f951bde6348786628efc9298a2595e3494vboxsync PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
051b18f951bde6348786628efc9298a2595e3494vboxsync int rc = SUPSemEventSignal(pAhci->pSupDrvSession, pAhciPort->hEvtProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Update the CI register first. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Clear all tasks which are already marked as busy. The guest
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * shouldn't write already busy tasks actually.
051b18f951bde6348786628efc9298a2595e3494vboxsync /* Send a notification to R3 if u32TasksNew was 0 before our write. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync if (ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_SCTL_IPM_GET(u32Value), AHCI_PORT_SCTL_SPD_GET(u32Value), AHCI_PORT_SCTL_DET_GET(u32Value)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
56bef151ea50f63620466fce377458ce5fd0967avboxsync if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%u: Port %d reset\n", ahci->CTX_SUFF(pDevIns)->iInstance,
a590a3ddfb8b7b634260e7879e45cd562c9397ecvboxsync else if ( (u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT
a590a3ddfb8b7b634260e7879e45cd562c9397ecvboxsync && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync /* Do the port reset here, so the guest sees the new status immediately. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync pAhciPort->regSCTL = u32Value; /* Update after finishing the reset, so the I/O thread doesn't get a chance to do the reset. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync pAhciPort->regSSTS = 0x1; /* Indicate device presence detected but communication not established. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync pAhciPort->regSCTL = u32Value; /* Update before kicking the I/O thread. */
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync /* Kick the thread to finish the reset. */
104d8d8a62631fa624f462905aa9f49a858b0d8cvboxsync else /* Just update the value if there is no device attached. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSCTL=%#010x\n", __FUNCTION__, pAhciPort->regSCTL));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_SCTL_IPM_GET(pAhciPort->regSCTL), AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSSTS=%#010x\n", __FUNCTION__, pAhciPort->regSSTS));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: IPM=%d SPD=%d DET=%d\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_SSTS_IPM_GET(pAhciPort->regSSTS), AHCI_PORT_SSTS_SPD_GET(pAhciPort->regSSTS),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regTFD=%#010x\n", __FUNCTION__, pAhciPort->regTFD));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ERR=%x BSY=%d DRQ=%d ERR=%d\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regTFD >> 8), (pAhciPort->regTFD & AHCI_PORT_TFD_BSY) >> 7,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regTFD & AHCI_PORT_TFD_DRQ) >> 3, (pAhciPort->regTFD & AHCI_PORT_TFD_ERR)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
b62f86b93654223916ae6e71c266ab9aa9ac4247vboxsync ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (pAhciPort->regCMD & AHCI_PORT_CMD_ICC) >> 28, (pAhciPort->regCMD & AHCI_PORT_CMD_ASP) >> 27,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ALPE) >> 26, (pAhciPort->regCMD & AHCI_PORT_CMD_DLAE) >> 25,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ATAPI) >> 24, (pAhciPort->regCMD & AHCI_PORT_CMD_CPD) >> 20,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISP) >> 19, (pAhciPort->regCMD & AHCI_PORT_CMD_HPCP) >> 18,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_PMA) >> 17, (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) >> 16,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_CR) >> 15, (pAhciPort->regCMD & AHCI_PORT_CMD_FR) >> 14,
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, pAhciPort->u32CurrentCommandSlot,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_FRE) >> 4, (pAhciPort->regCMD & AHCI_PORT_CMD_CLO) >> 3,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_POD) >> 2, (pAhciPort->regCMD & AHCI_PORT_CMD_SUD) >> 1,
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is the register where all the data transfer is started
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (u32Value & AHCI_PORT_CMD_ICC) >> 28, (u32Value & AHCI_PORT_CMD_ASP) >> 27,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_ALPE) >> 26, (u32Value & AHCI_PORT_CMD_DLAE) >> 25,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_ATAPI) >> 24, (u32Value & AHCI_PORT_CMD_CPD) >> 20,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_ISP) >> 19, (u32Value & AHCI_PORT_CMD_HPCP) >> 18,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_PMA) >> 17, (u32Value & AHCI_PORT_CMD_CPS) >> 16,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_CR) >> 15, (u32Value & AHCI_PORT_CMD_FR) >> 14,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_ISS) >> 13, (u32Value & AHCI_PORT_CMD_CCS) >> 8,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_FRE) >> 4, (u32Value & AHCI_PORT_CMD_CLO) >> 3,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_POD) >> 2, (u32Value & AHCI_PORT_CMD_SUD) >> 1,
b62f86b93654223916ae6e71c266ab9aa9ac4247vboxsync /* The PxCMD.CCS bits are R/O and maintained separately. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command list override requested\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear the CLO bit. */
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync * Set engine state to running if there is a device attached and
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync * IS.PCS is clear.
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync /* If there is something in CI, kick the I/O thread. */
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync && ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping))
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksNew, pAhciPort->regCI);
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync int rc = SUPSemEventSignal(ahci->pSupDrvSession, pAhciPort->hEvtProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear command issue register. */
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync /* Clear current command slot. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Power on the device\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set states in the Port Signature and SStatus registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x03 << 0); /* Device detected and communication established. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Spin up the device\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Send the first D2H FIS only if it wasn't already send. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port interrupt enable register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regIE=%#010x\n", __FUNCTION__, pAhciPort->regIE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (pAhciPort->regIE & AHCI_PORT_IE_CPDE) >> 31, (pAhciPort->regIE & AHCI_PORT_IE_TFEE) >> 30,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_HBFE) >> 29, (pAhciPort->regIE & AHCI_PORT_IE_HBDE) >> 28,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_IFE) >> 27, (pAhciPort->regIE & AHCI_PORT_IE_INFE) >> 26,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_OFE) >> 24, (pAhciPort->regIE & AHCI_PORT_IE_IPME) >> 23,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_PRCE) >> 22, (pAhciPort->regIE & AHCI_PORT_IE_DIE) >> 7,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_PCE) >> 6, (pAhciPort->regIE & AHCI_PORT_IE_DPE) >> 5,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_UFE) >> 4, (pAhciPort->regIE & AHCI_PORT_IE_SDBE) >> 3,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIE & AHCI_PORT_IE_DSE) >> 2, (pAhciPort->regIE & AHCI_PORT_IE_PSE) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port interrupt enable register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (u32Value & AHCI_PORT_IE_CPDE) >> 31, (u32Value & AHCI_PORT_IE_TFEE) >> 30,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_HBFE) >> 29, (u32Value & AHCI_PORT_IE_HBDE) >> 28,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_IFE) >> 27, (u32Value & AHCI_PORT_IE_INFE) >> 26,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_OFE) >> 24, (u32Value & AHCI_PORT_IE_IPME) >> 23,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_PRCE) >> 22, (u32Value & AHCI_PORT_IE_DIE) >> 7,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_PCE) >> 6, (u32Value & AHCI_PORT_IE_DPE) >> 5,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_UFE) >> 4, (u32Value & AHCI_PORT_IE_SDBE) >> 3,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_IE_DSE) >> 2, (u32Value & AHCI_PORT_IE_PSE) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if some a interrupt status bit changed*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = ahciHbaSetInterrupt(ahci, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regIS=%#010x\n", __FUNCTION__, pAhciPort->regIS));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (pAhciPort->regIS & AHCI_PORT_IS_CPDS) >> 31, (pAhciPort->regIS & AHCI_PORT_IS_TFES) >> 30,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_HBFS) >> 29, (pAhciPort->regIS & AHCI_PORT_IS_HBDS) >> 28,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_IFS) >> 27, (pAhciPort->regIS & AHCI_PORT_IS_INFS) >> 26,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_OFS) >> 24, (pAhciPort->regIS & AHCI_PORT_IS_IPMS) >> 23,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_PRCS) >> 22, (pAhciPort->regIS & AHCI_PORT_IS_DIS) >> 7,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_PCS) >> 6, (pAhciPort->regIS & AHCI_PORT_IS_DPS) >> 5,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_UFS) >> 4, (pAhciPort->regIS & AHCI_PORT_IS_SDBS) >> 3,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regIS & AHCI_PORT_IS_DSS) >> 2, (pAhciPort->regIS & AHCI_PORT_IS_PSS) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port FIS base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port FIS base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port FIS base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port FIS base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command list base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command list base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command list base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command list base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global Version register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global Ports implemented register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_WRITE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Clear the interrupt only if no port has signalled
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * an interrupt and the guest has cleared all set interrupt
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * notification bits.
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync bool fClear = true;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fClear = !ahci->u32PortsInterrupted && !ahci->regHbaIs;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync unsigned i = 0;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync /* Check if the cleared ports have a interrupt status bit set. */
2d8894b1c178c9f1199cac84059ca66aa5dee6b3vboxsync while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We need to set the interrupt again because the I/O APIC does not set it again even if the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * line is still high.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We need to clear it first because the PCI bus only calls the interrupt controller if the state changes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInterruptStatus_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_READ);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32PortsInterrupted = ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaControl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: AE=%d IE=%d HR=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Increase the active thread counter because we might set the host controller
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * reset bit.
c4e862df22b8c582055b945e086a51957e913e6bvboxsync ASMAtomicWriteU32(&ahci->regHbaCtrl, (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Do the HBA reset if requested and there is no other active thread at the moment,
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * the work is deferred to the last active thread otherwise.
c4e862df22b8c582055b945e086a51957e913e6bvboxsync uint32_t cThreadsActive = ASMAtomicDecU32(&ahci->cThreadsActive);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaControl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: AE=%d IE=%d HR=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global capabilities register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCapabilities_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%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",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (ahci->regHbaCap & AHCI_HBA_CAP_S64A) >> 31, (ahci->regHbaCap & AHCI_HBA_CAP_SNCQ) >> 30,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SIS) >> 28, (ahci->regHbaCap & AHCI_HBA_CAP_SSS) >> 27,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SALP) >> 26, (ahci->regHbaCap & AHCI_HBA_CAP_SAL) >> 25,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SCLO) >> 24, (ahci->regHbaCap & AHCI_HBA_CAP_ISS) >> 20,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SNZO) >> 19, (ahci->regHbaCap & AHCI_HBA_CAP_SAM) >> 18,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SPM) >> 17, (ahci->regHbaCap & AHCI_HBA_CAP_PMD) >> 15,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_SSC) >> 14, (ahci->regHbaCap & AHCI_HBA_CAP_PSC) >> 13,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCap & AHCI_HBA_CAP_NCS) >> 8, (ahci->regHbaCap & AHCI_HBA_CAP_NP)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global command completion coalescing control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccCtl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: TV=%d CC=%d INT=%d EN=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(u32Value), AHCI_HBA_CCC_CTL_CC_GET(u32Value),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CCC_CTL_INT_GET(u32Value), (u32Value & AHCI_HBA_CCC_CTL_EN)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Arm the timer */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTimerSetMillies(ahci->CTX_SUFF(pHbaCccTimer), ahci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global command completion coalescing control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccCtl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: TV=%d CC=%d INT=%d EN=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, AHCI_HBA_CCC_CTL_TV_GET(ahci->regHbaCccCtl), AHCI_HBA_CCC_CTL_CC_GET(ahci->regHbaCccCtl),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CCC_CTL_INT_GET(ahci->regHbaCccCtl), (ahci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global command completion coalescing ports register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccPorts_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global command completion coalescing ports register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccPorts_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, ahci->regHbaCccPorts));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid write to global register
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInvalid_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid Port write.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortInvalid_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid Port read.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortInvalid_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register descriptor table for global HBA registers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register descriptor table for port registers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortReserved1", PortInvalid_r, PortInvalid_w}, /* Not used. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortTaskFileData", PortTaskFileData_r, PortInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortSignature", PortSignature_r, PortInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortSStatus", PortSStatus_r, PortInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset initiated by system software for one port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port to reset.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Cancel all tasks first. */
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort, NULL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync /* Hotplugging supported?. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ASMAtomicWriteU32(&pAhciPort->MediaTrackType, ATA_MEDIA_TYPE_UNKNOWN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set states in the Port Signature and SStatus registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x03 << 0); /* Device detected and communication established. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Hardware reset used for machine power on and reset.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciport The port to reset.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset the address registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset calculated addresses. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Create implemented ports bitmap.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns 32bit bitmask with a bit set for every implemented port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cPorts Number of ports.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint32_t ahciGetPortsImplemented(unsigned cPorts)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (unsigned i = 0; i < cPorts; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset the entire HBA.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThis The HBA state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%u: Reset the HBA\n", pThis->CTX_SUFF(pDevIns)->iInstance));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Stop the CCC timer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
d3faf04f5ef353bbc31bb75a17444d7902726d2evboxsync /* Reset every port */
d3faf04f5ef353bbc31bb75a17444d7902726d2evboxsync /* Init Global registers */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaCap = AHCI_HBA_CAP_ISS_SHIFT(AHCI_HBA_CAP_ISS_GEN2) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_S64A | /* 64bit addressing supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_CCCS | /* Support command completion coalescing */
3649373f921ada8549bf86c6edb03b340f2d214avboxsync AHCI_HBA_CAP_NCS_SET(pThis->cCmdSlotsAvail) | /* Number of command slots we support */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_NP_SET(pThis->cPortsImpl); /* Number of supported ports */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
6cb10f8ce31d79193cf8c98c8787cbed1232fbb8vboxsync /* Clear pending interrupts. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
d3faf04f5ef353bbc31bb75a17444d7902726d2evboxsync /* Clear the HBA Reset bit */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Reads from a AHCI controller register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pAhci The AHCI instance.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param uReg The register to write.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pv Where to store the result.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cb Number of bytes read.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncstatic int ahciRegisterRead(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the access offset is smaller than AHCI_HBA_GLOBAL_SIZE the guest accesses the global registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Otherwise it accesses the registers of a port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Calculate accessed port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Windows Vista tries to read one byte from some registers instead of four.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Correct the value according to the read size.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear old value */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync AssertMsgFailed(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Writes a value to one of the AHCI controller registers.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pAhci The AHCI instance.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * @param offReg The offset of the register to write to.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * @param u32Value The value to write.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsyncstatic int ahciRegisterWrite(PAHCI pAhci, uint32_t offReg, uint32_t u32Value)
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * If the access offset is smaller than 100h the guest accesses the global registers.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * Otherwise it accesses the registers of a port.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Calculate accessed port. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, u32Value);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Memory mapped I/O Handler for read operations.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pDevIns The device instance.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pvUser User argument.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param GCPhysAddr Physical address (in GC) where the read starts.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pv Where to store the result.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param cb Number of bytes read.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync int rc = ahciRegisterRead(pAhci, GCPhysAddr - pAhci->MMIOBase, pv, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("#%d ahciMMIORead: return pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Memory mapped I/O Handler for write operations.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pvUser User argument.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param GCPhysAddr Physical address (in GC) where the read starts.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pv Where to fetch the result.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cb Number of bytes to write.
6826c1a65f586b47c2abbbabab801950c9a0bb75vboxsyncPDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Break up 64 bits writes into two dword writes. */
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync /** @todo Eliminate this code once the IOM/EM starts taking care of these
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync * situations. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only write the first 4 bytes if they weren't already.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * It is possible that the last write to the register caused a world
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * switch and we entered this function again.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Writing the first 4 bytes again could cause indeterminate behavior
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * which can cause errors in the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset flag again so that the first 4 bytes are written again on the next
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 8byte MMIO access.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync /* Do the access. */
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n", pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync return ahciRegisterWrite(pAhci, GCPhysAddr - pAhci->MMIOBase, *(uint32_t const *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * I/O port handler for writes to the index/data register pair.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pDevIns The device instance.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pvUser User argument.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param Port Port address where the write starts.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pv Where to fetch the result.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param cb Number of bytes to write.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Write the index register. */
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync /** @todo range check? */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* else: ignore */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pDevIns->iInstance, &u32, cb, &u32, cb, Port, rc));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * I/O port handler for reads from the index/data register pair.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pDevIns The device instance.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pvUser User argument.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param Port Port address where the read starts.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pv Where to fetch the result.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param cb Number of bytes to write.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Read the index register. */
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync /** @todo range check? */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciRegisterRead(pAhci, pAhci->regIdx, pu32, cb);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pDevIns->iInstance, pu32, cb, pu32, cb, Port, rc));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync /** @todo change this to IOMMMIO_FLAGS_WRITE_ONLY_DWORD once EM/IOM starts
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync * handling 2nd DWORD failures on split accesses correctly. */
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD,
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Map the legacy I/O port ranges to make Solaris work with the controller.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLegacyFakeWrite, ahciLegacyFakeRead, NULL, NULL, "AHCI Fake");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Map the BMDMA I/O port range (used for the Index/Data pair register access)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncstatic DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, cb, NULL,
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync ahciIdxDataWrite, ahciIdxDataRead, NULL, NULL, "AHCI IDX/DATA");
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Gets the pointer to the status LED of a unit.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param iLUN The unit which status LED we desire.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param ppLed Where to store the LED pointer.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKPORT, &pAhciPort->IPort);
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNCPORT, &pAhciPort->IPortAsync);
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @interface_method_impl{PDMIBLOCKPORT,pfnQueryDeviceLocation}
cab115cfa31c584def7069312a1e23c3fc88533bvboxsyncstatic DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIBLOCKPORT pInterface, const char **ppcszController,
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync PAHCIPort pAhciPort = PDMIBLOCKPORT_2_PAHCIPORT(pInterface);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Dump info about the FIS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port the command FIS was read from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cmdFis The FIS to print info from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print FIS type. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command register update\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Control register update\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Dump info about the command header
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @param pAhciPort Pointer to the port the command header was read from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCmdHdr The command header to print info from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** Begin command header info dump. ***\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Number of Scatter/Gatther List entries: %u\n", __FUNCTION__, AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command FIS length %u DW\n", __FUNCTION__, (pCmdHdr->u32DescInf & AHCI_CMDHDR_CFL_MASK)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** End command header info dump. ***\n", __FUNCTION__));
f7ea3663e40eb08539d5047a6c31ca8e3e6e02f2vboxsync#endif /* LOG_ENABLED */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Post the first D2H FIS from the device into guest memory.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort Pointer to the port which "receives" the FIS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set the signature based on the device type. */
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port which "receives" the FIS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param uFisType The type of the FIS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCmdFis Pointer to the FIS which is to be posted into memory.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cbFis = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Determine the offset and size of the FIS based on uFisType. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We should post the unknown FIS into memory too but this never happens because
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * we know which FIS types we generate. ;)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Post the FIS into memory. */
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync ahciLog(("%s: PDMDevHlpPCIPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void atapiCmdOK(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync | ((pAhciReq->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync | (!pAhciReq->cbTransfer ? ATAPI_INT_REASON_CD : 0);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13])));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/** @todo deprecated function - doesn't provide enough info. Replace by direct
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * calls to atapiCmdError() with full data. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsyncstatic uint32_t ataChecksum(void* ptr, size_t count)
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync for (i = 0; i < count; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[1] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[3] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Block size; obsolete, but required for the BIOS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[6] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[54] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[55] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cHeads);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[56] = RT_H2LE_U16(pAhciPort->PCHSGeometry.cSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[57] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[58] = RT_H2LE_U16(RT_MIN(pAhciPort->PCHSGeometry.cCylinders, 16383) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors >> 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Report maximum number of sectors possible with LBA28 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync p[81] = RT_H2LE_U16(0x28); /* conforms to ATA/ATAPI-8 ACS */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[101] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[102] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[103] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 48);
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync /* valid information, more than one logical sector per physical sector, 2^cLogSectorsPerPhysicalExp logical sectors per physical sector */
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync p[106] = RT_H2LE_U16(RT_BIT(14) | RT_BIT(13) | pAhciPort->cLogSectorsPerPhysicalExp);
99afce7a96e1262ce137aa1fd4d2a911ebd644b1vboxsync uint32_t cSectorSizeInWords = pAhciPort->cbSector / sizeof(uint16_t);
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync /* Enable reporting of logical sector size. */
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync && pAhciPort->pDrvBlockAsync->pfnStartDiscard)) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The following are SATA specific */
3649373f921ada8549bf86c6edb03b340f2d214avboxsync p[75] = RT_H2LE_U16(pAhciPort->CTX_SUFF(pAhci)->cCmdSlotsAvail-1); /* Number of commands we support, 0's based */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef int (*PAtapiFunc)(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetConfigurationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetEventStatusNotificationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiIdentifySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiInquirySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiMechanismStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseErrorRecoverySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseCDStatusSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadCapacitySS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadDiscInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCNormalSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCMultiSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCRawSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTrackInformationSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiRequestSenseSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiPassthroughSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsyncstatic int atapiReadDVDStructureSS(PAHCIREQ, PAHCIPort, size_t, size_t *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Source/sink function indexes for g_apfnAtapiFuncs.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Array of source/sink functions, the index is ATAFNSS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Make sure ATAFNSS and this array match!
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiIdentifySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Removable CDROM, 50us response, 12 byte packets */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataPadString((uint8_t *)(p + 10), pAhciPort->szSerialNumber, AHCI_SERIAL_NUMBER_LENGTH); /* serial number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataPadString((uint8_t *)(p + 23), pAhciPort->szFirmwareRevision, AHCI_FIRMWARE_REVISION_LENGTH); /* firmware version */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataPadString((uint8_t *)(p + 27), pAhciPort->szModelNumber, AHCI_MODEL_NUMBER_LENGTH); /* model */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* MDMA modes supported / mode enabled */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, pAhciPort->uATATransferMode)); /* UDMA modes supported / mode enabled */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((pAhciPort->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The following are SATA specific */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[75] = RT_H2LE_U16(31); /* We support 32 commands */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[76] = RT_H2LE_U16((1 << 8) | (1 << 2)); /* Native command queuing and Serial ATA Gen2 (3.0 Gbps) speed supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&p[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadCapacitySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 1; /* first track number in last session (LSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 1; /* last track number in last session (LSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTrackInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Accept address/number type of 1 only, and only track 1 exists. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ((pAhciReq->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciReq->aATAPICmd[2]) != 1)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 8, 0); /* track start address is 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 24, pAhciPort->cTotalSectors); /* track size */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureListProfiles(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x0); /* feature 0: list of profiles supported */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* The MMC-3 spec says that DVD-ROM read capability should be reported
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync * before CD-ROM read capability. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 4, 0x10); /* profile: read-only DVD */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 8, 0x08); /* profile: read only CD */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureCore(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x1); /* feature 0001h: Core Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureMorphing(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureRemovableMedium(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x3); /* feature 0003h: Removable Medium Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Tray type loading | Load | Eject | !Pvnt Jmpr | !DBML | Lock */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[4] = (0x2 << 5) | RT_BIT(4) | RT_BIT(3) | (0x0 << 2) | (0x0 << 1) | RT_BIT(0);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureRandomReadable(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x10); /* feature 0010h: Random Readable Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U32(pbBuf + 4, 2048); /* Logical block size. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureCDRead(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x1e); /* feature 001Eh: CD Read Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeaturePowerManagement(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureTimeout(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Accept valid request types only, and only starting feature 0. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ((pAhciReq->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciReq->aATAPICmd[2]) != 0)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync * way to differentiate them right now is based on the image size). */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 6, 0x00); /* current profile: none -> no media */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureListProfiles(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureCore(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureMorphing(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureRemovableMedium(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureRandomReadable(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureCDRead(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeaturePowerManagement(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureTimeout(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Set data length now. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* no asynchronous operation supported */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* mount */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[5] = 0x02; /* medium present / door closed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* umount */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[4] = 0x01; /* eject requested (eject button pressed) */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[5] = 0x02; /* medium present / door closed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[2] = 0x01; /* operational change request / notification */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&abBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiInquirySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The following claims we support audio play. This is obviously false,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * but the Linux generic CDROM support makes many features depend on this
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * capability. If it's not set, this causes many things to be disabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[13] = 0x00; /* no subchannel reads supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvMount->pfnIsLocked(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[16], 5632); /* (obsolete) claim 32x speed support */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[18], 2); /* number of audio volume levels */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[20], 128); /* buffer size supported in Kbyte - We don't have a buffer because we write directly into guest memory.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Just write the value DevATA is using. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[22], 5632); /* (obsolete) current read speed 32x */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[25] = 0; /* reserved for digital audio (see idx 15) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[26], 0); /* (obsolete) maximum write speed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[28], 0); /* (obsolete) current write speed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[30], 0); /* copy management revision supported 0=no CSS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[36], 0); /* current write speed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiRequestSenseSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->abATAPISense, RT_MIN(cbData, sizeof(pAhciPort->abATAPISense)));
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* no current LBA */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* lead out track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCMultiSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* multi session: only a single session defined */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 1; /* first track in last complete session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCRawSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync * Sets the given media track type.
c825c31dbee005ba09e3c293433ae984f489a4bdvboxsyncstatic uint32_t ahciMediumTypeSet(PAHCIPort pAhciPort, uint32_t MediaTrackType)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync return ASMAtomicXchgU32(&pAhciPort->MediaTrackType, MediaTrackType);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf, cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Simple heuristics: if there is at least one sector of data
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * to transfer, it's worth updating the LEDs. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Linux accepts commands with up to 100KB of data, but expects
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * us to handle commands with up to 128KB of data. The usual
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * imbalance of powers. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t iATAPILBA, cSectors, cReqSectors, cbCurrTX;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cSectors = ataMSF2LBA(pAhciReq->aATAPICmd + 6) - iATAPILBA;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciReq->aATAPICmd[0]));
3689d0733b6efa19676293c493337c8b6948c8c8vboxsync LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync memcpy(aATAPICmd, pAhciReq->aATAPICmd, ATAPI_PACKET_SIZE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (i * pAhciReq->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgFailed(("Invalid transfer direction %d\n", pAhciReq->enmTxDir));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Update the LEDs and the read/write statistics. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync /* Do post processing for certain commands. */
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync rc = ATAPIPassthroughTrackListCreateEmpty(&pAhciPort->pTrackList);
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync rc = ATAPIPassthroughTrackListUpdate(pAhciPort->pTrackList, pAhciReq->aATAPICmd, pvBuf);
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync LogRel(("AHCI: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n",
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync rc, pAhciReq->aATAPICmd[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP"));
5032c360cee50ead84dff3f87825cb082b2c07bevboxsync ATAPIPassthroughTrackListClear(pAhciPort->pTrackList);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Make sure that the real drive cannot be identified.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Motivation: changing the VM configuration should be as
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * invisible as possible to the guest. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ataSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Reply with the same amount of data as the real drive. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf,
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* don't log superfluous errors */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n",
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->iLUN, u8Cmd, abATAPISense[2] & 0x0f, abATAPISense[12], abATAPISense[13], rc));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (0);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync/** @todo: Revise ASAP. */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync/* Keep in sync with DevATA.cpp! */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsyncstatic int atapiReadDVDStructureSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync uint8_t aBuf[25]; /* Counted a maximum of 20 bytes but better be on the safe side. */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync uint16_t max_len = ataBE2H_U16(&pAhciReq->aATAPICmd[8]);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* FIXME: 0x30000 per spec? */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync ataH2BE_U32(buf + 12, total_sectors - 1); /* end sector */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync ataH2BE_U32(buf + 16, total_sectors - 1); /* l0 end sector */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* Size of buffer, not including 2 byte size field */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* 2k data + 4 byte header */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* Size of buffer, not including 2 byte size field */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* 4 byte header + 4 byte data */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync case 0x03: /* BCA information - invalid field for no BCA info */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync case 0x04: /* DVD disc manufacturing information */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* Size of buffer, not including 2 byte size field */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* 2k data + 4 byte header */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync * This lists all the command capabilities above. Add new ones
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync * in order and update the length and buffer return values.
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* Size of buffer, not including 2 byte size field */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* data written + 4 byte header */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync default: /* TODO: formats beyond DVD-ROM requires */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, -uASC);
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync return false;
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* TODO: BD support, fall through for now */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* Generic disk structures */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync case 0x90: /* TODO: List of recognized format layers */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST,
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync return false;
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync /* Copy the buffer into the scatter gather list. */
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync return false;
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Write updated command header into memory of the guest. */
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBufSrc = (uint8_t *)pAhciReq->u.Io.DataSeg.pvSeg;
bb15489a522b0e9b94dfb262572e8ca1a9b6c995vboxsync size_t cbAlloc = pAhciReq->cbTransfer + cSectors * (1 + 11 + 3 + 1 + 288); /* Per sector data like ECC. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* sync bytes */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.pfnPostProcess = atapiReadSectors2352PostProcess;
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* Rate limited logging, one log line per second. For
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * guests that insist on reading from places outside the
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * valid area this often generates too many release log
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * entries otherwise. */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
23754115bd6df8b823a323c50acc83cf334b5facvboxsync if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* Rate limited logging, one log line per second. For
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * guests that insist on reading from places outside the
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * valid area this often generates too many release log
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * entries otherwise. */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* nothing */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* normal read */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* read all data */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* Rate limited logging, one log line per second. For
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * guests that insist on seeking to places outside the
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * valid area this often generates too many release log
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * entries otherwise. */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync pAhciReq->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync case 0: /* 00 - Stop motor */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* This must be done from EMT. */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
23754115bd6df8b823a323c50acc83cf334b5facvboxsync pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
cc9d606df7a28e6edf8631422cd9b618c3874cb0vboxsync Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
23754115bd6df8b823a323c50acc83cf334b5facvboxsync * the other field is clear... */
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
23754115bd6df8b823a323c50acc83cf334b5facvboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No media change stuff here, it can confuse Linux guests. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
6c37f571518aef92bb8747b41b2a75c18de713e4vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DVD_STRUCTURE);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Parse ATAPI commands, passing them directly to the CD/DVD drive.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** @todo do not forget to unlock when a VM is shut down */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /* Get sector size based on the expected sector type field. */
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iLbaStart);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync default: /* Reserved */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync else /* SCSI_READ_MSF */
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
c0fa6fe4a52eff9785fdf7a79cf3bc149eecd937vboxsync pAhciReq->cbATAPISector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pAhciPort->pTrackList, iATAPILBA);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x07: /* download microcode with offsets and save */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x0e: /* download microcode with offsets and defer activation */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", pAhciPort->iLUN));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Obsolete command used by cdrecord. What else would one expect?
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * This command is not sent to the drive, it is handled internally,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * as the Linux kernel doesn't like it (message "scsi: unknown
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * opcode 0x01" in syslog) and replies with a sense code of 0,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * which sends cdrecord to an endless loop. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogRel(("AHCI: LUN#%d: passthrough unimplemented for command %#x\n", pAhciPort->iLUN, pbPacket[0]));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Send a command to the drive, passing data in/out as required. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset all values after a reset of the attached storage device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port the device is attached to.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The state to get the tag number from.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Send a status good D2H FIS. */
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * @returns nothing.
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * @param pAhciPort The device to reset.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The task state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * Because this ATAPI only and ATAPI can't have
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * more than one command active at a time the task counter should be 0
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * and it is possible to finish the reset now.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * Create a PIO setup FIS and post it into the memory area of the guest.
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync * @returns nothing.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * @param pAhciPort The port of the SATA controller.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * @param pAhciReq The state of the task.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * @param pCmdFis Pointer to the command FIS from the guest.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * @param fInterrupt If an interrupt should be send to the guest.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsyncstatic void ahciSendPioSetupFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis,
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync bool fAssertIntr = false;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync ahciLog(("%s: building PIO setup Fis\n", __FUNCTION__));
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync ("Can't send PIO setup FIS for requests with 0 bytes to transfer or greater than 65534\n"));
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync memset(&abPioSetupFis[0], 0, sizeof(abPioSetupFis));
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_PIOSETUP;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync /* Set transfer count. */
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync abPioSetupFis[16] = (pAhciReq->cbTransfer >> 8) & 0xff;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync /* Update registers. */
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_PIOSETUP, abPioSetupFis);
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PSS);
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync /* Check if we should assert an interrupt */
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Build a D2H FIS and post into the memory area of the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port of the SATA controller.
267957dcacbf753410d79dc1ef9fc0834131ddcdvboxsync * @param pAhciReq The state of the task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCmdFis Pointer to the command FIS from the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fInterrupt If an interrupt should be send to the guest.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAssertIntr = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTN] = pCmdFis[AHCI_CMDFIS_SECTN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLL] = pCmdFis[AHCI_CMDFIS_CYLL];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLH] = pCmdFis[AHCI_CMDFIS_CYLH];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_HEAD] = pCmdFis[AHCI_CMDFIS_HEAD];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTNEXP] = pCmdFis[AHCI_CMDFIS_SECTNEXP];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLLEXP] = pCmdFis[AHCI_CMDFIS_CYLLEXP];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLHEXP] = pCmdFis[AHCI_CMDFIS_CYLHEXP];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTC] = pCmdFis[AHCI_CMDFIS_SECTC];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTCEXP] = pCmdFis[AHCI_CMDFIS_SECTCEXP];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Update registers. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Error bit is set. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * Don't mark the command slot as completed because the guest
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * needs it to identify the failed command.
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we should assert an interrupt */
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /* Mark command as completed. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Build a SDB Fis and post it into the memory area of the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port for which the SDB Fis is send.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param uFinishedTasks Bitmask of finished tasks.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fInterrupt If an interrupt should be asserted.
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsyncstatic void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAssertIntr = false;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Update registers. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
fa65f915725c271afa39d64ce9de684549a4959avboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Error bit is set. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we should assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 65536;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 256;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* any LBA variant */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* LBA48 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iLBA = ((pCmdFis[AHCI_CMDFIS_CYLH] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * pAhciPort->PCHSGeometry.cHeads * pAhciPort->PCHSGeometry.cSectors +
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) * pAhciPort->PCHSGeometry.cSectors +
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 65536;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * Allocates memory for the given request using already allocated memory if possible.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @returns Pointer to the memory or NULL on failure
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync * @param pAhciPort The AHCI port.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param pAhciReq The request to allocate memory for.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param cb The amount of memory to allocate.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsyncstatic void *ahciReqMemAlloc(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cb)
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync pAhciPort->pDrvBlock->pfnIoBufFree(pAhciPort->pDrvBlock, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync int rc = pAhciPort->pDrvBlock->pfnIoBufAlloc(pAhciPort->pDrvBlock, pAhciReq->cbAlloc, &pAhciReq->pvAlloc);
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * Frees memory allocated for the given request.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @returns nothing.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync * @param pAhciPort The AHCI port.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param pAhciReq The request.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync * @param fForceFree Flag whether to force a free
d758f923c07f7ccd2bd54356fda961436b330f35vboxsyncstatic void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree)
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync if ( pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync pAhciPort->pDrvBlock->pfnIoBufFree(pAhciPort->pDrvBlock, pAhciReq->pvAlloc, pAhciReq->cbAlloc);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Copies a data buffer into the S/G buffer set up by the guest.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @returns Amount of bytes copied to the PRDTL.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pDevIns Pointer to the device instance data.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq AHCI request structure.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pvBuf The buffer to copy from.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param cbBuf The size of the buffer.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync uint32_t cPrdtlEntriesRead = cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into SG entry. */
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync PDMDevHlpPCIPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Copies the S/G buffer into a data buffer.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @returns Amount of bytes copied to the PRDTL.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pDevIns Pointer to the device instance data.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq AHCI request structure.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pvBuf The buffer to copy to.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param cbBuf The size of the buffer.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Allocate I/O memory and copies the guest buffer for writes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync * @param pAhciPort The AHCI port.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The request state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param cbTransfer Amount of bytes to allocate.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsyncstatic int ahciIoBufAllocate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbTransfer)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ("Allocating I/O memory for a non I/O request is not allowed\n"));
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciPort, pAhciReq, cbTransfer);
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync * Frees the I/O memory of the given request and updates the guest buffer if necessary.
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync * @returns nothing.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync * @param pAhciPort The AHCI port.
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync * @param pAhciReq The request state.
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync * @param fCopyToGuest Flag whether to update the guest buffer if necessary.
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync * Nothing is copied if false even if the request was a read.
d758f923c07f7ccd2bd54356fda961436b330f35vboxsyncstatic void ahciIoBufFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ("Freeing I/O memory for a non I/O request is not allowed\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync pAhciReq->cbTransfer = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pv, cb);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync ahciReqMemFree(pAhciPort, pAhciReq, false /* fForceFree */);
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * Free all cached tasks on the given port.
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * @returns nothing.
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * @param pAhciPort The AHCI port.
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsyncstatic void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort)
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync ahciReqMemFree(pAhciPort, pAhciPort->aCachedTasks[i], true /* fForceFree */);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Cancels all active tasks on the port.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * @returns Whether all active tasks were canceled.
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * @param pAhciPort The ahci port.
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * @param pAhciReqExcept The given request is excepted from the cancelling
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * (used for error page reading).
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsyncstatic bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aCachedTasks); i++)
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Task is active and was canceled. */
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("Task was canceled but none is active\n"));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Clear the pointer in the cached array. The controller will allocate a
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * a new task structure for this tag.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ASMAtomicWriteNullPtr(&pAhciPort->aCachedTasks[i]);
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ("Invalid task state, must be free!\n"));
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync AssertRelease( !ASMAtomicReadU32(&pAhciPort->cTasksActive)
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync || (pAhciReqExcept && ASMAtomicReadU32(&pAhciPort->cTasksActive) == 1));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncstatic void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync 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"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncbool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync /* iSCSI connection abort (first error) or failure to reestablish
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync * connection (second error). Pause VM. On resume we'll retry. */
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
1741b757f7a570a7e6d48db46c3f4cd50f2ee296vboxsync /* Error message already set. */
1741b757f7a570a7e6d48db46c3f4cd50f2ee296vboxsync ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false);
1741b757f7a570a7e6d48db46c3f4cd50f2ee296vboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return false;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * Creates the array of ranges to trim.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * @returns VBox status code.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciPort AHCI port state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The request handling the TRIM request.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync unsigned cRanges = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync /* The data buffer contains LBA range entries. Each range is 8 bytes big. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] && !pAhciReq->cmdFis[AHCI_CMDFIS_SECTCEXP])
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync /* Convert the ranges from the guest to our format. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * pAhciPort->cbSector;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * Destroy the trim range list.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * @returns nothing.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The task state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Complete a data transfer task by freeing all occupied resources
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and notifying the guest.
ac6c45d7c02a274a1d1e01d6b0a84e972e531d6avboxsync * @returns Flag whether the given request was canceled inbetween;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciPort Pointer to the port where to request completed.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq Pointer to the task which finished.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param rcReq IPRT status code of the completed request.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param fFreeReq Flag whether to free the request if it was canceled.
ac6c45d7c02a274a1d1e01d6b0a84e972e531d6avboxsyncstatic bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq, bool fFreeReq)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fXchg = false;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync bool fRedo = false;
ac6c45d7c02a274a1d1e01d6b0a84e972e531d6avboxsync bool fCanceled = false;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d fFreeReq=%RTbool\n",
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync enmTxState = (AHCITXSTATE)ASMAtomicReadU32((volatile uint32_t *)&pAhciReq->enmTxState);
acc7ccb2f5c04099b13742547abff1b18b3d49cevboxsync VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, enmTxState, pAhciReq->uOffset, pAhciReq->cbTransfer);
25866675a2cd68211a7a90bc0abd32c40235d07dvboxsync VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(pAhciReq, tsNow);
3b5486d99a3b391015873e5524bb1974d6dd3935vboxsync * Leave a release log entry if the request was active for more than 25 seconds
3b5486d99a3b391015873e5524bb1974d6dd3935vboxsync * (30 seconds is the timeout of the guest).
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: %s request was active for %llu seconds\n",
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, pcszReq, (tsNow - pAhciReq->tsStart) / 1000));
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync ahciIoBufFree(pAhciPort, pAhciReq, true /* fCopyToGuest */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Log the error. */
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
3d40799173fcdd842291c870033d85379d731a4avboxsync ASMAtomicOrU32(&pAhciPort->u32TasksRedo, RT_BIT_32(pAhciReq->uTag));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Status will be set by already for non I/O requests. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Write updated command header into memory of the guest. */
b14c09e8af60e4d1ba4da27da03cbd175617f298vboxsync PDMDevHlpPCIPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * The guest tried to transfer more data than there is space in the buffer.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Terminate task and set the overflow bit.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Notify the guest. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("Inconsistent request counter\n"));
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync /* Post a PIO setup FIS first if this is a PIO command which transfers data. */
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync ahciSendPioSetupFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false /* fInterrupt */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Always raise an interrupt after task completion; delaying
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * this (interrupt coalescing) increases latency and has a significant
5981e6935987b08737b730b63a41acc1dd696377vboxsync * impact on performance (see @bugref{5071})
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Task was canceled, do the cleanup but DO NOT access the guest memory!
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * The guest might use it for other things now because it doesn't know about that task anymore.
051b18f951bde6348786628efc9298a2595e3494vboxsync AssertMsg( pAhciReq->enmTxState == AHCITXSTATE_CANCELED
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ("Task is not active but wasn't canceled!\n"));
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync ASMAtomicXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync ahciIoBufFree(pAhciPort, pAhciReq, false /* fCopyToGuest */);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Leave a log message about the canceled request. */
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: Canceled flush returned rc=%Rrc\n",
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, rcReq));
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: Canceled trim returned rc=%Rrc\n",
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance,pAhciPort->iLUN, rcReq));
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync LogRel(("AHCI#%uP%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
eab76ae67801d10882ae1fbdb90351044a2a3a54vboxsync pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Finally free the task state structure because it is completely unused now. */
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Notification callback for a completed transfer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pInterface Pointer to the interface.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pvUser User data.
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsync * @param rcReq IPRT Status code of the completed request.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsyncstatic DECLCALLBACK(int) ahciR3TransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync ahciTransferComplete(pAhciPort, pAhciReq, rcReq, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Process an non read/write ATA command.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns The direction of the data transfer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCmdHdr Pointer to the command header.
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fLBA48 = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Fill the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xcc: /* reverting to power-on defaults enable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x66: /* reverting to power-on defaults disable */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
23754115bd6df8b823a323c50acc83cf334b5facvboxsync /* set transfer mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync /* Reset the device. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break; /* Do nothing. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fall through */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * pAhciPort->cbSector;
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * pAhciPort->cbSector;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync aBuf[0] = (pTaskErr->fFlags & AHCI_REQ_IS_QUEUED) ? pTaskErr->uTag : (1 << 7);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Calculate checksum */
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync ahciIoBufFree(pAhciPort, pTaskErr, false /* fCopyToGuest */);
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync /* Finally free the error task state structure because it is completely unused now. */
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * Reading this log page results in an abort of all outstanding commands
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * and clearing the SActive register and TaskFile register.
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync * See SATA2 1.2 spec chapter 4.2.3.4
21453e986cd731f6a3915d774abc31bdf221c1f3vboxsync bool fAbortedAll = ahciCancelActiveTasks(pAhciPort, pAhciReq);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Copy the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Check that the trim bit is set and all other bits are 0. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ( !(pAhciReq->cmdFis[AHCI_CMDFIS_FET] & UINT16_C(0x01))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync || (pAhciReq->cmdFis[AHCI_CMDFIS_FET] & ~UINT16_C(0x1)))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync /* else: fall through and report error to the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* All not implemented commands go below. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default: /* For debugging purposes. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Retrieve a command FIS from guest memory.
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * @returns whether the H2D FIS was successfully read from the guest memory.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The state of the actual task.
c4e862df22b8c582055b945e086a51957e913e6bvboxsyncstatic bool ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
c4e862df22b8c582055b945e086a51957e913e6bvboxsync AssertMsgReturn(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb,
c4e862df22b8c582055b945e086a51957e913e6bvboxsync ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * First we are reading the command header pointed to by regCLB.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * From this we get the address of the command table which we are reading too.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We can process the Command FIS afterwards.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the command header. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync AssertMsgReturn((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
c4e862df22b8c582055b945e086a51957e913e6bvboxsync ("This is not a command FIS!!\n"),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Read the command Fis. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdTbl=%RGp cbCmdFis=%u\n", __FUNCTION__, GCPhysAddrCmdTbl, AHCI_CMDFIS_TYPE_H2D_SIZE));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync AssertMsgReturn(pAhciReq->cmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D,
c4e862df22b8c582055b945e086a51957e913e6bvboxsync ("This is not a command FIS\n"),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set transfer direction. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If this is an ATAPI command read the atapi command. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We "received" the FIS. Clear the BSY bit in regTFD. */
b32cbfd89d5d933a6c86fc4d24ffae4d27976af3vboxsync if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fFlags & AHCI_REQ_CLEAR_SACT))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * but this FIS does not assert an interrupt
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->GCPhysPrdtl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cPrdtlEntries = AHCI_CMDHDR_PRDTL_ENTRIES(pAhciReq->cmdHdr.u32DescInf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the FIS. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync /* Print the PRDT */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
c4e862df22b8c582055b945e086a51957e913e6bvboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Transmit queue consumer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Queue a new async task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Success indicator.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If false the item will not be removed and the flushing will stop.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pItem The item to consume. Upon return this item will be freed.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync PAHCIPort pAhciPort = &pThis->ahciPort[pNotifierItem->iPort];
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync /* Notify the async IO thread. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync return true;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync/* The async IO thread for one port. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsyncstatic DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync unsigned idx = 0;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, true);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync Assert(ASMAtomicReadBool(&pAhciPort->fWrkThreadSleeping));
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = SUPSemEventWaitNoResume(pAhci->pSupDrvSession, pAhciPort->hEvtProcess, RT_INDEFINITE_WAIT);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync ASMAtomicWriteBool(&pAhciPort->fWrkThreadSleeping, false);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Check whether the global host controller bit is set and go to sleep immediately again
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * if it is set.
c4e862df22b8c582055b945e086a51957e913e6bvboxsync u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync bool fReqCanceled = false;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Decrement to get the slot number. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Check if there is already an allocated task struct in the cache.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Allocate a new task otherwise.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n"));
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Set current command slot */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync bool fFisRead = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Couldn't find anything in either the AHCI or SATA spec which
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * indicates what should be done if the FIS is not read successfully.
fabcc93bba60b4f8c99c87e20f5806d38f5091ebvboxsync * The closest thing is in the state machine, stating that the device
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * should go into idle state again (SATA spec 1.0 chapter 8.7.1).
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Do the same here and ignore any corrupt FIS types, after all
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * the guest messed up everything and this behavior is undefined.
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* 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. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* If the reset bit is set put the device into reset state. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync else /* We are not in a reset state update the control registers. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
22001ffa3bd10acd596a193053e52ffa8297097bvboxsync fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("There are more than 32 requests active"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
d758f923c07f7ccd2bd54356fda961436b330f35vboxsync rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock, pAhciReq->u.Trim.paRanges,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, pAhciReq->uOffset,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, pAhciReq->uOffset,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* Command */
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync * Don't process other requests if the last one was canceled,
7b485386ada9770b8a1df782ce55b607b52c111fvboxsync * the others are not valid anymore.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* while tasks available */
051b18f951bde6348786628efc9298a2595e3494vboxsync /* Check whether a port reset was active. */
051b18f951bde6348786628efc9298a2595e3494vboxsync && (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT)
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * Check whether a host controller reset is pending and execute the reset
c4e862df22b8c582055b945e086a51957e913e6bvboxsync * if this is the last active thread.
c4e862df22b8c582055b945e086a51957e913e6bvboxsync u32RegHbaCtrl = ASMAtomicReadU32(&pAhci->regHbaCtrl);
c4e862df22b8c582055b945e086a51957e913e6bvboxsync uint32_t cThreadsActive = ASMAtomicDecU32(&pAhci->cThreadsActive);
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync } /* While running */
fa65f915725c271afa39d64ce9de684549a4959avboxsync ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Unblock the async I/O thread so it can respond to a state change.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
761f441a49e44d77d290c521746320de9a0b46ccvboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThread The send thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync return SUPSemEventSignal(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync/* -=-=-=-=- DBGF -=-=-=-=- */
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync * AHCI status info callback.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pDevIns The device instance.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pHlp The output helpers.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pszArgs The arguments.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsyncstatic DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Show info.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Show global registers.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaCap=%#x\n", pThis->regHbaCap);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaCtrl=%#x\n", pThis->regHbaCtrl);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaIs=%#x\n", pThis->regHbaIs);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaPi=%#x", pThis->regHbaPi);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaVs=%#x\n", pThis->regHbaVs);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaCccCtl=%#x\n", pThis->regHbaCccCtl);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "HbaCccPorts=%#x\n", pThis->regHbaCccPorts);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortsInterrupted=%#x\n", pThis->u32PortsInterrupted);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Per port data.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "Port %d: async=%RTbool device-attached=%RTbool\n",
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pThisPort->iLUN, pThisPort->fAsyncInterface, pThisPort->pDrvBase != NULL);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortClb=%#x\n", pThisPort->regCLB);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortClbU=%#x\n", pThisPort->regCLBU);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortFb=%#x\n", pThisPort->regFB);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortFbU=%#x\n", pThisPort->regFBU);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortIs=%#x\n", pThisPort->regIS);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortIe=%#x\n", pThisPort->regIE);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortCmd=%#x\n", pThisPort->regCMD);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortTfd=%#x\n", pThisPort->regTFD);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSig=%#x\n", pThisPort->regSIG);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSSts=%#x\n", pThisPort->regSSTS);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSCtl=%#x\n", pThisPort->regSCTL);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSErr=%#x\n", pThisPort->regSERR);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSAct=%#x\n", pThisPort->regSACT);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortCi=%#x\n", pThisPort->regCI);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortFirstD2HFisSend=%RTbool\n", pThisPort->fFirstD2HFisSend);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortATAPI=%RTbool\n", pThisPort->fATAPI);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- Helper -=-=-=-=- */
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync * Checks if all asynchronous I/O is finished, both AHCI and IDE.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * use of it in strict builds (which is why it's up here).
9083f76e8c5709604766d0215a380de516e781eevboxsync * @returns true if quiesced, false if busy.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance.
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
fabcc93bba60b4f8c99c87e20f5806d38f5091ebvboxsync return false;
9083f76e8c5709604766d0215a380de516e781eevboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
9083f76e8c5709604766d0215a380de516e781eevboxsync return false;
9083f76e8c5709604766d0215a380de516e781eevboxsync return true;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- Saved State -=-=-=-=- */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @copydoc FNDEVSSMSAVEPREP
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @copydoc FNDEVSSMLOADPREP
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * @copydoc FNDEVSSMLIVEEXEC
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* config. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].fHotpluggable);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
928e1d6581a40f26932a8b35526773805bc69e47vboxsync int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * @copydoc FNDEVSSMSAVEEXEC
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The config */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The main device structure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cCylinders);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cHeads);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].PCHSGeometry.cSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU64(pSSM, pThis->ahciPort[i].cTotalSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].cMultSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU8(pSSM, pThis->ahciPort[i].uATATransferMode);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /* ATAPI saved state. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3PutMem(pSSM, &pThis->ahciPort[i].abATAPISense[0], sizeof(pThis->ahciPort[i].abATAPISense));
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3PutU8(pSSM, pThis->ahciPort[i].cNotifiedMediaChange);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].MediaEventStatus);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * Loads a saved legacy ATA emulated device state.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * @returns VBox status code.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * @param pSSM The handle to the saved state.
02f955f7b03b123d49915acf2231bf30ab76071avboxsyncstatic int ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Test for correct version. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync /** @todo triple-check this hack after passthrough is working */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32 != ~0U)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Loads a saved AHCI device state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * @param pSSM The handle to the saved state.
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync * @param uVersion The data unit version number.
6dea6d87ed79bc0994d314fed1c90431091e8820vboxsync * @param uPass The data pass.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
02f955f7b03b123d49915acf2231bf30ab76071avboxsync /* Deal with the priod after removing the saved IDE bits where the saved
02f955f7b03b123d49915acf2231bf30ab76071avboxsync state version remained unchanged. */
02f955f7b03b123d49915acf2231bf30ab76071avboxsync if ( uVersion == AHCI_SAVED_STATE_VERSION_IDE_EMULATION
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync * Check whether we have to resort to the legacy port reset method to
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync * prevent older BIOS versions from failing after a reset.
f20f7cf8c2a0f141965d11345d910cc8e65c1fb3vboxsync if (uVersion <= AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Verify config. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
e8ad3d010ce14b8afa8d2b5ecc59c4e89c16fe7avboxsync N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_HOTPLUG_FLAG)
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync if (fHotpluggable != pThis->ahciPort[i].fHotpluggable)
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync N_("AHCI: Port %u config mismatch: Hotplug flag - saved=%RTbool config=%RTbool\n"),
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync i, fHotpluggable, pThis->ahciPort[i].fHotpluggable);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (strcmp(szSerialNumber, pThis->ahciPort[i].szSerialNumber))
ef77d80be9abe31afebaac8083af7ba8314795fcvboxsync LogRel(("AHCI: Port %u config mismatch: Serial number - saved='%s' config='%s'\n",
da5e996e05c747df5185b4b68bb2e242458edbb2vboxsync i, szSerialNumber, pThis->ahciPort[i].szSerialNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (strcmp(szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision))
ef77d80be9abe31afebaac8083af7ba8314795fcvboxsync LogRel(("AHCI: Port %u config mismatch: Firmware revision - saved='%s' config='%s'\n",
da5e996e05c747df5185b4b68bb2e242458edbb2vboxsync i, szFirmwareRevision, pThis->ahciPort[i].szFirmwareRevision));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (strcmp(szModelNumber, pThis->ahciPort[i].szModelNumber))
ef77d80be9abe31afebaac8083af7ba8314795fcvboxsync LogRel(("AHCI: Port %u config mismatch: Model number - saved='%s' config='%s'\n",
da5e996e05c747df5185b4b68bb2e242458edbb2vboxsync i, szModelNumber, pThis->ahciPort[i].szModelNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
928e1d6581a40f26932a8b35526773805bc69e47vboxsync rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Restore data. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The main device structure. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_PORT_RESET_CHANGES)
926975f2c06340117f6b3d218e38fe2d4c446d23vboxsync SSMR3GetBool(pSSM, &pThis->fLegacyPortResetMethod);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Now every port. */
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrClb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetGCPhys(pSSM, (RTGCPHYS *)&pThis->ahciPort[i].GCPhysAddrFb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regIS);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regSACT);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].regCI);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cCylinders);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cHeads);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].PCHSGeometry.cSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU64(pSSM, &pThis->ahciPort[i].cTotalSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].cMultSectors);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU8(pSSM, &pThis->ahciPort[i].uATATransferMode);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->ahciPort[i].fResetDevice);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /* The old positions in the FIFO, not required. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
d00ac6bac8066f17185a6319257f617ecd021b4bvboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3GetMem(pSSM, pThis->ahciPort[i].abATAPISense, sizeof(pThis->ahciPort[i].abATAPISense));
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3GetU8(pSSM, &pThis->ahciPort[i].cNotifiedMediaChange);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3GetU32(pSSM, (uint32_t*)&pThis->ahciPort[i].MediaEventStatus);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync /* Check if we have tasks pending. */
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
fa65f915725c271afa39d64ce9de684549a4959avboxsync * There are tasks pending. The VM was saved after a task failed
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * because of non-fatal error. Set the redo flag.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
0df0bb09b5473a52f430fa3bca214be7f542cae0vboxsync AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- device PDM interface -=-=-=-=- */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Relocate every port. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium removed" event
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * from now on, regardless if there was a medium inserted or not.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * SCSI_GET_EVENT_STATUS_NOTIFICATION should return "medium inserted". If
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * there was already a medium inserted, don't forget to send the "medium
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * removed" event first.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* no change, we will send "medium removed" + "medium inserted" */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Called when a media is mounted.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsyncstatic DECLCALLBACK(void) ahciR3MountNotify(PPDMIMOUNTNOTIFY pInterface)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Ignore the call if we're called while being attached. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Report media changed in TEST UNIT and other (probably incorrect) places. */
c825c31dbee005ba09e3c293433ae984f489a4bdvboxsync ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Called when a media is unmounted
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsyncstatic DECLCALLBACK(void) ahciR3UnmountNotify(PPDMIMOUNTNOTIFY pInterface)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * present and 2 in which it is changed.
c825c31dbee005ba09e3c293433ae984f489a4bdvboxsync ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Configure the attached device for a port.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Used by ahciR3Construct and ahciR3Attach.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @returns VBox status code
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pAhciPort The port for which the device is to be configured.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Query the block and blockbios interfaces.
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Try to get the optional async block interface. */
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Validate type.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciPort->cbSector = pAhciPort->pDrvBlock->pfnGetSectorSize(pAhciPort->pDrvBlock);
e18d16f31765f000e2a4a111a3df6d211cd825f1vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / pAhciPort->cbSector;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Set the disk geometry information. Ignore errors. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
e91a1af7d4269cdd9c9bf82320fabeb475d68d8bvboxsync LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Callback employed by ahciR3Suspend and ahciR3PowerOff..
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @returns true if we've quiesced, false if we're still working.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return false;
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * Free all cached tasks here, not possible on destruct because the driver
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * is destroyed before us.
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return true;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Common worker for ahciR3Suspend and ahciR3PowerOff.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * Free all cached tasks here, not possible on destruct because the driver
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync * is destroyed before us.
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync for (unsigned iPort = 0; iPort < pThis->cPortsImpl; iPort++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Suspend notification.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Resume notification.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Check if one of the ports has pending tasks.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Queue a notification item again in this case.
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * Initializes the VPD data of a attached device.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * @returns VBox status code.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * @param pDevIns The device instance.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * @param pAhciPort The attached device.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * @param szName Name of the port to get the CFGM node.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsyncstatic int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* Generate a default serial number. */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* Get user config if present using defaults otherwise. */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync PCFGMNODE pCfgNode = CFGMR3GetChild(pDevIns->pCfg, pszName);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync rc = CFGMR3QueryU8Def(pCfgNode, "LogicalSectorsPerPhysical", &pAhciPort->cLogSectorsPerPhysicalExp, 0);
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync N_("AHCI configuration error: failed to read \"LogicalSectorsPerPhysical\" as integer"));
b6a171211dc56d6a805da5f43dcb6b3eb73c7e8avboxsync N_("AHCI configuration error: \"LogicalSectorsPerPhysical\" must be between 0 and 15"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* There are three other identification strings for CD drives used for INQUIRY */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Detach notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * One harddisk at one port has been unplugged.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The VM is suspended at this point.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param iLUN The logical unit which is being detached.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy the thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
76f99cb799ef9e02a214fbe65ad9840a2e292361vboxsync /* Free all cached I/O tasks. */
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync * Inform the guest about the removed device.
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync * Clear CR bit too to prevent submission of new commands when CI is written
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync * (AHCI Spec 1.2: 7.4 Interaction of the Command List and Port Change Status).
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
bb86f79a8790070b1202ad7724eae91da09ec2e5vboxsync ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Zero some important members.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach command.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is called when we change block driver for one port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The VM is suspended at this point.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param iLUN The logical unit which is being detached.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* the usual paranoia */
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync AssertMsg(iLUN < pThis->cPortsImpl, ("iLUN=%u", iLUN));
ab58bb42bb43ca65a808a48dc31f05dfed087d8avboxsync ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Try attach the block device and get the interfaces,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * required as well as optional.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
c825c31dbee005ba09e3c293433ae984f489a4bdvboxsync * In case there is a medium inserted.
c825c31dbee005ba09e3c293433ae984f489a4bdvboxsync ahciMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync /* Create the async IO thread. */
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync * Init vendor product data.
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Inform the guest about the added device in case of hotplugging. */
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync ("AHCI: Port %d is not marked hotpluggable\n", pAhciPort->iLUN),
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync * Initialize registers
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync ASMAtomicOrU32(&pAhciPort->regCMD, AHCI_PORT_CMD_CPS);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS | AHCI_PORT_IS_PCS);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_X | AHCI_PORT_SERR_N);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync (0x03 << 0); /* Device detected and communication established. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
9083f76e8c5709604766d0215a380de516e781eevboxsync * Common reset worker.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Hardware reset for the ports. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Callback employed by ahciR3Reset.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @returns true if we've quiesced, false if we're still working.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance.
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
9083f76e8c5709604766d0215a380de516e781eevboxsync return false;
9083f76e8c5709604766d0215a380de516e781eevboxsync ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
9083f76e8c5709604766d0215a380de516e781eevboxsync return true;
9083f76e8c5709604766d0215a380de516e781eevboxsync * Reset notification.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
9083f76e8c5709604766d0215a380de516e781eevboxsync PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
9083f76e8c5709604766d0215a380de516e781eevboxsync ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Poweroff notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns Pointer to the device instance
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * Destroy a driver instance.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * resources can be freed correctly.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * @param pDevIns The device instance data.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsyncstatic DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * At this point the async I/O thread is suspended and will not enter
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * this module again. So, no coordination is needed here and PDM
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * will take care of terminating and cleaning up the thread.
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync for (unsigned iActPort = 0; iActPort < pThis->cPortsImpl; iActPort++)
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync SUPSemEventClose(pThis->pSupDrvSession, pAhciPort->hEvtProcess);
6453ab7aee83b53063ef339e594e5499de3f607cvboxsync for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
cad8876b46f9e366c4a1007a40c27ca1df078950vboxsync * @interface_method_impl{PDMDEVREG,pfnConstruct}
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsyncstatic DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fGCEnabled = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fR0Enabled = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate and read configuration.
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "R0Enabled\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "PrimaryMaster\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "PrimarySlave\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "SecondaryMaster\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "SecondarySlave\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "PortCount\0"
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync "UseAsyncInterfaceIfAvailable\0"
3649373f921ada8549bf86c6edb03b340f2d214avboxsync "Bootable\0"
3649373f921ada8549bf86c6edb03b340f2d214avboxsync "CmdSlotsAvail\0"))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: unknown option specified"));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read GCEnabled as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read R0Enabled as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read PortCount as integer"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: PortCount=%u should not exceed %u"),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: PortCount=%u should be at least 1"),
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync N_("AHCI configuration error: failed to read Bootable as boolean"));
3649373f921ada8549bf86c6edb03b340f2d214avboxsync rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
3649373f921ada8549bf86c6edb03b340f2d214avboxsync Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
3649373f921ada8549bf86c6edb03b340f2d214avboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
3649373f921ada8549bf86c6edb03b340f2d214avboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * Initialize the instance data (everything touched by the destructor need
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * to be initialized here!).
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
2e29d74fdcb3d8b2addc098119a729c0b3c7dbc3vboxsync PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
c8fa825f24555add43a7f0221dc4ad8320c4752dvboxsync pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync /* Initialize port members. */
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync * Init locks, using explicit locking where necessary.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync Log(("%s: Failed to create critical section.\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register the PCI device, it's I/O regions.
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync /* That's OK, we can work without MSI */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Solaris 10 U5 fails to map the AHCI register space when the sets (0..5) for the legacy
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * IDE registers are not available.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We set up "fake" entries in the PCI configuration register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * That means they are available but read and writes from/to them have no effect.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * No guest should access them anyway because the controller is marked as AHCI in the Programming interface
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and we don't have an option to change to IDE emulation (real hardware provides an option in the BIOS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to switch to it which also changes device Id and other things in the PCI configuration space).
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region for BMDMA"));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI memory region for registers"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create the timer for command completion coalescing feature. */
37abe5bbe92fe55c7fc61b4f597fe79fab95a2dbvboxsync rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ahciCccTimer, pThis,
3956d0151065a11e49d2213b38a5efdad46807e0vboxsync TMTIMER_FLAGS_NO_CRIT_SECT, "AHCI CCC Timer", &pThis->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Status LUN. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Create the notification queue.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * We need 2 items for every port because of SMP races.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL * 2, 0,
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialize static members on every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Attach drivers to every available port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init interfaces.
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciR3TransferCompleteNotify;
ebfd0f4dd08d412929e69081b23a144ac52c5e1avboxsync pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync pAhciPort->IMountNotify.pfnMountNotify = ahciR3MountNotify;
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync pAhciPort->IMountNotify.pfnUnmountNotify = ahciR3UnmountNotify;
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync /* Query per port configuration options if available. */
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync PCFGMNODE pCfgPort = CFGMR3GetChild(pDevIns->pCfg, szName);
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync rc = CFGMR3QueryBoolDef(pCfgPort, "Hotpluggable", &pAhciPort->fHotpluggable, true);
73ae72ef2c54d514301f3efda669dc6db5f28da5vboxsync N_("AHCI configuration error: failed to read Hotpluggable as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach the block driver
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Mark that a device is present on that port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init vendor product data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the new async interface is available we use a PDMQueue to transmit
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the requests into R3.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Otherwise we use a event semaphore and a async I/O thread which processes them.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync rc = SUPSemEventCreate(pThis->pSupDrvSession, &pAhciPort->hEvtProcess);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop,
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync ahciAsyncIOLoopWakeUp, 0, RTTHREADTYPE_IO, szName);
d6ec942234269e5c8ddc45e26473fd575ade6fbcvboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5135fa8414ee502f2d718001871ac58f9b58af07vboxsync N_("AHCI: Failed to create worker thread %s"), szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach status driver (optional).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("AHCI cannot attach to status driver"));
c11f819521ac699ff05361aa39f2a6e7342aacaevboxsync rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis) + cbTotalBufferSize, NULL,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Register the info item.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
9083f76e8c5709604766d0215a380de516e781eevboxsync return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The device registration structure.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32Version */
2c8ee291fb75c4a6f05df160f5d67f4e9ef1cabcvboxsync /* szName */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* szRCMod */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxDDGC.gc",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* szR0Mod */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "VBoxDDR0.r0",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pszDescription */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Intel AHCI controller.\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fFlags */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
22f5063af9740075661e9512a5b9ba92ea3a535evboxsync PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fClass */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cMaxInstances */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cbInstance */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnConstruct */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDestruct */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnRelocate */
24ca3d27f14cf8a03b8448f6d0898110e915d46avboxsync /* pfnMemSetup */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOn */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSuspend */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnResume */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnAttach */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDetach */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnQueryInterface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnInitComplete */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOff */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSoftReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32VersionEnd */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */