DevAHCI.cpp revision f11eaffbbd9153a62d2c6eb3ec1810947c956802
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * VBox storage devices: AHCI controller device (disk and cdrom).
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * Implements the AHCI standard 1.1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync * Copyright (C) 2006-2011 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync//#define DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define LOG_GROUP LOG_GROUP_DEV_AHCI
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmdev.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmqueue.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmthread.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmcritsect.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/scsi.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/assert.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/asm.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/string.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/param.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/thread.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/semaphore.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/alloc.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/uuid.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <iprt/time.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9ee86050975427444ed8f68e502d2aa9ddcbff1cvboxsync#include "PIIX3ATABmDma.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "ide.h"
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include "VBoxDD.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync#define AHCI_MAX_NR_PORTS_IMPL 30
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync/** Maximum number of command slots available. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync#define AHCI_NR_COMMAND_SLOTS 32
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync#define AHCI_MAX_ALLOC_TOO_MUCH 20
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/** The current saved state version. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define AHCI_SAVED_STATE_VERSION 6
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync/** Saved state version before legacy ATA emulation was dropped. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define AHCI_SAVED_STATE_VERSION_IDE_EMULATION 5
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync/** Saved state version before ATAPI support was added. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync#define AHCI_SAVED_STATE_VERSION_PRE_ATAPI 3
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/** The saved state version use in VirtualBox 3.0 and earlier.
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * This was before the config was added and ahciIOTasks was dropped. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync#define AHCI_SAVED_STATE_VERSION_VBOX_30 2
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync/* for Older ATA state Read handling */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define ATA_CTL_SAVED_STATE_VERSION 3
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
f11eaffbbd9153a62d2c6eb3ec1810947c956802vboxsync
f11eaffbbd9153a62d2c6eb3ec1810947c956802vboxsync/** The maximum number of release log entries per device. */
9ee86050975427444ed8f68e502d2aa9ddcbff1cvboxsync#define MAX_LOG_REL_ERRORS 1024
f11eaffbbd9153a62d2c6eb3ec1810947c956802vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define ATA_MAX_MULT_SECTORS 128
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest PIO mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define ATA_PIO_MODE_MAX 4
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest MDMA mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define ATA_MDMA_MODE_MAX 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Fastest UDMA mode supported by the drive.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define ATA_UDMA_MODE_MAX 6
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Length of the configurable VPD data (without termination)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_SERIAL_NUMBER_LENGTH 20
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_FIRMWARE_REVISION_LENGTH 8
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_MODEL_NUMBER_LENGTH 40
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_ATAPI_INQUIRY_VENDOR_ID_LENGTH 8
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_ATAPI_INQUIRY_PRODUCT_ID_LENGTH 16
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync#define AHCI_ATAPI_INQUIRY_REVISION_LENGTH 4
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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) */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync/* Media track type */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync#define ATA_MEDIA_TYPE_UNKNOWN 0 /**< unknown CD type */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync#define ATA_MEDIA_TYPE_DATA 1 /**< Data CD */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync#define ATA_MEDIA_TYPE_CDDA 2 /**< CD-DA (audio) CD type */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/** ATAPI sense info size. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATAPI_SENSE_SIZE 64
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync/**
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Command Header.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync#pragma pack(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Description Information. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32DescInf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command status. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32PRDBC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Table Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32CmdTblAddr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Table Base Address - upper 32-bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32CmdTblAddrUp;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32Reserved[4];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} CmdHdr;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync#pragma pack()
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompileSize(CmdHdr, 32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command header. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_PRDTL_MASK 0xffff0000
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_PRDTL_ENTRIES(x) ((x & AHCI_CMDHDR_PRDTL_MASK) >> 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_C RT_BIT(10)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_B RT_BIT(9)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_R RT_BIT(8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_P RT_BIT(7)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_W RT_BIT(6)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_A RT_BIT(5)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_CFL_MASK 0x1f
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_PRDT_OFFSET 0x80
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDHDR_ACMD_OFFSET 0x40
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines that are used in the first double word. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_TYPE 0 /* The first byte. */
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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CMD 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_FET 3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_SECTN 4
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CYLL 5
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CYLH 6
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_HEAD 7
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_SECTNEXP 8
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CYLLEXP 9
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CYLHEXP 10
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_FETEXP 11
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_SECTC 12
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_SECTCEXP 13
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_CTL 15
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* For D2H FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_STS 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_CMDFIS_ERR 3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/** Pointer to a task state. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef struct AHCIREQ *PAHCIREQ;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/**
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Data processing callback
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *
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.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/** Pointer to a FNAHCIPOSTPROCESS() function. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsynctypedef FNAHCIPOSTPROCESS *PFNAHCIPOSTPROCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync/**
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync * Transfer type.
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsynctypedef enum AHCITXDIR
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync{
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Invalid */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR_INVALID = 0,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** None */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR_NONE,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Read */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR_READ,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Write */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR_WRITE,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /** Flush */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync AHCITXDIR_FLUSH,
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync /** Trim */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync AHCITXDIR_TRIM
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync} AHCITXDIR;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync/**
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Task state.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsynctypedef enum AHCITXSTATE
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync{
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Invalid. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AHCITXSTATE_INVALID = 0,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task is not active. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AHCITXSTATE_FREE,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task is active */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AHCITXSTATE_ACTIVE,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task was canceled but the request didn't completed yet. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AHCITXSTATE_CANCELED,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** 32bit hack. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AHCITXSTATE_32BIT_HACK = 0x7fffffff
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync} AHCITXSTATE, *PAHCITXSTATE;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync/** Task encountered a buffer overflow. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync#define AHCI_REQ_OVERFLOW RT_BIT_32(0)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * A task state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef struct AHCIREQ
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /** Task state. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync volatile AHCITXSTATE enmTxState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Tag of the task. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uTag;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command is queued. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fQueued;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The command header for this task. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync CmdHdr cmdHdr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The command Fis for this task. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t cmdFis[AHCI_CMDFIS_TYPE_H2D_SIZE];
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** The ATAPI command data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** Size of one sector for the ATAPI transfer. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync size_t cbATAPISector;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Physical address of the command header. - GC */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysCmdHdrAddr;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Physical address if the PRDT */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysPrdtl;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Number of entries in the PRDTL. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync unsigned cPrdtlEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data direction. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Start offset. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t uOffset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of bytes to transfer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATA error register */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uATARegError;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATA status register */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uATARegStatus;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Flags for this task. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t fFlags;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Additional memory allocation for this task. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync void *pvAlloc;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Siize of the allocation. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync size_t cbAlloc;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync /** Number of times we had too much memory allocated for the request. */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync unsigned cAllocTooMuch;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data dependent on the transfer direction. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync union
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data for an I/O request. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync struct
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data segment. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTSGSEG DataSeg;
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 PFNAHCIPOSTPROCESS pfnPostProcess;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } Io;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Data for a trim request. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync struct
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Pointer to the array of ranges to trim. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PRTRANGE paRanges;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /** Number of entries in the array. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync unsigned cRanges;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } Trim;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } u;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync} AHCIREQ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Notifier queue item.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct DEVPORTNOTIFIERQUEUEITEM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The core part owned by the queue manager. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMQUEUEITEMCORE Core;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The port to process. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t iPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBASE
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBLOCKPORT
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBLOCKASYNCPORT
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIMOUNTNOTIFY
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCIPort
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSR3 pDevInsR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSR0 pDevInsR0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - RC ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSRC pDevInsRC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - R3 ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(struct AHCI *) pAhciR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - R0 ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R0PTRTYPE(struct AHCI *) pAhciR0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the parent AHCI structure - RC ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RCPTRTYPE(struct AHCI *) pAhciRC;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regCLB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address upper bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regCLBU;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regFB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address upper bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regFBU;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Status. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync volatile uint32_t regIS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Enable. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regIE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regCMD;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Task File Data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regTFD;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Signature */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regSIG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Status. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regSSTS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Control. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regSCTL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Error. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regSERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Serial ATA Active. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t regSACT;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command Issue. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regCI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command List Base Address */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile RTGCPHYS GCPhysAddrClb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** FIS Base Address */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile RTGCPHYS GCPhysAddrFb;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Current number of active tasks. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t cTasksActive;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device is powered on. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fPoweredOn;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device has spun up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fSpunUp;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** First D2H FIS was send. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fFirstD2HFisSend;
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync bool fNonRotational;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Attached device is a CD/DVD drive. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fATAPI;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** Passthrough SCSI commands. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync bool fATAPIPassthrough;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag whether this port is in a reset state. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile bool fPortReset;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** If we use the new async interface. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync bool fAsyncInterface;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag if we are in a device reset. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync bool fResetDevice;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag whether the I/O thread idles. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile bool fAsyncIOThreadIdle;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Flag whether the port is in redo task mode. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile bool fRedo;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync#if HC_ARCH_BITS == 64
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync bool fAlignment2;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync#endif
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Number of total sectors. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint64_t cTotalSectors;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Currently configured number of sectors in a multi-sector transfer. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint32_t cMultSectors;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint8_t uATATransferMode;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** ATAPI sense data. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint8_t abATAPISense[ATAPI_SENSE_SIZE];
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint8_t cNotifiedMediaChange;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The same for GET_EVENT_STATUS for mechanism */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t MediaEventStatus;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Media type if known. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t MediaTrackType;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** The LUN. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync RTUINT iLUN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for finished tasks (R3 -> Guest). */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t u32TasksFinished;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for finished queued tasks (R3 -> Guest). */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t u32QueuedTasksFinished;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Bitmap for new queued tasks (Guest -> R3). */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t u32TasksNew;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
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. */
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync volatile uint32_t u32CurrentCommandSlot;
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync#if HC_ARCH_BITS == 64
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync uint32_t u32Alignment2;
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync#endif
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Device specific settings (R3 only stuff). */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's base interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMIBASE) pDrvBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's block interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMIBLOCK) pDrvBlock;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's async block interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMIBLOCKASYNC) pDrvBlockAsync;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's block bios interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the attached driver's mount interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMIMOUNT) pDrvMount;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The base interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIBASE IBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The block port interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIBLOCKPORT IPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The optional block async port interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIBLOCKASYNCPORT IPortAsync;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The mount notify interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIMOUNTNOTIFY IMountNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Physical geometry of this image. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMMEDIAGEOMETRY PCHSGeometry;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The status LED state for this drive. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMLED Led;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint32_t u32Alignment3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Async IO Thread. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync R3PTRTYPE(PPDMTHREAD) pAsyncIOThread;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /** Request semaphore. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync RTSEMEVENT AsyncIORequestSem;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Array of cached tasks. The tag number is the index value.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only used with the async interface.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync R3PTRTYPE(PAHCIREQ) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /** First task throwing an error. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync R3PTRTYPE(volatile PAHCIREQ) pTaskErr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync#if HC_ARCH_BITS == 32
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync uint32_t u32Alignment4;
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync#endif
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of DMA commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMCOUNTER StatDMA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of bytes written. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMCOUNTER StatBytesWritten;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: number of bytes read. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMCOUNTER StatBytesRead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Release statistics: Number of I/O requests processed per second. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMCOUNTER StatIORequestsPerSecond;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_WITH_STATISTICS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Time to complete one request. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMPROFILE StatProfileProcessTime;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Time to map requests into R3. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMPROFILE StatProfileMapIntoR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Amount of time to read/write data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMPROFILE StatProfileReadWrite;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Statistics: Amount of time to destroy a list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAMPROFILE StatProfileDestroyScatterGatherList;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* VBOX_WITH_STATISTICS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync uint32_t cErrors;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync uint32_t u32Alignment5;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync} AHCIPort;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/** Pointer to the state of an AHCI port. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef AHCIPort *PAHCIPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Main AHCI device state.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync *
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMILEDPORTS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCI
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The PCI device structure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDEVICE dev;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R3 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSR3 pDevInsR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSR0 pDevInsR0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the device instance - RC ptr. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINSRC pDevInsRC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: The base interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIBASE IBase;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: Leds interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMILEDPORTS ILeds;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** Status LUN: Partner of ILeds. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync /** Status LUN: Media Notifys. */
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d5d8a18c82ced223ee7d069cdb1ba074c80449d8vboxsync#if HC_ARCH_BITS == 32
d5d8a18c82ced223ee7d069cdb1ba074c80449d8vboxsync uint32_t Alignment1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Base address of the MMIO region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS MMIOBase;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /** Base address of the I/O port region for Idx/Data. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync RTIOPORT IOPortBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Global Host Control register of the HBA */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HBA Capabilities - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaCap;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HBA Control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaCtrl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Interrupt Status */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaIs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Ports Implemented - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaPi;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** AHCI Version - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaVs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command completion coalescing control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaCccCtl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Command completion coalescing ports */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t regHbaCccPorts;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /** Index register for BIOS access. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uint32_t regIdx;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - R3 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PTMTIMERR3 pHbaCccTimerR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - R0 ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PTMTIMERR0 pHbaCccTimerR0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Countdown timer for command completion coalescing - RC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PTMTIMERRC pHbaCccTimerRC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - HC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue to send tasks to R3. - RC ptr */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment5;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Which port number is used to mark an CCC interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uCccPortNr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment6;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Timeout value */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t uCccTimeout;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of completions used to assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uCccNr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Current number of completed commands */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uCccCurrentNr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Register structure per port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCIPort ahciPort[AHCI_MAX_NR_PORTS_IMPL];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
8b82f5ce032cb07de31804c998483b0988530aebvboxsync /** The critical section. */
8b82f5ce032cb07de31804c998483b0988530aebvboxsync PDMCRITSECT lock;
8b82f5ce032cb07de31804c998483b0988530aebvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Bitmask of ports which asserted an interrupt. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync volatile uint32_t u32PortsInterrupted;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device is in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fReset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Supports 64bit addressing */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool f64BitAddr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** GC enabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fGCEnabled;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** R0 enabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fR0Enabled;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** If the new async interface is used if available. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fUseAsyncInterfaceIfAvailable;
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. */
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync bool fBootable;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of usable ports on this controller. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cPortsImpl;
3649373f921ada8549bf86c6edb03b340f2d214avboxsync /** Number of usable command slots for each port. */
3649373f921ada8549bf86c6edb03b340f2d214avboxsync uint32_t cCmdSlotsAvail;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync} AHCI;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/** Pointer to the state of an AHCI device. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef AHCI *PAHCI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Scatter gather list entry.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data Base Address. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32DBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data Base Address - Upper 32-bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32DBAUp;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32Reserved;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Description information. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32DescInf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} SGLEntry;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncAssertCompileSize(SGLEntry, 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Defines for a scatter gather list entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define SGLENTRY_DBA_READONLY ~(RT_BIT(0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define SGLENTRY_DESCINF_I RT_BIT(31)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define SGLENTRY_DESCINF_DBC 0x3fffff
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define SGLENTRY_DESCINF_READONLY 0x803fffff
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the global host control registers for the HBA. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_GLOBAL_SIZE 0x100
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Capabilities - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_S64A RT_BIT(31)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SNCQ RT_BIT(30)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SIS RT_BIT(28)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SSS RT_BIT(27)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SALP RT_BIT(26)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SAL RT_BIT(25)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SCLO RT_BIT(24)
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_ISS_GEN1 RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_HBA_CAP_ISS_GEN2 RT_BIT(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SNZO RT_BIT(19)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SAM RT_BIT(18)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SPM RT_BIT(17)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_PMD RT_BIT(15)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_SSC RT_BIT(14)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CAP_PSC RT_BIT(13)
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_CCCS RT_BIT(7)
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Control register - Read/Write */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CTRL_AE RT_BIT(31)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CTRL_IE RT_BIT(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CTRL_HR RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CTRL_RW_MASK (RT_BIT(0) | RT_BIT(1)) /* Mask for the used bits */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the HBA Version register - Readonly (We support AHCI 1.0) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_VS_MJR (1 << 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_VS_MNR 0x100
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the command completion coalescing control register */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_TV 0xffff0000
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_TV_SET(x) (x << 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_TV_GET(x) ((x & AHCI_HBA_CCC_CTL_TV) >> 16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_CC 0xff00
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_CC_SET(x) (x << 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_CC_GET(x) ((x & AHCI_HBA_CCC_CTL_CC) >> 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_INT 0xf8
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_INT_SET(x) (x << 3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_INT_GET(x) ((x & AHCI_HBA_CCC_CTL_INT) >> 3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_HBA_CCC_CTL_EN RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Defines for the port registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_REGISTER_SIZE 0x80
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CLB_RESERVED 0xfffffc00 /* For masking out the reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b8d7fd85fc9270b7ad49b0e1af2cafec0b9ec818vboxsync#define AHCI_PORT_FB_RESERVED 0xffffff00 /* For masking out the reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_CPDS RT_BIT(31)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_TFES RT_BIT(30)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_HBFS RT_BIT(29)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_HBDS RT_BIT(28)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_IFS RT_BIT(27)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_INFS RT_BIT(26)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_OFS RT_BIT(24)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_IPMS RT_BIT(23)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_PRCS RT_BIT(22)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_DIS RT_BIT(7)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_PCS RT_BIT(6)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_DPS RT_BIT(5)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_UFS RT_BIT(4)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_SDBS RT_BIT(3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_DSS RT_BIT(2)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_PSS RT_BIT(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_DHRS RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IS_READONLY 0xfd8000af /* Readonly mask including reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_CPDE RT_BIT(31)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_TFEE RT_BIT(30)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_HBFE RT_BIT(29)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_HBDE RT_BIT(28)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_IFE RT_BIT(27)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_INFE RT_BIT(26)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_OFE RT_BIT(24)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_IPME RT_BIT(23)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_PRCE RT_BIT(22)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_DIE RT_BIT(7) /* Not supported for now, readonly. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_PCE RT_BIT(6)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_DPE RT_BIT(5)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_UFE RT_BIT(4)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_SDBE RT_BIT(3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_DSE RT_BIT(2)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_PSE RT_BIT(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_DHRE RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_IE_READONLY (0xfdc000ff) /* Readonly mask including reserved bits. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ICC (RT_BIT(28) | RT_BIT(29) | RT_BIT(30) | RT_BIT(31))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ICC_SHIFT(x) ((x) << 28)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_PORT_CMD_ICC_IDLE 0x0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_PORT_CMD_ICC_ACTIVE 0x1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_PORT_CMD_ICC_PARTIAL 0x2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define AHCI_PORT_CMD_ICC_SLUMBER 0x6
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_DLAE RT_BIT(25)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ATAPI RT_BIT(24)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CPD RT_BIT(20)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ISP RT_BIT(19) /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_HPCP RT_BIT(18)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_PMA RT_BIT(17) /* Not supported - Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CPS RT_BIT(16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CR RT_BIT(15) /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_FR RT_BIT(14) /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ISS RT_BIT(13) /* 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_FRE RT_BIT(4)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_CLO RT_BIT(3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_POD RT_BIT(2)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_SUD RT_BIT(1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_ST RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_CMD_READONLY (0xff02001f & ~(AHCI_PORT_CMD_ASP | AHCI_PORT_CMD_ALPE | AHCI_PORT_CMD_PMA))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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_SCTL_DET_NINIT 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_DET_INIT 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_DET_OFFLINE 4
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SCTL_READONLY 0xfff
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_TFD_BSY RT_BIT(7)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_TFD_DRQ RT_BIT(3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_TFD_ERR RT_BIT(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SERR_X RT_BIT(26)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SERR_W RT_BIT(18)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SERR_N RT_BIT(16)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Signatures for attached storage devices. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SIG_DISK 0x00000101
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_SIG_ATAPI 0xeb140101
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
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 */
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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)
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * AHCI register operator.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct ahci_opreg
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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} AHCIOPREG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * AHCI port register operator.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct pAhciPort_opreg
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} AHCIPORTOPREG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncRT_C_DECLS_BEGIN
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciHBAReset(PAHCI pThis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pvBuf, size_t cbBuf);
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pvBuf, size_t cbBuf);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsyncstatic bool ahciCancelActiveTasks(PAHCIPort pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncRT_C_DECLS_END
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# ifdef LOG_USE_C99
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("R3 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("R3 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#elif IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# ifdef LOG_USE_C99
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("R0 P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("R0 P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#elif IN_RC
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# ifdef LOG_USE_C99
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("GC P%u: %M", pAhciPort->iLUN, _LogRelRemoveParentheseis a))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# define ahciLog(a) \
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do { Log(("GC P%u: ", pAhciPort->iLUN)); Log(a); } while(0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Update PCI IRQ levels
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciHbaClearInterrupt(PAHCI pAhci)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Clearing interrupt\n", __FUNCTION__));
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Updates the IRQ level and sets port bit in the global interrupt status register of the HBA.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsyncstatic int ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort, int rcBusy)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync int rc = PDMCritSectEnter(&pAhci->lock, rcBusy);
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync if (rc != VINF_SUCCESS)
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhci->regHbaCtrl & AHCI_HBA_CTRL_IE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhci->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN) && (pAhci->regHbaCccPorts & (1 << iPort)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->uCccCurrentNr++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhci->uCccCurrentNr >= pAhci->uCccNr)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset command completion coalescing state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTimerSetMillies(pAhci->CTX_SUFF(pHbaCccTimer), pAhci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->uCccCurrentNr = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->u32PortsInterrupted |= (1 << pAhci->uCccPortNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!(pAhci->u32PortsInterrupted & ~(1 << pAhci->uCccPortNr)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32((volatile uint32_t *)&pAhci->u32PortsInterrupted, (1 << iPort));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!(pAhci->u32PortsInterrupted & ~(1 << iPort)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Fire interrupt\n", iPort, __FUNCTION__));
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(pAhci->CTX_SUFF(pDevIns), 0, 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMCritSectLeave(&pAhci->lock);
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Assert irq when an CCC timeout occurs
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLCALLBACK(void) ahciCccTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = (PAHCI)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdIssue_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uCIValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Update the CI register first. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCI &= ~uCIValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync if ( (pAhciPort->regCMD & AHCI_PORT_CMD_CR)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync && u32Value > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint32_t u32Tasks;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /*
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Clear all tasks which are already marked as busy. The guest
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * shouldn't write already busy tasks actually.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync u32Value &= ~pAhciPort->regCI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync u32Tasks = ASMAtomicReadU32(&pAhciPort->u32TasksNew);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Send a notification to R3 if u32TasksNew was before our write. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (!(u32Tasks ^ u32Value))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pItem->iPort = pAhciPort->iLUN;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCI |= u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdIssue_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uCIValue = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uCIValue = ASMAtomicXchgU32(&pAhciPort->u32TasksFinished, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCI=%#010x uCIValue=%#010x\n", __FUNCTION__, pAhciPort->regCI, uCIValue));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCI &= ~uCIValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regCI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSActive_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSACT |= u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSActive_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32TasksFinished = ASMAtomicXchgU32(&pAhciPort->u32QueuedTasksFinished, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSACT &= ~u32TasksFinished;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSACT=%#010x regCI=%#010x u32TasksFinished=%#010x\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pAhciPort->regSACT, pAhciPort->regCI, u32TasksFinished));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regSACT;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSError_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync if ( (u32Value & AHCI_PORT_SERR_X)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync && (pAhciPort->regSERR & AHCI_PORT_SERR_X))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD |= ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD &= ~(ATA_STAT_DRQ | ATA_STAT_BUSY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync if ( (u32Value & AHCI_PORT_SERR_N)
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync && (pAhciPort->regSERR & AHCI_PORT_SERR_N))
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~AHCI_PORT_IS_PRCS);
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync pAhciPort->regSERR &= ~u32Value;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSError_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSERR=%#010x\n", __FUNCTION__, pAhciPort->regSERR));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regSERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSControl_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#ifndef IN_RING3
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync return VINF_IOM_R3_MMIO_WRITE;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fAllTasksCanceled;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Cancel all tasks first. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync Assert(fAllTasksCanceled);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
56bef151ea50f63620466fce377458ce5fd0967avboxsync if (!ASMAtomicXchgBool(&pAhciPort->fPortReset, true))
56bef151ea50f63620466fce377458ce5fd0967avboxsync LogRel(("AHCI#%d: Port %d reset\n", ahci->CTX_SUFF(pDevIns)->iInstance,
56bef151ea50f63620466fce377458ce5fd0967avboxsync pAhciPort->iLUN));
56bef151ea50f63620466fce377458ce5fd0967avboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = ~0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = 0x7f;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fFirstD2HFisSend = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_NINIT && pAhciPort->pDrvBase &&
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regSCTL & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Signature for SATA device. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x03 << 0); /* Device detected and communication established. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Use the maximum allowed speed.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * (Not that it changes anything really)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (AHCI_PORT_SCTL_SPD_GET(pAhciPort->regSCTL))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x01:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS |= (0x01 << 4); /* Generation 1 (1.5GBps) speed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x02:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x00:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS |= (0x02 << 4); /* Generation 2 (3.0GBps) speed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We received a COMINIT from the device. Tell the guest. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_PCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSERR |= AHCI_PORT_SERR_X;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD |= ATA_STAT_BUSY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_FRE) && (!pAhciPort->fFirstD2HFisSend))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFirstD2HFisIntoMemory(pAhciPort);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync {
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSCTL = u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSControl_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_SCTL_DET_GET(pAhciPort->regSCTL)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regSCTL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSStatus_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_SSTS_DET_GET(pAhciPort->regSSTS)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regSSTS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortSignature_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regSIG=%#010x\n", __FUNCTION__, pAhciPort->regSIG));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regSIG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortTaskFileData_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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 *pu32Value = pAhciPort->regTFD;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmd_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCMD=%#010x\n", __FUNCTION__, pAhciPort->regCMD));
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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ST)));
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync *pu32Value = pAhciPort->regCMD | AHCI_PORT_CMD_CCS_SHIFT(pAhciPort->u32CurrentCommandSlot);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is the register where all the data transfer is started
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmd_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_PORT_CMD_ST)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fPoweredOn && pAhciPort->fSpunUp)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32Value & AHCI_PORT_CMD_CLO)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command list override requested\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~(AHCI_PORT_TFD_BSY | AHCI_PORT_TFD_DRQ);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear the CLO bit. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~(AHCI_PORT_CMD_CLO);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32Value & AHCI_PORT_CMD_ST)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Engine starts\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync /* Set engine state to running if there is a device attached. */
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync if (pAhciPort->pDrvBase)
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync u32Value |= AHCI_PORT_CMD_CR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Engine stops\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear command issue register. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCI = 0;
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync /* Clear current command slot. */
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync pAhciPort->u32CurrentCommandSlot = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~AHCI_PORT_CMD_CR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_CMD_POD) && (pAhciPort->regCMD & AHCI_PORT_CMD_CPS) && !pAhciPort->fPoweredOn)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Power on the device\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fPoweredOn = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set states in the Port Signature and SStatus registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync if (pAhciPort->fATAPI)
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync else
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x03 << 0); /* Device detected and communication established. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifndef IN_RING3
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync return VINF_IOM_R3_MMIO_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFirstD2HFisIntoMemory(pAhciPort);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync {
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_CMD_SUD) && pAhciPort->fPoweredOn && !pAhciPort->fSpunUp)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Spin up the device\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fSpunUp = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32Value & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FIS receive enabled\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value |= AHCI_PORT_CMD_FR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Send the first D2H FIS only if it wasn't already send. */
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync if ( !pAhciPort->fFirstD2HFisSend
16e6bb956968b3b7caee5a07dc98ad0e4aa60d36vboxsync && pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifndef IN_RING3
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync return VINF_IOM_R3_MMIO_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFirstD2HFisIntoMemory(pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fFirstD2HFisSend = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!(u32Value & AHCI_PORT_CMD_FRE))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FIS receive disabled\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~AHCI_PORT_CMD_FR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD = u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port interrupt enable register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrEnable_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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 (pAhciPort->regIE & AHCI_PORT_IE_DHRE)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regIE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port interrupt enable register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrEnable_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync int rc = VINF_SUCCESS;
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 (u32Value & AHCI_PORT_IE_DHRE)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync u32Value &= AHCI_PORT_IE_READONLY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if some a interrupt status bit changed*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync if (u32Value & u32IntrStatus)
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = ahciHbaSetInterrupt(ahci, pAhciPort->iLUN, VINF_IOM_R3_MMIO_WRITE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync if (rc == VINF_SUCCESS)
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync pAhciPort->regIE = u32Value;
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync
b4dc9a151c850935f866da241db86e6ae33c45a2vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrSts_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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 (pAhciPort->regIS & AHCI_PORT_IS_DHRS)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regIS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortIntrSts_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicAndU32(&pAhciPort->regIS, ~(u32Value & AHCI_PORT_IS_READONLY));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port FIS base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regFBU=%#010x\n", __FUNCTION__, pAhciPort->regFBU));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regFBU;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port FIS base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regFBU = u32Value;
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port FIS base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regFB=%#010x\n", __FUNCTION__, pAhciPort->regFB));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regFB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port FIS base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortFisAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync Assert(!(u32Value & ~AHCI_PORT_FB_RESERVED));
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regFB = (u32Value & AHCI_PORT_FB_RESERVED);
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrFb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regFBU, pAhciPort->regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command list base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddrUp_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCLBU = u32Value;
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command list base address upper 32bit register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddrUp_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCLBU=%#010x\n", __FUNCTION__, pAhciPort->regCLBU));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regCLBU;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the port command list base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddr_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: read regCLB=%#010x\n", __FUNCTION__, pAhciPort->regCLB));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regCLB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the port command list base address register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortCmdLstAddr_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync Assert(!(u32Value & ~AHCI_PORT_CLB_RESERVED));
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCLB = (u32Value & AHCI_PORT_CLB_RESERVED);
9b9a21c4dedad15ac8b2059a858a94c5a33db1bdvboxsync pAhciPort->GCPhysAddrClb = AHCI_RTGCPHYS_FROM_U32(pAhciPort->regCLBU, pAhciPort->regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global Version register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaVersion_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaVs=%#010x\n", __FUNCTION__, ahci->regHbaVs));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = ahci->regHbaVs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global Ports implemented register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaPortsImplemented_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaPi=%#010x\n", __FUNCTION__, ahci->regHbaPi));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = ahci->regHbaPi;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInterruptStatus_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_WRITE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc != VINF_SUCCESS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32Value > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Clear the interrupt only if no port has signalled
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * an interrupt and the guest has cleared all set interrupt
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * notification bits.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync bool fClear = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->regHbaIs &= ~(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fClear = !ahci->u32PortsInterrupted && !ahci->regHbaIs;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync if (fClear)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync unsigned i = 0;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync /* Check if the cleared ports have a interrupt status bit set. */
2d8894b1c178c9f1199cac84059ca66aa5dee6b3vboxsync while ((u32Value > 0) && (i < AHCI_MAX_NR_PORTS_IMPL))
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync if (u32Value & 0x01)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync PAHCIPort pAhciPort = &ahci->ahciPort[i];
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync if (pAhciPort->regIE & pAhciPort->regIS)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync Log(("%s: Interrupt status of port %u set -> Set interrupt again\n", __FUNCTION__, i));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&ahci->u32PortsInterrupted, 1 << i);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync fClear = false;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync break;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync }
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync }
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync u32Value = u32Value >> 1;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync i++;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync }
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync }
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync if (fClear)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaClearInterrupt(ahci);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Not clearing interrupt: u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->u32PortsInterrupted));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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 */
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 0);
5e403442588989687ee8fb66dd921dd08199bfd0vboxsync PDMDevHlpPCISetIrq(ahci->CTX_SUFF(pDevIns), 0, 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMCritSectLeave(&ahci->lock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read from the global interrupt status register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInterruptStatus_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32PortsInterrupted;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_R3_MMIO_READ);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc != VINF_SUCCESS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32PortsInterrupted = ASMAtomicXchgU32(&ahci->u32PortsInterrupted, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMCritSectLeave(&ahci->lock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaIs=%#010x u32PortsInterrupted=%#010x\n", __FUNCTION__, ahci->regHbaIs, u32PortsInterrupted));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->regHbaIs |= u32PortsInterrupted;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef LOG_ENABLED
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < ahci->cPortsImpl; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((ahci->regHbaIs >> i) & 0x01)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log((" P%d", i));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = ahci->regHbaIs;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaControl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: AE=%d IE=%d HR=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, u32Value,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (u32Value & AHCI_HBA_CTRL_AE) >> 31, (u32Value & AHCI_HBA_CTRL_IE) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (u32Value & AHCI_HBA_CTRL_HR)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#ifndef IN_RING3
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync return VINF_IOM_R3_MMIO_WRITE;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->regHbaCtrl = (u32Value & AHCI_HBA_CTRL_RW_MASK) | AHCI_HBA_CTRL_AE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHBAReset(ahci);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaControl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaCtrl=%#010x\n"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: AE=%d IE=%d HR=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, ahci->regHbaCtrl,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, (ahci->regHbaCtrl & AHCI_HBA_CTRL_AE) >> 31, (ahci->regHbaCtrl & AHCI_HBA_CTRL_IE) >> 1,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (ahci->regHbaCtrl & AHCI_HBA_CTRL_HR)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = ahci->regHbaCtrl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global capabilities register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCapabilities_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaCap=%#010x\n"
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,
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 *pu32Value = ahci->regHbaCap;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global command completion coalescing control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccCtl_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: TV=%d CC=%d INT=%d EN=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, u32Value,
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->regHbaCccCtl = u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->uCccTimeout = AHCI_HBA_CCC_CTL_TV_GET(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->uCccPortNr = AHCI_HBA_CCC_CTL_INT_GET(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->uCccNr = AHCI_HBA_CCC_CTL_CC_GET(u32Value);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32Value & AHCI_HBA_CCC_CTL_EN)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Arm the timer */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTimerSetMillies(ahci->CTX_SUFF(pHbaCccTimer), ahci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTimerStop(ahci->CTX_SUFF(pHbaCccTimer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global command completion coalescing control register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccCtl_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaCccCtl=%#010x\n"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "%s: TV=%d CC=%d INT=%d EN=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, ahci->regHbaCccCtl,
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 *pu32Value = ahci->regHbaCccCtl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Write to the global command completion coalescing ports register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccPorts_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: write u32Value=%#010x\n", __FUNCTION__, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahci->regHbaCccPorts = u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the global command completion coalescing ports register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaCccPorts_r(PAHCI ahci, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: read regHbaCccPorts=%#010x\n", __FUNCTION__, ahci->regHbaCccPorts));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef LOG_ENABLED
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < ahci->cPortsImpl; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((ahci->regHbaCccPorts >> i) & 0x01)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log((" P%d", i));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = ahci->regHbaCccPorts;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid write to global register
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int HbaInvalid_w(PAHCI ahci, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid Port write.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortInvalid_w(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t u32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Write denied!!! iReg=%u u32Value=%#010x\n", __FUNCTION__, iReg, u32Value));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Invalid Port read.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int PortInvalid_r(PAHCI ahci, PAHCIPort pAhciPort, uint32_t iReg, uint32_t *pu32Value)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Read denied!!! iReg=%u\n", __FUNCTION__, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register descriptor table for global HBA registers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const AHCIOPREG g_aOpRegs[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaCapabilites", HbaCapabilities_r, HbaInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaControl" , HbaControl_r, HbaControl_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaInterruptStatus", HbaInterruptStatus_r, HbaInterruptStatus_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaPortsImplemented", HbaPortsImplemented_r, HbaInvalid_w}, /* Readonly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaVersion", HbaVersion_r, HbaInvalid_w}, /* ReadOnly */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaCccCtl", HbaCccCtl_r, HbaCccCtl_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"HbaCccPorts", HbaCccPorts_r, HbaCccPorts_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register descriptor table for port registers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const AHCIPORTOPREG g_aPortOpRegs[] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmdLstAddr", PortCmdLstAddr_r, PortCmdLstAddr_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmdLstAddrUp", PortCmdLstAddrUp_r, PortCmdLstAddrUp_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortFisAddr", PortFisAddr_r, PortFisAddr_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortFisAddrUp", PortFisAddrUp_r, PortFisAddrUp_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortIntrSts", PortIntrSts_r, PortIntrSts_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortIntrEnable", PortIntrEnable_r, PortIntrEnable_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmd", PortCmd_r, PortCmd_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 {"PortSControl", PortSControl_r, PortSControl_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortSError", PortSError_r, PortSError_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortSActive", PortSActive_r, PortSActive_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortCmdIssue", PortCmdIssue_r, PortCmdIssue_w},
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {"PortReserved2", PortInvalid_r, PortInvalid_w}, /* Not used. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset initiated by system software for one port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port to reset.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPortSwReset(PAHCIPort pAhciPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fAllTasksCanceled;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Cancel all tasks first. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync fAllTasksCanceled = ahciCancelActiveTasks(pAhciPort);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync Assert(fAllTasksCanceled);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regIS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regIE = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync AHCI_PORT_CMD_HPCP | /* Hotplugging supported. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_CMD_SUD | /* Device has spun up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_PORT_CMD_POD; /* Port is powered on. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = ~0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSCTL = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSERR = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSACT = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCI = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fResetDevice = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fPoweredOn = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fSpunUp = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->u32TasksNew = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->u32TasksFinished = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->u32QueuedTasksFinished = 0;
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync pAhciPort->u32CurrentCommandSlot = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->cTasksActive = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ASMAtomicWriteU32(&pAhciPort->MediaTrackType, ATA_MEDIA_TYPE_UNKNOWN);
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD |= AHCI_PORT_CMD_CPS; /* Indicate that there is a device on that port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fPoweredOn)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set states in the Port Signature and SStatus registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync if (pAhciPort->fATAPI)
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync else
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (0x03 << 0); /* Device detected and communication established. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Hardware reset used for machine power on and reset.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciport The port to reset.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPortHwReset(PAHCIPort pAhciPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset the address registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCLB = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCLBU = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regFB = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regFBU = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset calculated addresses. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->GCPhysAddrClb = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->GCPhysAddrFb = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Create implemented ports bitmap.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns 32bit bitmask with a bit set for every implemented port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cPorts Number of ports.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint32_t ahciGetPortsImplemented(unsigned cPorts)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uPortsImplemented = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (unsigned i = 0; i < cPorts; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uPortsImplemented |= (1 << i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return uPortsImplemented;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset the entire HBA.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThis The HBA state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciHBAReset(PAHCI pThis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
56bef151ea50f63620466fce377458ce5fd0967avboxsync LogRel(("AHCI#%d: Reset the HBA\n", pThis->CTX_SUFF(pDevIns)->iInstance));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Stop the CCC timer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->regHbaCccCtl & AHCI_HBA_CCC_CTL_EN)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = TMTimerStop(pThis->CTX_SUFF(pHbaCccTimer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to stop timer!\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d3faf04f5ef353bbc31bb75a17444d7902726d2evboxsync /* Reset every port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < pThis->cPortsImpl; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pThis->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->iLUN = i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPortSwReset(pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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_SAM | /* AHCI mode only */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_SNCQ | /* Support native command queuing */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_SSS | /* Staggered spin up */
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->regHbaCtrl = AHCI_HBA_CTRL_AE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaIs = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaPi = ahciGetPortsImplemented(pThis->cPortsImpl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaVs = AHCI_HBA_VS_MJR | AHCI_HBA_VS_MNR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaCccCtl = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaCccPorts = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->uCccTimeout = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->uCccPortNr = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->uCccNr = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->f64BitAddr = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->u32PortsInterrupted = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->f8ByteMMIO4BytesWrittenSuccessfully = false;
d3faf04f5ef353bbc31bb75a17444d7902726d2evboxsync /* Clear the HBA Reset bit */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->regHbaCtrl &= ~AHCI_HBA_CTRL_HR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Reads from a AHCI controller register.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncstatic int ahciRegisterRead(PAHCI pAhci, uint32_t uReg, void *pv, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uint32_t iReg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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 */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (uReg < AHCI_HBA_GLOBAL_SIZE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iReg = uReg >> 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read from global register %u\n", __FUNCTION__, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iReg < RT_ELEMENTS(g_aOpRegs))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const AHCIOPREG *pReg = &g_aOpRegs[iReg];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pReg->pfnRead(pAhci, iReg, (uint32_t *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *(uint32_t *)pv = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iRegOffset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Calculate accessed port. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uReg -= AHCI_HBA_GLOBAL_SIZE;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iPort = uReg / AHCI_PORT_REGISTER_SIZE;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iRegOffset = (uReg % AHCI_PORT_REGISTER_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iReg = iRegOffset >> 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read from port %u and register %u\n", __FUNCTION__, iPort, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_LIKELY( iPort < pAhci->cPortsImpl
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && iReg < RT_ELEMENTS(g_aPortOpRegs)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pPortReg->pfnRead(pAhci, &pAhci->ahciPort[iPort], iReg, (uint32_t *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to read port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_IOM_MMIO_UNUSED_00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Windows Vista tries to read one byte from some registers instead of four.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Correct the value according to the read size.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc) && cb != sizeof(uint32_t))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 1:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uNewValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *p = (uint8_t *)pv;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iRegOffset &= 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: iRegOffset=%u\n", __FUNCTION__, iRegOffset));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uNewValue = p[iRegOffset];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Clear old value */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *(uint32_t *)pv = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *(uint8_t *)pv = uNewValue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync AssertMsgFailed(("%s: unsupported access width cb=%d iPort=%x iRegOffset=%x iReg=%x!!!\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync __FUNCTION__, cb, iPort, iRegOffset, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync}
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Writes a value to one of the AHCI controller registers.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pAhci The AHCI instance.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param uReg The register to write.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param pv Where to fetch the result.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @param cb Number of bytes to write.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync */
6826c1a65f586b47c2abbbabab801950c9a0bb75vboxsyncstatic int ahciRegisterWrite(PAHCI pAhci, uint32_t uReg, void const *pv, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uint32_t iReg;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (uReg < AHCI_HBA_GLOBAL_SIZE)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("Write global HBA register\n"));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iReg = uReg >> 2;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (iReg < RT_ELEMENTS(g_aOpRegs))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync const AHCIOPREG *pReg = &g_aOpRegs[iReg];
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uint32_t iPort;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("Write Port register\n"));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Calculate accessed port. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uReg -= AHCI_HBA_GLOBAL_SIZE;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iPort = uReg / AHCI_PORT_REGISTER_SIZE;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync iReg = (uReg % AHCI_PORT_REGISTER_SIZE) >> 2;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (RT_LIKELY( iPort < pAhci->cPortsImpl
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync && iReg < RT_ELEMENTS(g_aPortOpRegs)))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync}
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Memory mapped I/O Handler for read operations.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
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.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Break up 64 bits reads into two dword reads. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (cb == 8)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciMMIORead(pDevIns, pvUser, GCPhysAddr, pv, 4);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (RT_FAILURE(rc))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return ahciMMIORead(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciRegisterRead(pAhci, uOffset, pv, cb);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
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 return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Memory mapped I/O Handler for write operations.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6826c1a65f586b47c2abbbabab801950c9a0bb75vboxsyncPDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Break up 64 bits writes into two dword writes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cb == 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhci->f8ByteMMIO4BytesWrittenSuccessfully)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr, pv, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc != VINF_SUCCESS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->f8ByteMMIO4BytesWrittenSuccessfully = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciMMIOWrite(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset flag again so that the first 4 bytes are written again on the next
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 8byte MMIO access.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VINF_SUCCESS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->f8ByteMMIO4BytesWrittenSuccessfully = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("#%d ahciMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Validate access. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cb != sizeof(uint32_t))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: Bad write size!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (GCPhysAddr & 0x3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: Unaligned write!!! GCPhysAddr=%RGp cb=%d\n", __FUNCTION__, GCPhysAddr, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the access offset is smaller than 100h the guest accesses the global registers.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Otherwise it accesses the registers of a port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciRegisterWrite(pAhci, uOffset, pv, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Should not happen\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Should not happen\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * I/O port handler for writes to the index/data register pair.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
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.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciIdxDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (Port - pAhci->IOPortBase >= 8)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Assert(cb == 4);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (iReg == 0)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Write the index register. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pAhci->regIdx = u32;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Assert(iReg == 1);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciRegisterWrite(pAhci, pAhci->regIdx, &u32, cb);
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync if (rc == VINF_IOM_R3_MMIO_WRITE)
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = VINF_IOM_R3_IOPORT_WRITE;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* else: ignore */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("#%d ahciIdxDataWrite: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pDevIns->iInstance, &u32, cb, &u32, cb, Port, rc));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync}
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * I/O port handler for reads from the index/data register pair.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * @returns VBox status code.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *
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.
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncPDMBOTHCBDECL(int) ahciIdxDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (Port - pAhci->IOPortBase >= 8)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync unsigned iReg = (Port - pAhci->IOPortBase - 8) / 4;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Assert(cb == 4);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (iReg == 0)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync /* Read the index register. */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *pu32 = pAhci->regIdx;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Assert(iReg == 1);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = ahciRegisterRead(pAhci, pAhci->regIdx, pu32, cb);
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync if (rc == VINF_IOM_R3_MMIO_READ)
648b0a0e189323afe4d836f1848f82c7dded0e58vboxsync rc = VINF_IOM_R3_IOPORT_READ;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync else
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync *pu32 = UINT32_C(0xffffffff);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("#%d ahciIdxDataRead: pu32=%p:{%.*Rhxs} cb=%d Port=%#x rc=%Rrc\n",
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pDevIns->iInstance, pu32, cb, pu32, cb, Port, rc));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync}
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINS pDevIns = pPciDev->pDevIns;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(enmType == PCI_ADDRESS_SPACE_MEM);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(cb >= 4352);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync ahciMMIOWrite, ahciMMIORead, "AHCI");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fR0Enabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fGCEnabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
fb9af443dbf06990f4956d683286ddce29c4dca6vboxsync rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, "ahciMMIOWrite", "ahciMMIORead");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->MMIOBase = GCPhysAddress;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Map the legacy I/O port ranges to make Solaris work with the controller.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINS pDevIns = pPciDev->pDevIns;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(enmType == PCI_ADDRESS_SPACE_IO);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fR0Enabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fGCEnabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciLegacyFakeWrite", "ahciLegacyFakeRead", NULL, NULL, "AHCI Fake");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync/**
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync * Map the BMDMA I/O port range (used for the Index/Data pair register access)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsyncstatic DECLCALLBACK(int) ahciR3IdxDataIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync{
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PPDMDEVINS pDevIns = pPciDev->pDevIns;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync int rc = VINF_SUCCESS;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Log2(("%s: registering fake I/O area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync Assert(enmType == PCI_ADDRESS_SPACE_IO);
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
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 if (RT_FAILURE(rc))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (pThis->fR0Enabled)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (RT_FAILURE(rc))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (pThis->fGCEnabled)
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync {
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, cb, 0,
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync "ahciIdxDataWrite", "ahciIdxDataRead", NULL, NULL, "AHCI IDX/DATA");
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync if (RT_FAILURE(rc))
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync }
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync return rc;
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync}
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* -=-=-=-=-=- PAHCI::ILeds -=-=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Gets the pointer to the status LED of a unit.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iLUN < AHCI_MAX_NR_PORTS_IMPL)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *ppLed = &pAhci->ahciPort[iLUN].Led;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_PDM_LUN_NOT_FOUND;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync{
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync/**
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @interface_method_impl{PDMIBLOCKPORT,pfnQueryDeviceLocation}
6308f6770d7f8fb842b437338e31554e913e6773vboxsync */
cab115cfa31c584def7069312a1e23c3fc88533bvboxsyncstatic DECLCALLBACK(int) ahciR3PortQueryDeviceLocation(PPDMIBLOCKPORT pInterface, const char **ppcszController,
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync uint32_t *piInstance, uint32_t *piLUN)
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync{
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync PAHCIPort pAhciPort = PDMIBLOCKPORT_2_PAHCIPORT(pInterface);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync *ppcszController = pDevIns->pReg->szName;
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync *piInstance = pDevIns->iInstance;
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync *piLUN = pAhciPort->iLUN;
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync return VINF_SUCCESS;
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync}
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Dump info about the FIS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port the command FIS was read from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cmdFis The FIS to print info from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciDumpFisInfo(PAHCIPort pAhciPort, uint8_t *cmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** Begin FIS info dump. ***\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print FIS type. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (cmdFis[AHCI_CMDFIS_TYPE])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_H2D:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
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 if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command register update\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
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
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
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: Reset bit is set\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_D2H:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_SETDEVBITS:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
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));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMAACTD2H:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
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));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMASETUP:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_PIOSETUP:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DATA:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ERROR Unknown command FIS type\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: *** End FIS info dump. ***\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Dump info about the command header
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciDumpCmdHdrInfo(PAHCIPort pAhciPort, CmdHdr *pCmdHdr)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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 if (pCmdHdr->u32DescInf & AHCI_CMDHDR_C)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Clear busy upon R_OK\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdHdr->u32DescInf & AHCI_CMDHDR_B)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: BIST Fis\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdHdr->u32DescInf & AHCI_CMDHDR_R)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Device Reset Fis\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdHdr->u32DescInf & AHCI_CMDHDR_P)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command prefetchable\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdHdr->u32DescInf & AHCI_CMDHDR_W)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Device write\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Device read\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdHdr->u32DescInf & AHCI_CMDHDR_A)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ATAPI command\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ATA command\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* DEBUG */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Post the first D2H FIS from the device into guest memory.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort Pointer to the port which "receives" the FIS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t d2hFis[AHCI_CMDFIS_TYPE_D2H_SIZE];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fFirstD2HFisSend = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Sending First D2H FIS from FIFO\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&d2hFis[0], 0, sizeof(d2hFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_ERR] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_STS] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set the signature based on the device type. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLL] = 0x14;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLH] = 0xeb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLL] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_CYLH] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_HEAD] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTN] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_SECTC] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync if (!pAhciPort->fATAPI)
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync pAhciPort->regTFD |= ATA_STAT_READY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Post the FIS in the memory area allocated by the guest and set interrupt if necessary.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrRecFis = pAhciPort->GCPhysAddrFb;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cbFis = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pAhciPort=%p uFisType=%u pCmdFis=%p\n", __FUNCTION__, pAhciPort, uFisType, pCmdFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(GCPhysAddrRecFis, ("%s: GCPhysAddrRecFis is 0\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Determine the offset and size of the FIS based on uFisType. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (uFisType)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_D2H:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_SETDEVBITS:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMASETUP:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_PIOSETUP:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We should post the unknown FIS into memory too but this never happens because
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * we know which FIS types we generate. ;)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Unknown FIS type!\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Post the FIS into memory. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: PDMDevHlpPhysWrite GCPhysAddrRecFis=%RGp cbFis=%u\n", __FUNCTION__, GCPhysAddrRecFis, cbFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrRecFis, pCmdFis, cbFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[0] = val >> 8;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[1] = val;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[0] = val >> 16;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[1] = val >> 8;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[2] = val;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[0] = val >> 24;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[1] = val >> 16;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[2] = val >> 8;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[3] = val;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] << 8) | pbBuf[1];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iATAPILBA += 150;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[0] = (iATAPILBA / 75) / 60;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[1] = (iATAPILBA / 75) % 60;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf[2] = iATAPILBA % 75;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void atapiCmdOK(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->abATAPISense[0] = 0x70;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->abATAPISense[7] = 10;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void atapiCmdError(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, const uint8_t *pabATAPISense, size_t cbATAPISense)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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->uATARegError = pabATAPISense[2] << 4;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciReq->cmdFis[AHCI_CMDFIS_SECTN] & ~7) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memset(pAhciPort->abATAPISense, '\0', sizeof(pAhciPort->abATAPISense));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memcpy(pAhciPort->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pAhciPort->abATAPISense)));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
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)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abATAPISense[ATAPI_SENSE_SIZE];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memset(abATAPISense, '\0', sizeof(abATAPISense));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense[0] = 0x70 | (1 << 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense[2] = uATAPISenseKey & 0x0f;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense[7] = 10;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense[12] = uATAPIASC;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < cbSize; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (*pbSrc)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbDst[i] = *pbSrc++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbDst[i] = ' ';
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < cbSize; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (*pbSrc)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbDst[i ^ 1] = *pbSrc++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbDst[i ^ 1] = ' ';
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsyncstatic uint32_t ataChecksum(void* ptr, size_t count)
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync{
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync uint8_t u8Sum = 0xa5, *p = (uint8_t*)ptr;
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync size_t i;
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync for (i = 0; i < count; i++)
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync {
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync u8Sum += *p++;
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync }
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync return (uint8_t)-(int32_t)u8Sum;
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync}
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciIdentifySS(PAHCIPort pAhciPort, void *pvBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint16_t *p;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p = (uint16_t *)pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(p, 0, 512);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[0] = RT_H2LE_U16(0x0040);
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[5] = RT_H2LE_U16(512);
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 p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
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#if ATA_MAX_MULT_SECTORS > 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
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[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
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 if (pAhciPort->cMultSectors)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[59] = RT_H2LE_U16(0x100 | pAhciPort->cMultSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cTotalSectors <= (1 << 28) - 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[60] = RT_H2LE_U16(pAhciPort->cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[61] = RT_H2LE_U16(pAhciPort->cTotalSectors >> 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Report maximum number of sectors possible with LBA28 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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 */
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync if ( pAhciPort->pDrvBlock->pfnDiscard
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync || ( pAhciPort->fAsyncInterface
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
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 }
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync else
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
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 */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync }
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[84] = RT_H2LE_U16(1 << 14);
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[87] = RT_H2LE_U16(1 << 14);
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(0x00);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[100] = RT_H2LE_U16(pAhciPort->cTotalSectors);
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);
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync if (pAhciPort->fNonRotational)
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync if ( pAhciPort->pDrvBlock->pfnDiscard
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync || ( pAhciPort->fAsyncInterface
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. */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync uint32_t uCsum = ataChecksum(p, 510);
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync p[255] = RT_H2LE_U16(0xa5 | (uCsum << 8)); /* Integrity word */
996f6011d1bafd9dd0ebfd07bf8821eff20491dfvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsynctypedef int (*PAtapiFunc)(PAHCIREQ, PAHCIPort, size_t, size_t *);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
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 *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Source/sink function indexes for g_apfnAtapiFuncs.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef enum ATAPIFN
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_NULL = 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_GET_CONFIGURATION,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_IDENTIFY,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_INQUIRY,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_MECHANISM_STATUS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_CAPACITY,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_TOC_NORMAL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_TOC_MULTI,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_TOC_RAW,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_ATAPI_REQUEST_SENSE,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ATAFN_SS_ATAPI_PASSTHROUGH,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ATAFN_SS_MAX
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} ATAPIFN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Array of source/sink functions, the index is ATAFNSS.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Make sure ATAFNSS and this array match!
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic const PAtapiFunc g_apfnAtapiFuncs[ATAFN_SS_MAX] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiGetConfigurationSS,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiGetEventStatusNotificationSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiIdentifySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiInquirySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiMechanismStatusSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiModeSenseErrorRecoverySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiModeSenseCDStatusSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadCapacitySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadDiscInformationSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCNormalSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCMultiSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCRawSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTrackInformationSS,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiRequestSenseSS,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiPassthroughSS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiIdentifySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint16_t p[256];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(p, 0, 512);
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[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
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[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
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[83] = RT_H2LE_U16(1 << 14);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[84] = RT_H2LE_U16(1 << 14);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[86] = RT_H2LE_U16(0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[87] = RT_H2LE_U16(1 << 14);
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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&p[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(p)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadCapacitySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[8];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf, pAhciPort->cTotalSectors - 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 4, 2048);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadDiscInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[34];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(aBuf, '\0', 34);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf, 32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 1; /* number of first track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[4] = 1; /* number of sessions (LSB) */
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 aBuf[8] = 0; /* disc type = CD-ROM */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[9] = 0; /* number of sessions (MSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[10] = 0; /* number of sessions (MSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[11] = 0; /* number of sessions (MSB) */
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTrackInformationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[36];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(aBuf, '\0', 36);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf, 34);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 1; /* track number (LSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 1; /* session number (LSB) */
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 aBuf[32] = 0; /* track number (MSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[33] = 0; /* session number (MSB) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureListProfiles(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 3*4)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
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 pbBuf[3] = 8; /* additional bytes for profiles */
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 pbBuf[6] = (0 << 0); /* NOT current profile */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 8, 0x08); /* profile: read only CD */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[10] = (1 << 0); /* current profile */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 3*4; /* Header + 2 profiles entries */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureCore(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 12)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x1); /* feature 0001h: Core Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x2 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[3] = 8; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 4, 0x00000002); /* Physical interface ATAPI. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[8] = RT_BIT(0); /* DBE */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 12;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureMorphing(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 8)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x2); /* feature 0002h: Morphing Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x1 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[3] = 4; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[4] = RT_BIT(1) | 0x0; /* OCEvent | !ASYNC */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 8;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureRemovableMedium(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 8)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
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 pbBuf[3] = 4; /* Additional length */
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. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 8;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureRandomReadable(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 12)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
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 pbBuf[3] = 8; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U32(pbBuf + 4, 2048); /* Logical block size. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 8, 0x10); /* Blocking (0x10 for DVD, CD is not defined). */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[10] = 0; /* PP not present */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 12;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureCDRead(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 8)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
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[3] = 0; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[4] = (0x0 << 7) | (0x0 << 1) | 0x0; /* !DAP | !C2-Flags | !CD-Text. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Rest is reserved. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 8;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeaturePowerManagement(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 4)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x100); /* feature 0100h: Power Management Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[3] = 0; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 4;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsyncstatic size_t atapiGetConfigurationFillFeatureTimeout(PAHCIPort pAhciPort, uint8_t *pbBuf, size_t cbBuf)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync if (cbBuf < 8)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 0;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf, 0x105); /* feature 0105h: Timeout Feature */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[2] = (0x0 << 2) | RT_BIT(1) | RT_BIT(0); /* Version | Persistent | Current */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[3] = 4; /* Additional length */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf[4] = 0x0; /* !Group3 */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync return 8;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetConfigurationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync uint8_t aBuf[80];
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync uint8_t *pbBuf = &aBuf[0];
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync size_t cbBuf = sizeof(aBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync size_t cbCopied = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Accept valid request types only, and only starting feature 0. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ((pAhciReq->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciReq->aATAPICmd[2]) != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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 if (pAhciPort->cTotalSectors)
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync else
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U16(pbBuf + 6, 0x00); /* current profile: none -> no media */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= 8;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += 8;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureListProfiles(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureCore(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureMorphing(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureRemovableMedium(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureRandomReadable(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureCDRead(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeaturePowerManagement(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbCopied = atapiGetConfigurationFillFeatureTimeout(pAhciPort, pbBuf, cbBuf);
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync cbBuf -= cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync pbBuf += cbCopied;
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync /* Set data length now. */
2255e4c50ad0baa1a293a35a61e893633b7f7727vboxsync ataH2BE_U32(&aBuf[0], sizeof(aBuf) - cbBuf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiGetEventStatusNotificationSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abBuf[8];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Assert(pAhciReq->enmTxDir == AHCITXDIR_READ);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Assert(pAhciReq->cbTransfer <= 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->aATAPICmd[1] & 1))
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* no asynchronous operation supported */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t OldStatus, NewStatus;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync do
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync NewStatus = ATA_EVENT_STATUS_UNCHANGED;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (OldStatus)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_NEW:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* mount */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U16(abBuf + 0, 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[2] = 0x04; /* media */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[4] = 0x02; /* new medium */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[5] = 0x02; /* medium present / door closed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[6] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[7] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_CHANGED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_REMOVED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* umount */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U16(abBuf + 0, 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[2] = 0x04; /* media */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[4] = 0x03; /* media removal */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[5] = 0x00; /* medium absent / door closed */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[6] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[7] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (OldStatus == ATA_EVENT_STATUS_MEDIA_CHANGED)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_EJECT_REQUESTED: /* currently unused */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U16(abBuf + 0, 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[2] = 0x04; /* media */
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[6] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[7] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_UNCHANGED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U16(abBuf + 0, 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[2] = 0x01; /* operational change request / notification */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync abBuf[3] = 0x5e; /* supported = busy|media|external|power|operational */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[4] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[5] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[6] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[7] = 0x00;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&abBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(abBuf)));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiInquirySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[36];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[0] = 0x05; /* CD-ROM */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[1] = 0x80; /* removable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 0x00; /* ISO */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[4] = 31; /* additional length */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[7] = 0; /* reserved */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 8, pAhciPort->szInquiryVendorId, 8);
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 16, pAhciPort->szInquiryProductId, 16);
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync ataSCSIPadStr(aBuf + 32, pAhciPort->szInquiryRevision, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseErrorRecoverySS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[16];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[0], 16 + 6);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 0x70;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[4] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[7] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[8] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[9] = 0x06;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[10] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[11] = 0x05;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[12] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[13] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[14] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[15] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiModeSenseCDStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[40];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[0], 38);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 0x70;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[4] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[7] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[8] = 0x2a;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[9] = 30; /* page length */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[10] = 0x08; /* DVD-ROM read support */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[11] = 0x00; /* no write support */
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[14] |= 1 << 1; /* report lock state */
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[24] = 0; /* reserved */
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 aBuf[32] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[33] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[34] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[35] = 1; /* rotation control CAV */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[36], 0); /* current write speed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[38], 0); /* number of write speed performance descriptors */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiRequestSenseSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiMechanismStatusSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[8];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(&aBuf[0], 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* no current LBA */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[4] = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf + 6, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCNormalSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[20], *q, iStartTrack;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fMSF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSize;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iStartTrack = pAhciReq->aATAPICmd[6];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iStartTrack > 1 && iStartTrack != 0xaa)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q = aBuf + 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* first session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* last session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iStartTrack <= 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* ADR, control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fMSF)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(q, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(q, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* lead out track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* ADR, control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0xaa; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fMSF)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(q, pAhciPort->cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(q, pAhciPort->cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbSize = q - aBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf, cbSize - 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, cbSize));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCMultiSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[12];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fMSF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
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 memset(aBuf, 0, 12);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[1] = 0x0a;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[3] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[5] = 0x14; /* ADR, control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[6] = 1; /* first track in last complete session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fMSF)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[8] = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(&aBuf[9], 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf + 8, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, sizeof(aBuf)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadTOCRawSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[50]; /* Counted a maximum of 45 bytes but better be on the safe side. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *q, iStartTrack;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fMSF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSize;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync fMSF = (pAhciReq->aATAPICmd[1] >> 1) & 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iStartTrack = pAhciReq->aATAPICmd[6];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q = aBuf + 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* first session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* last session */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* session number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* data track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0xa0; /* first track in program area */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* first track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x00; /* disk type CD-DA or CD data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* session number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* data track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0xa1; /* last track in program area */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* last track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* session number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* data track */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0xa2; /* lead-out */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fMSF)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(q, pAhciPort->cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(q, pAhciPort->cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* session number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0x14; /* ADR, control */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* track number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 1; /* point */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* min */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* sec */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* frame */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fMSF)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *q++ = 0; /* reserved */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(q, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sector 0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(q, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync q += 4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbSize = q - aBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf, cbSize - 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, (void *)&aBuf[0],
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RT_MIN(cbData, cbSize));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync/**
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync * Sets the given media track type.
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsyncstatic uint32_t ataMediumTypeSet(PAHCIPort pAhciPort, uint32_t MediaTrackType)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync{
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync return ASMAtomicXchgU32(&pAhciPort->MediaTrackType, MediaTrackType);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync}
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiPassthroughSS(PAHCIREQ pAhciReq, PAHCIPort pAhciPort, size_t cbData, size_t *pcbData)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync int rc = VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abATAPISense[ATAPI_SENSE_SIZE];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pvBuf = NULL;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cbTransfer;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cbTransfer)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pvBuf = (uint8_t *)RTMemAlloc(cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!pvBuf)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VERR_NO_MEMORY;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciCopyFromPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf, cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VINF_SUCCESS;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Simple heuristics: if there is at least one sector of data
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * to transfer, it's worth updating the LEDs. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer >= 2048)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer > SCSI_MAX_BUFFER_SIZE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
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 uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t iATAPILBA, cSectors, cReqSectors, cbCurrTX;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBuf = (uint8_t *)pvBuf;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync switch (pAhciReq->aATAPICmd[0])
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_AND_VERIFY_10:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cSectors = ataBE2H_U16(pAhciReq->aATAPICmd + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_12:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cSectors = ataBE2H_U32(pAhciReq->aATAPICmd + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iATAPILBA = ataBE2H_U32(pAhciReq->aATAPICmd + 2);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cSectors = ataBE2H_U24(pAhciReq->aATAPICmd + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD_MSF:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync iATAPILBA = ataMSF2LBA(pAhciReq->aATAPICmd + 3);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cSectors = ataMSF2LBA(pAhciReq->aATAPICmd + 6) - iATAPILBA;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciReq->aATAPICmd[0]));
3689d0733b6efa19676293c493337c8b6948c8c8vboxsync if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
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 RTMemFree(pvBuf);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync memcpy(aATAPICmd, pAhciReq->aATAPICmd, ATAPI_PACKET_SIZE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cReqSectors = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (i * pAhciReq->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cReqSectors = i;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCurrTX = pAhciReq->cbATAPISector * cReqSectors;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync switch (pAhciReq->aATAPICmd[0])
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_AND_VERIFY_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U16(aATAPICmd + 7, cReqSectors);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U32(aATAPICmd + 6, cReqSectors);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
3689d0733b6efa19676293c493337c8b6948c8c8vboxsync ataH2BE_U24(aATAPICmd + 6, cReqSectors);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD_MSF:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync aATAPICmd,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir == AHCITXDIR_READ
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ? PDMBLOCKTXDIR_FROM_DEVICE
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync : PDMBLOCKTXDIR_TO_DEVICE,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pbBuf,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync &cbCurrTX,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync sizeof(abATAPISense),
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync 30000 /**< @todo timeout */);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (rc != VINF_SUCCESS)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA += cReqSectors;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbBuf += pAhciReq->cbATAPISector * cReqSectors;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PDMBLOCKTXDIR enmBlockTxDir = PDMBLOCKTXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_READ)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_TO_DEVICE;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir == AHCITXDIR_NONE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgFailed(("Invalid transfer direction %d\n", pAhciReq->enmTxDir));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->aATAPICmd,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pvBuf,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync &cbTransfer,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abATAPISense,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync sizeof(abATAPISense),
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync 30000 /**< @todo timeout */);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Update the LEDs and the read/write statistics. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer >= 2048)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir != AHCITXDIR_WRITE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Actual.s.fReading = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (RT_SUCCESS(rc))
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Assert(cbTransfer <= pAhciReq->cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_READ)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->aATAPICmd[0] == SCSI_INQUIRY)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
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 if (cbTransfer >= 8 + 8)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ataSCSIPadStr((uint8_t *)pvBuf + 8, "VBOX", 8);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cbTransfer >= 16 + 16)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ataSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cbTransfer >= 32 + 4)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ataSCSIPadStr((uint8_t *)pvBuf + 32, "1.0", 4);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->aATAPICmd[0] == SCSI_READ_TOC_PMA_ATIP)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync {
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /* Set the media type if we can detect it. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBuf = (uint8_t *)pvBuf;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /** @todo: Implemented only for formatted TOC now. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ( (pAhciReq->aATAPICmd[1] & 0xf) == 0
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync && cbTransfer >= 6)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync {
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync uint32_t NewMediaType;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync uint32_t OldMediaType;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync if (pbBuf[5] & 0x4)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync NewMediaType = ATA_MEDIA_TYPE_DATA;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync else
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync NewMediaType = ATA_MEDIA_TYPE_CDDA;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync OldMediaType = ataMediumTypeSet(pAhciPort, NewMediaType);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync if (OldMediaType != NewMediaType)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync LogRel(("AHCI: LUN#%d: CD-ROM passthrough, detected %s CD\n",
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync pAhciPort->iLUN,
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync NewMediaType == ATA_MEDIA_TYPE_DATA
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ? "data"
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync : "audio"));
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync }
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync else /* Play safe and set to unknown. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pvBuf));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Reply with the same amount of data as the real drive. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq, pvBuf,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbData = cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t u8Cmd = pAhciReq->aATAPICmd[0];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync do
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* don't log superfluous errors */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if ( rc == VERR_DEV_IO_ERROR
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync && ( u8Cmd == SCSI_TEST_UNIT_READY
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync || u8Cmd == SCSI_READ_CAPACITY
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync || u8Cmd == SCSI_READ_DVD_STRUCTURE
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cErrors++;
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);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdError(pAhciPort, pAhciReq, abATAPISense, sizeof(abATAPISense));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pvBuf)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTMemFree(pvBuf);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, size_t cbMax, ATAPIFN iSourceSink)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cbTransfered = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc, rcSourceSink;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciReq, pAhciPort, cbMax,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &cbTransfered);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdHdr.u32PRDBC = cbTransfered;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogFlow(("cbTransfered=%d\n", cbTransfered));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Write updated command header into memory of the guest. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &pAhciReq->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rcSourceSink;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadSectors2352PostProcess(PAHCIREQ pAhciReq, void **ppvProc, size_t *pcbProc)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBuf = NULL;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cSectors = pAhciReq->cbTransfer / 2048;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t iATAPILBA = pAhciReq->uOffset / 2048;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBufDst;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBufSrc = (uint8_t *)pAhciReq->u.Io.DataSeg.pvSeg;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbBuf = (uint8_t *)RTMemAlloc(pAhciReq->cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (RT_UNLIKELY(!pbBuf))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VERR_NO_MEMORY;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbBufDst = pbBuf;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync for (uint32_t i = iATAPILBA; i < iATAPILBA + cSectors; i++)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* sync bytes */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pbBufDst++ = 0x00;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync memset(pbBufDst, 0xff, 11);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pbBufDst += 11;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* MSF */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync ataLBA2MSF(pbBufDst, i);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pbBufDst += 3;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pbBufDst++ = 0x01; /* mode 1 data */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* data */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync memcpy(pbBufDst, pbBufSrc, 2048);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pbBufDst += 2048;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pbBufSrc += 2048;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* ECC */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync memset(pbBufDst, 0, 288);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pbBufDst += 288;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *ppvProc = pbBuf;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync *pcbProc = pAhciReq->cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync return VINF_SUCCESS;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync}
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int atapiReadSectors(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iATAPILBA));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (cbSector)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2048:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = (uint64_t)iATAPILBA * cbSector;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cSectors * cbSector;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2352:
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.pfnPostProcess = atapiReadSectors2352PostProcess;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = (uint64_t)iATAPILBA * 2048;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cSectors * 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Unsupported sectors size\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR rc = AHCITXDIR_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const uint8_t *pbPacket;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbMax;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbPacket = pAhciReq->aATAPICmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: ATAPI CMD=%#04x \"%s\"\n", __FUNCTION__, pbPacket[0], SCSICmdText(pbPacket[0])));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pbPacket[0])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_TEST_UNIT_READY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange-- > 2)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync case SCSI_GET_EVENT_STATUS_NOTIFICATION:
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODE_SENSE_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uPageControl, uPageCode;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uPageControl = pbPacket[2] >> 6;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uPageCode = pbPacket[2] & 0x3f;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (uPageControl)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PAGECONTROL_CURRENT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (uPageCode)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODEPAGE_ERROR_RECOVERY:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODEPAGE_CD_STATUS:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync goto error_cmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PAGECONTROL_CHANGEABLE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync goto error_cmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PAGECONTROL_DEFAULT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync goto error_cmd;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PAGECONTROL_SAVED:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_REQUEST_SENSE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = pbPacket[4];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_REQUEST_SENSE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pbPacket[4] & 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvMount->pfnLock(pAhciPort->pDrvMount);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvMount->pfnUnlock(pAhciPort->pDrvMount);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_12:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSectors, iATAPILBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pbPacket[0] == SCSI_READ_10)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSectors = ataBE2H_U16(pbPacket + 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSectors = ataBE2H_U32(pbPacket + 6);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cSectors == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Rate limited logging, one log line per second. For
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * guests that insist on reading from places outside the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * valid area this often generates too many release log
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * entries otherwise. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static uint64_t uLastLogTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uLastLogTS = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_CD:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSectors, iATAPILBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cSectors == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((uint64_t)iATAPILBA + cSectors > pAhciPort->cTotalSectors)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Rate limited logging, one log line per second. For
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * guests that insist on reading from places outside the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * valid area this often generates too many release log
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * entries otherwise. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static uint64_t uLastLogTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA + cSectors));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uLastLogTS = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pbPacket[9] & 0xf8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x00:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* nothing */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* normal read */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2048);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xf8:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* read all data */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiReadSectors(pAhciPort, pAhciReq, iATAPILBA, cSectors, 2352);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_SEEK_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iATAPILBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iATAPILBA > pAhciPort->cTotalSectors)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Rate limited logging, one log line per second. For
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * guests that insist on seeking to places outside the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * valid area this often generates too many release log
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * entries otherwise. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static uint64_t uLastLogTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", pAhciPort->iLUN, (uint64_t)iATAPILBA));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uLastLogTS = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus |= ATA_STAT_SEEK; /* Linux expects this. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_START_STOP_UNIT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync int rc2 = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pbPacket[4] & 3)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0: /* 00 - Stop motor */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 1: /* 01 - Start motor */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2: /* 10 - Eject media */
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* This must be done from EMT. */
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync
50f998bb47f333d10515d4c12ad01a4e92a0747bvboxsync rc2 = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
50f998bb47f333d10515d4c12ad01a4e92a0747bvboxsync (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 3,
50f998bb47f333d10515d4c12ad01a4e92a0747bvboxsync pAhciPort->pDrvMount, false/*=fForce*/, true/*=fEject*/);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync Assert(RT_SUCCESS(rc2) || (rc2 == VERR_PDM_MEDIA_LOCKED) || (rc2 = VERR_PDM_MEDIA_NOT_MOUNTED));
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync if (RT_SUCCESS(rc) && pAhci->pMediaNotify)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync rc2 = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync (PFNRT)pAhci->pMediaNotify->pfnEjected, 2,
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync pAhci->pMediaNotify, pAhciPort->iLUN);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 3: /* 11 - Load media */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (RT_SUCCESS(rc2))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdOK(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MECHANISM_STATUS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 8);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_MECHANISM_STATUS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_TOC_PMA_ATIP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t format;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the other field is clear... */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (format)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 1:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_MULTI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TOC_RAW);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync error_cmd:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_CAPACITY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, 8 /* cbMax */, ATAFN_SS_ATAPI_READ_CAPACITY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_DISC_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_TRACK_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_GET_CONFIGURATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No media change stuff here, it can confuse Linux guests. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_GET_CONFIGURATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_INQUIRY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = pbPacket[4];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbMax, ATAFN_SS_ATAPI_INQUIRY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiCmdErrorSimple(pAhciPort, pAhciReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return rc;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/*
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Parse ATAPI commands, passing them directly to the CD/DVD drive.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync const uint8_t *pbPacket;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cSectors, iATAPILBA;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cbTransfer = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR enmTxDir = AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbPacket = pAhciReq->aATAPICmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (pbPacket[0])
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_BLANK:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_CLOSE_TRACK_SESSION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_ERASE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d\n", iATAPILBA));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_FORMAT_UNIT:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_GET_CONFIGURATION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_GET_EVENT_STATUS_NOTIFICATION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (ASMAtomicReadU32(&pAhciPort->MediaEventStatus) != ATA_EVENT_STATUS_UNCHANGED)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = RT_MIN(cbTransfer, 8);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, pAhciReq->cbTransfer, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_GET_PERFORMANCE:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8); /* use ATAPI transfer length */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_INQUIRY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 3);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_LOAD_UNLOAD_MEDIUM:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_MECHANISM_STATUS:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_MODE_SELECT_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_MODE_SENSE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_PAUSE_RESUME:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_PLAY_AUDIO_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_PLAY_AUDIO_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_PLAY_AUDIO_MSF:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** @todo do not forget to unlock when a VM is shut down */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = cSectors * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U32(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = cSectors * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_BUFFER:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_BUFFER_CAPACITY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CAPACITY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = 8;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD:
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync {
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /* Get sector size based on the expected sector type field. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync switch ((pbPacket[1] >> 2) & 0x7)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync {
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x0: /* All types. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync if (ASMAtomicReadU32(&pAhciPort->MediaTrackType) == ATA_MEDIA_TYPE_CDDA)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2352;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /* Might be incorrect if we couldn't determine the type. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x1: /* CD-DA */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2352;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x2: /* Mode 1 */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x3: /* Mode 2 formless */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2336;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x4: /* Mode 2 form 1 */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync case 0x5: /* Mode 2 form 2 */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2324;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync break;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync default: /* Reserved */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync AssertMsgFailed(("Unknown sector type\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 0; /** @todo we should probably fail the command here already. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync }
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6) * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD_MSF:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cSectors > 32)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = cSectors * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_DISC_INFORMATION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_DVD_STRUCTURE:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_FORMAT_CAPACITIES:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_SUBCHANNEL:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_TOC_PMA_ATIP:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_TRACK_INFORMATION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REPAIR_TRACK:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REPORT_KEY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REQUEST_SENSE:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = pbPacket[4];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if ((pAhciPort->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = AHCITXDIR_READ;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_REQUEST_SENSE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_RESERVE_TRACK:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SCAN:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEEK_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEND_CUE_SHEET:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEND_DVD_STRUCTURE:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEND_EVENT:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEND_KEY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SEND_OPC_INFORMATION:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SET_CD_SPEED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SET_READ_AHEAD:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SET_STREAMING:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 9);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_START_STOP_UNIT:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_STOP_PLAY_SCAN:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_SYNCHRONIZE_CACHE:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_TEST_UNIT_READY:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_VERIFY_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = cSectors * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U32(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 2048; /**< @todo this size is not always correct */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = cSectors * pAhciReq->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_AND_VERIFY_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U16(pbPacket + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* The sector size is determined by the async I/O thread. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbATAPISector = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Preliminary, will be corrected once the sector size is known. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_BUFFER:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (pbPacket[1] & 0x1f)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x04: /* download microcode */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x05: /* download microcode and save */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x06: /* download microcode with offsets */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x07: /* download microcode with offsets and save */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x0e: /* download microcode with offsets and defer activation */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case 0x0f: /* activate deferred microcode */
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 break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U16(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_WRITE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U32(pbPacket + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_REZERO_UNIT:
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 break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
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 break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync sendcmd:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Send a command to the drive, passing data in/out as required. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("ATAPI PT: max size %d\n", cbTransfer));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer == 0)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_NONE;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = enmTxDir;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, cbTransfer, ATAFN_SS_ATAPI_PASSTHROUGH);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR enmTxDir = AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync const uint8_t *pbPacket;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbPacket = pAhciReq->aATAPICmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#ifdef DEBUG
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0], SCSICmdText(pbPacket[0])));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#else /* !DEBUG */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: LUN#%d CMD=%#04x\n", __FUNCTION__, pAhciPort->iLUN, pbPacket[0]));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#endif /* !DEBUG */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciReq->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciReq->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPIPassthrough)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciReq);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciReq);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset all values after a reset of the attached storage device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port the device is attached to.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The state to get the tag number from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc;
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Send a status good D2H FIS. */
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fResetDevice = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFirstD2HFisIntoMemory(pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* As this is the first D2H FIS after the reset update the signature in the SIG register of the port. */
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync if (pAhciPort->fATAPI)
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync else
4d4628e1fe67e333b01942cc6ac92818832fd0edvboxsync pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync rc = ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync/**
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * Initiates a device reset caused by ATA_DEVICE_RESET (ATAPI only).
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync *
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * @returns nothing.
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync * @param pAhciPort The device to reset.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The task state.
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciDeviceReset(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync{
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync ASMAtomicWriteBool(&pAhciPort->fResetDevice, true);
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync /*
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.
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync}
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Build a D2H FIS and post into the memory area of the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port of the SATA controller.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis, bool fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t d2hFis[20];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAssertIntr = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: building D2H Fis\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&d2hFis[0], 0, sizeof(d2hFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_TYPE] = AHCI_CMDFIS_TYPE_D2H;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_BITS] = (fInterrupt ? AHCI_CMDFIS_I : 0);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync d2hFis[AHCI_CMDFIS_STS] = pAhciReq->uATARegStatus;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync d2hFis[AHCI_CMDFIS_ERR] = pAhciReq->uATARegError;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Update registers. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->regTFD = (pAhciReq->uATARegError << 8) | pAhciReq->uATARegStatus;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->uATARegStatus & ATA_STAT_ERR)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Error bit is set. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAssertIntr = true;
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /*
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * Don't mark the command slot as completed because the guest
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync * needs it to identify the failed command.
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync else if (fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we should assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAssertIntr = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /* Mark command as completed. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fAssertIntr)
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync {
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Build a SDB Fis and post it into the memory area of the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsyncstatic void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t sdbFis[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAssertIntr = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regCMD & AHCI_PORT_CMD_FRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&sdbFis[0], 0, sizeof(sdbFis));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (RT_UNLIKELY(pTaskErr))
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] = pTaskErr->uATARegError;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Update registers. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync else
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] = 0;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fa65f915725c271afa39d64ce9de684549a4959avboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (RT_UNLIKELY(pTaskErr))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Error bit is set. */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_TFEE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAssertIntr = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_SDBS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we should assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAssertIntr = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, uFinishedTasks);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fAssertIntr)
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync {
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync int rc = ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN, VERR_IGNORED);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync AssertRC(rc);
fe869d55b000b5b3445dcf7077ac443434ff3ec3vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint32_t ahciGetNSectors(uint8_t *pCmdFis, bool fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pCmdFis[AHCI_CMDFIS_SECTC] && !pCmdFis[AHCI_CMDFIS_SECTCEXP])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 65536;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8 | pCmdFis[AHCI_CMDFIS_SECTC];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pCmdFis[AHCI_CMDFIS_SECTC])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 256;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_SECTC];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint64_t ahciGetSector(PAHCIPort pAhciPort, uint8_t *pCmdFis, bool fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t iLBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pCmdFis[AHCI_CMDFIS_HEAD] & 0x40)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* any LBA variant */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fLBA48)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* LBA48 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmdFis[AHCI_CMDFIS_SECTN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* LBA */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iLBA = ((pCmdFis[AHCI_CMDFIS_HEAD] & 0x0f) << 24) | (pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pCmdFis[AHCI_CMDFIS_CYLL] << 8) | pCmdFis[AHCI_CMDFIS_SECTN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* CHS */
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 +
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pCmdFis[AHCI_CMDFIS_SECTN] - 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return iLBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic uint64_t ahciGetSectorQueued(uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t uLBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uLBA = ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLHEXP] << 40) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLLEXP] << 32) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_SECTNEXP] << 24) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLH] << 16) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ((uint64_t)pCmdFis[AHCI_CMDFIS_CYLL] << 8) |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmdFis[AHCI_CMDFIS_SECTN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return uLBA;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint32_t) ahciGetNSectorsQueued(uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pCmdFis[AHCI_CMDFIS_FETEXP] && !pCmdFis[AHCI_CMDFIS_FET])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return 65536;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_FETEXP] << 8 | pCmdFis[AHCI_CMDFIS_FET];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(uint8_t) ahciGetTagQueued(uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return pCmdFis[AHCI_CMDFIS_SECTC] >> 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync/**
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * Allocates memory for the given request using already allocated memory if possible.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync *
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @returns Pointer to the memory or NULL on failure
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param pAhciReq The request to allocate memory for.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param cb The amount of memory to allocate.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsyncstatic void *ahciReqMemAlloc(PAHCIREQ pAhciReq, size_t cb)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync{
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync if (pAhciReq->cbAlloc > cb)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync {
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync pAhciReq->cAllocTooMuch++;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync }
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync else if (pAhciReq->cbAlloc < cb)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync {
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync if (pAhciReq->cbAlloc)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync RTMemPageFree(pAhciReq->pvAlloc, pAhciReq->cbAlloc);
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync
67bed6de126c5524d1970e0ec099531bd2bdee40vboxsync pAhciReq->cbAlloc = RT_ALIGN_Z(cb, _4K);
67bed6de126c5524d1970e0ec099531bd2bdee40vboxsync pAhciReq->pvAlloc = RTMemPageAlloc(pAhciReq->cbAlloc);
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync pAhciReq->cAllocTooMuch = 0;
67bed6de126c5524d1970e0ec099531bd2bdee40vboxsync if (RT_UNLIKELY(!pAhciReq->pvAlloc))
67bed6de126c5524d1970e0ec099531bd2bdee40vboxsync pAhciReq->cbAlloc = 0;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync }
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync return pAhciReq->pvAlloc;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync}
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync/**
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * Frees memory allocated for the given request.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync *
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @returns nothing.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync * @param pAhciReq The request.
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync */
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsyncstatic void ahciReqMemFree(PAHCIREQ pAhciReq)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync{
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync if (pAhciReq->cAllocTooMuch >= AHCI_MAX_ALLOC_TOO_MUCH)
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync {
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync RTMemPageFree(pAhciReq->pvAlloc, pAhciReq->cbAlloc);
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync pAhciReq->cbAlloc = 0;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync pAhciReq->cAllocTooMuch = 0;
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync }
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync}
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync/**
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Copies a data buffer into the S/G buffer set up by the guest.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync *
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.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyToPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pvBuf, size_t cbBuf)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBuf = (uint8_t *)pvBuf;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync SGLEntry aPrdtlEntries[32];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cbCopied = 0;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync do
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ? cPrdtlEntries
6308f6770d7f8fb842b437338e31554e913e6773vboxsync : RT_ELEMENTS(aPrdtlEntries);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into SG entry. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbBuf += cbThisCopy;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbBuf -= cbThisCopy;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied += cbThisCopy;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cPrdtlEntries -= cPrdtlEntriesRead;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } while (cPrdtlEntries && cbBuf);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cbCopied < cbBuf)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return cbCopied;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync}
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Copies the S/G buffer into a data buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic size_t ahciCopyFromPrdtl(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pvBuf, size_t cbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint8_t *pbBuf = (uint8_t *)pvBuf;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync SGLEntry aPrdtlEntries[32];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync unsigned cPrdtlEntries = pAhciReq->cPrdtlEntries;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cbCopied = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(cPrdtlEntries > 0, ("Copying 0 bytes is not possible\n"), 0);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ? cPrdtlEntries
6308f6770d7f8fb842b437338e31554e913e6773vboxsync : RT_ELEMENTS(aPrdtlEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; (i < cPrdtlEntriesRead) && cbBuf; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aPrdtlEntries[i].u32DBAUp, aPrdtlEntries[i].u32DBA);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cbThisCopy = (aPrdtlEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbThisCopy = RT_MIN(cbThisCopy, cbBuf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbBuf, cbThisCopy);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pbBuf += cbThisCopy;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbBuf -= cbThisCopy;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied += cbThisCopy;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cPrdtlEntries -= cPrdtlEntriesRead;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } while (cPrdtlEntries && cbBuf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (cbCopied < cbBuf)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return cbCopied;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync}
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Allocate I/O memory and copies the guest buffer for writes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The request state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param cbTransfer Amount of bytes to allocate.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int ahciIoBufAllocate(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq, size_t cbTransfer)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
6308f6770d7f8fb842b437338e31554e913e6773vboxsync || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ("Allocating I/O memory for a non I/O request is not allowed\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync pAhciReq->u.Io.DataSeg.pvSeg = ahciReqMemAlloc(pAhciReq, cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!pAhciReq->u.Io.DataSeg.pvSeg)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VERR_NO_MEMORY;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.cbSeg = cbTransfer;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciCopyFromPrdtl(pDevIns, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.pvSeg,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciIoBufFree(PPDMDEVINS pDevIns, PAHCIREQ pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync bool fCopyToGuest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg( pAhciReq->enmTxDir == AHCITXDIR_READ
6308f6770d7f8fb842b437338e31554e913e6773vboxsync || pAhciReq->enmTxDir == AHCITXDIR_WRITE,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ("Freeing I/O memory for a non I/O request is not allowed\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ( pAhciReq->enmTxDir == AHCITXDIR_READ
6308f6770d7f8fb842b437338e31554e913e6773vboxsync && fCopyToGuest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->u.Io.pfnPostProcess)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync void *pv = NULL;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cb = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync int rc = pAhciReq->u.Io.pfnPostProcess(pAhciReq, &pv, &cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (RT_SUCCESS(rc))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciCopyToPrdtl(pDevIns, pAhciReq, pv, cb);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTMemFree(pv);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciCopyToPrdtl(pDevIns, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.pvSeg,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.cbSeg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
a5d319fc6b17a28a8d6738e6f872d66244601cebvboxsync ahciReqMemFree(pAhciReq);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.pvSeg = NULL;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.cbSeg = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync/**
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Cancels all active tasks on the port.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync *
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * @returns Whether all active tasks were canceled.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * @param pAhciPort The ahci port.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsyncstatic bool ahciCancelActiveTasks(PAHCIPort pAhciPort)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync{
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aCachedTasks); i++)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pAhciReq = pAhciPort->aCachedTasks[i];
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (VALID_PTR(pAhciReq))
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fXchg = false;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE, fXchg);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (fXchg)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Task is active and was canceled. */
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("Task was canceled but none is active\n"));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ASMAtomicDecU32(&pAhciPort->cTasksActive);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /*
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * Clear the pointer in the cached array. The controller will allocate a
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync * a new task structure for this tag.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ASMAtomicWriteNullPtr(&pAhciPort->aCachedTasks[i]);
896847542dfe233aafd200cf6a7793216c01613fvboxsync LogRel(("AHCI#%dP%d: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->iLUN, pAhciReq->uTag));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_FREE,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ("Invalid task state, must be free!\n"));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertRelease(!ASMAtomicReadU32(&pAhciPort->cTasksActive));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync return true; /* always true for now because tasks don't use guest memory as the buffer which makes canceling a task impossible. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync}
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* -=-=-=-=- IBlockAsyncPort -=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Makes a PAHCIPort out of a PPDMIBLOCKASYNCPORT. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncstatic void ahciWarningDiskFull(PPDMDEVINS pDevIns)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync{
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync int rc;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync LogRel(("AHCI: Host disk full\n"));
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"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync AssertRC(rc);
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync}
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncstatic void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync{
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync int rc;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync LogRel(("AHCI: File too big\n"));
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 AssertRC(rc);
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync}
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncstatic void ahciWarningISCSI(PPDMDEVINS pDevIns)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync{
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync int rc;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync LogRel(("AHCI: iSCSI target unavailable\n"));
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"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync AssertRC(rc);
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync}
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsyncbool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync{
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (rc == VERR_DISK_FULL)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (rc == VERR_FILE_TOO_BIG)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
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 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return true;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync return false;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync}
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync/**
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * Creates the array of ranges to trim.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync *
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * @returns VBox status code.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciPort AHCI port state.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The request handling the TRIM request.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int ahciTrimRangesCreate(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync SGLEntry aPrdtlEntries[32];
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync uint64_t aRanges[64];
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync unsigned cRangesMax;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync unsigned cRanges = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntries = pAhciReq->cPrdtlEntries;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync int rc = VINF_SUCCESS;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync LogFlowFunc(("pAhciPort=%#p pAhciReq=%#p\n", pAhciPort, pAhciReq));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsgReturn(pAhciReq->enmTxDir == AHCITXDIR_TRIM, ("This is not a trim request\n"), VERR_INVALID_PARAMETER);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
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 = 65536 * 512 / 8;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cRangesMax = pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] * 512 / 8;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!cPrdtlEntries)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VINF_SUCCESS;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync do
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ? cPrdtlEntries
6308f6770d7f8fb842b437338e31554e913e6773vboxsync : RT_ELEMENTS(aPrdtlEntries);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
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
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned idxRange = 0; idxRange < RT_ELEMENTS(aRanges); idxRange++)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync aRanges[idxRange] = RT_H2LE_U64(aRanges[idxRange]);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (AHCI_RANGE_LENGTH_GET(aRanges[idxRange]) != 0)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cRanges++;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cPrdtlEntries -= cPrdtlEntriesRead;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync } while (cPrdtlEntries);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (RT_UNLIKELY(!cRanges))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync return VERR_BUFFER_OVERFLOW;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.cRanges = cRanges;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->u.Trim.paRanges)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync uint32_t idxRange = 0;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cPrdtlEntries = pAhciReq->cPrdtlEntries;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync /* Convert the ranges from the guest to our format. */
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync do
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint32_t cPrdtlEntriesRead = (cPrdtlEntries < RT_ELEMENTS(aPrdtlEntries))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ? cPrdtlEntries
6308f6770d7f8fb842b437338e31554e913e6773vboxsync : RT_ELEMENTS(aPrdtlEntries);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPrdtl, &aPrdtlEntries[0], cPrdtlEntriesRead * sizeof(SGLEntry));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (uint32_t i = 0; i < cPrdtlEntriesRead; i++)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
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
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbThisCopy = RT_MIN(cbThisCopy, sizeof(aRanges));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy into buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, aRanges, cbThisCopy);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned idxRangeSrc = 0; idxRangeSrc < RT_ELEMENTS(aRanges); idxRangeSrc++)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync aRanges[idxRangeSrc] = RT_H2LE_U64(aRanges[idxRangeSrc]);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) != 0)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.paRanges[idxRange].offStart = (aRanges[idxRangeSrc] & AHCI_RANGE_LBA_MASK) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.paRanges[idxRange].cbRange = AHCI_RANGE_LENGTH_GET(aRanges[idxRangeSrc]) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync idxRange++;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync break;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += cPrdtlEntriesRead * sizeof(SGLEntry);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cPrdtlEntries -= cPrdtlEntriesRead;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync } while (idxRange < cRanges);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = VERR_NO_MEMORY;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync LogFlowFunc(("returns rc=%Rrc\n", rc));
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync return rc;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync}
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync/**
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * Destroy the trim range list.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync *
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync * @returns nothing.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The task state.
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciTrimRangesDestroy(PAHCIREQ pAhciReq)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync{
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertReturnVoid(pAhciReq->enmTxDir == AHCITXDIR_TRIM);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTMemFree(pAhciReq->u.Trim.paRanges);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync}
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Complete a data transfer task by freeing all occupied resources
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and notifying the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq, bool fFreeReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fXchg = false;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync bool fRedo = false;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (fXchg)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_READ)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, true /* fCopyToGuest */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciReq->cbTransfer);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->Led.Actual.s.fReading = 0;
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir == AHCITXDIR_WRITE)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, false /* fCopyToGuest */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciReq->cbTransfer);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciTrimRangesDestroy(pAhciReq);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (RT_FAILURE(rcReq))
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Log the error. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->iLUN, rcReq));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync LogRel(("AHCI#%u: Trim returned rc=%Rrc\n",
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync pAhciPort->iLUN, rcReq));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->iLUN,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir == AHCITXDIR_READ
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ? "Read"
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync : "Write",
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer, rcReq));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (!fRedo)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdHdr.u32PRDBC = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ID_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciReq, NULL);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksNew, RT_BIT_32(pAhciReq->uTag));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Status will be set by already for non I/O requests. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir != AHCITXDIR_NONE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Write updated command header into memory of the guest. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &pAhciReq->cmdHdr, sizeof(CmdHdr));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->fFlags & AHCI_REQ_OVERFLOW)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /*
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * The guest tried to transfer more data than there is space in the buffer.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * Terminate task and set the overflow bit.
6308f6770d7f8fb842b437338e31554e913e6773vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Notify the guest. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_OFS);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_OFE)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("Inconsistent request counter\n"));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ASMAtomicDecU32(&pAhciPort->cTasksActive);
b28326220af580dde4a61f15930f51fe584dc896vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (!fRedo)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->fQueued)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIREQ))
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, RT_BIT_32(pAhciReq->uTag));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /*
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})
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ahciSendSDBFis(pAhciPort, 0, true);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
b28326220af580dde4a61f15930f51fe584dc896vboxsync {
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /*
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.
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq->enmTxState == AHCITXSTATE_CANCELED,
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ("Task is not active but wasn't canceled!\n"));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_TRIM)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciTrimRangesDestroy(pAhciReq);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else if (pAhciReq->enmTxDir != AHCITXDIR_FLUSH)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciIoBufFree(pAhciPort->pDevInsR3, pAhciReq, false /* fCopyToGuest */);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Leave a log message about the canceled request. */
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->enmTxDir == AHCITXDIR_FLUSH)
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync LogRel(("AHCI#%u: Canceled flush returned rc=%Rrc\n",
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->iLUN, rcReq));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync else
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync LogRel(("AHCI#%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync pAhciPort->iLUN,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir == AHCITXDIR_READ
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync ? "read"
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync : "write",
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer, rcReq));
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync }
b28326220af580dde4a61f15930f51fe584dc896vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync /* Finally free the task state structure because it is completely unused now. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (fFreeReq)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTMemFree(pAhciReq);
b28326220af580dde4a61f15930f51fe584dc896vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Notification callback for a completed transfer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
f687f34bd232be13744edbc0cc5155fa5d4540edvboxsyncstatic DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pAhciReq = (PAHCIREQ)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
6308f6770d7f8fb842b437338e31554e913e6773vboxsync __FUNCTION__, pInterface, pvUser, pAhciReq->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync int rc = ahciTransferComplete(pAhciPort, pAhciReq, rcReq, true);
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
9083f76e8c5709604766d0215a380de516e781eevboxsync PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Process an non read/write ATA command.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns The direction of the data transfer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCmdHdr Pointer to the command header.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR rc = AHCITXDIR_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fLBA48 = false;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync CmdHdr *pCmdHdr = &pAhciReq->cmdHdr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmdFis[AHCI_CMDFIS_CMD])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDENTIFY_DEVICE:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync int rc2;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uint16_t u16Temp[256];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cbCopied;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Fill the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciIdentifySS(pAhciPort, u16Temp);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync /* Copy the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &u16Temp[0], sizeof(u16Temp));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cbCopied;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync break;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_NATIVE_MAX_ADDRESS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SET_FEATURES:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmdFis[AHCI_CMDFIS_FET])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x02: /* write cache enable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xaa: /* read look-ahead enable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x55: /* read look-ahead disable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xcc: /* reverting to power-on defaults enable */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x66: /* reverting to power-on defaults disable */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x82: /* write cache disable */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_FLUSH;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x03:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync { /* set transfer mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: transfer mode %#04x\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x00: /* PIO default */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x08: /* PIO mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_MODE_MDMA: /* MDMA mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_MDMA_MODE_MAX);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_MODE_UDMA: /* UDMA mode */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = (pCmdFis[AHCI_CMDFIS_SECTC] & 0xf8) | RT_MIN(pCmdFis[AHCI_CMDFIS_SECTC] & 0x07, ATA_UDMA_MODE_MAX);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync case ATA_DEVICE_RESET:
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync {
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync if (!pAhciPort->fATAPI)
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync }
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync else
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync {
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync /* Reset the device. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciDeviceReset(pAhciPort, pAhciReq);
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync }
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync break;
9d8f91b1f808d2e9d0594c41b6d89e18e05ecdcevboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_FLUSH_CACHE_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_FLUSH_CACHE:
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_FLUSH;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_PACKET:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = atapiParseCmd(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDENTIFY_PACKET_DEVICE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync atapiDoTransfer(pAhciPort, pAhciReq, 512, ATAFN_SS_ATAPI_IDENTIFY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SET_MULTIPLE_MODE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pCmdFis[AHCI_CMDFIS_SECTC] != 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && ( pCmdFis[AHCI_CMDFIS_SECTC] > ATA_MAX_MULT_SECTORS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || (pCmdFis[AHCI_CMDFIS_SECTC] & (pCmdFis[AHCI_CMDFIS_SECTC] - 1)) != 0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("%s: set multi sector count to %d\n", __FUNCTION__, pCmdFis[AHCI_CMDFIS_SECTC]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cMultSectors = pCmdFis[AHCI_CMDFIS_SECTC];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_STANDBY_IMMEDIATE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break; /* Do nothing. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_CHECK_POWER_MODE:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cmdFis[AHCI_CMDFIS_SECTC] = 0xff; /* drive active or idle */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fall through */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_INITIALIZE_DEVICE_PARAMETERS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDLE_IMMEDIATE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_RECALIBRATE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_NOP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_VERIFY_SECTORS_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_VERIFY_SECTORS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
fe9231c2cb1abca4d3a9390aa532e70d13f8e0c4vboxsync case ATA_SLEEP:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_DMA_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fLBA48 = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_DMA:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_WRITE_DMA_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fLBA48 = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_WRITE_DMA:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_WRITE_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync case ATA_READ_LOG_EXT:
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
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 unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
6308f6770d7f8fb842b437338e31554e913e6773vboxsync size_t cbCopied;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync uint8_t aBuf[512];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync memset(aBuf, 0, sizeof(aBuf));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (offLogRead + cbLogRead <= sizeof(aBuf))
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync switch (iPage)
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync case 0x10:
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync LogFlow(("Reading error page\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIREQ);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (pTaskErr)
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
b5b1f66b859b5af33a7fe5f121d664d0cd56dd1bvboxsync aBuf[0] = pTaskErr->fQueued ? pTaskErr->uTag : (1 << 7);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[2] = pTaskErr->uATARegStatus;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[3] = pTaskErr->uATARegError;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Calculate checksum */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync uint8_t uChkSum = 0;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync uChkSum += aBuf[i];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync aBuf[511] = (uint8_t)-(int8_t)uChkSum;
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync /*
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync * Reading this log page results in an abort of all outstanding commands
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync * and clearing the SActive register and TaskFile register.
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync */
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync ahciSendSDBFis(pAhciPort, 0xffffffff, true);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync break;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Copy the buffer. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbCopied = ahciCopyToPrdtl(pAhciPort->pDevInsR3, pAhciReq,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &aBuf[offLogRead], cbLogRead);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = cbCopied;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync break;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync case ATA_DATA_SET_MANAGEMENT:
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ( ( !pAhciPort->fAsyncInterface
6308f6770d7f8fb842b437338e31554e913e6773vboxsync && pAhciPort->pDrvBlock->pfnDiscard)
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync || ( pAhciPort->fAsyncInterface
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
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 {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = AHCITXDIR_TRIM;
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync break;
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync }
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync /* else: fall through and report error to the guest. */
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* All not implemented commands go below. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SECURITY_FREEZE_LOCK:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SMART:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_NV_CACHE:
595985b5ba8b80bfcd0da89e0a359e782b480ee7vboxsync case ATA_IDLE:
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default: /* For debugging purposes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Unknown command issued\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = ABRT_ERR;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Retrieve a command FIS from guest memory.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
6308f6770d7f8fb842b437338e31554e913e6773vboxsync * @param pAhciReq The state of the actual task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsyncstatic void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIREQ pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrCmdTbl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pAhciPort->GCPhysAddrClb && pAhciPort->GCPhysAddrFb, ("%s: GCPhysAddrClb and/or GCPhysAddrFb are 0\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciReq->uTag * sizeof(CmdHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciReq->GCPhysCmdHdrAddr, &pAhciReq->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the command header. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciDumpCmdHdrInfo(pAhciPort, &pAhciReq->cmdHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciReq->cmdHdr.u32CmdTblAddrUp, pAhciReq->cmdHdr.u32CmdTblAddr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_CFL_MASK) * sizeof(uint32_t) == AHCI_CMDFIS_TYPE_H2D_SIZE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ("This is not a command FIS!!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set transfer direction. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If this is an ATAPI command read the atapi command. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciReq->aATAPICmd[0], ATAPI_PACKET_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We "received" the FIS. Clear the BSY bit in regTFD. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ((pAhciReq->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciReq->fQueued))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the FIS. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciDumpFisInfo(pAhciPort, &pAhciReq->cmdFis[0]);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync /* Print the PRDT */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("PRDT address %RGp number of entries %u\n", pAhciReq->GCPhysPrdtl, pAhciReq->cPrdtlEntries));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTGCPHYS GCPhysPrdtl = pAhciReq->GCPhysPrdtl;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync for (unsigned i = 0; i < pAhciReq->cPrdtlEntries; i++)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync SGLEntry SGEntry;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("Entry %u at address %RGp\n", i, GCPhysPrdtl));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysPrdtl, &SGEntry, sizeof(SGLEntry));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync RTGCPHYS GCPhysDataAddr = AHCI_RTGCPHYS_FROM_U32(SGEntry.u32DBAUp, SGEntry.u32DBA);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ahciLog(("GCPhysAddr=%RGp Size=%u\n", GCPhysDataAddr, SGEntry.u32DescInf & SGLENTRY_DESCINF_DBC));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync GCPhysPrdtl += sizeof(SGLEntry);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Transmit queue consumer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Queue a new async task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(bool) ahciNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDEVPORTNOTIFIERQUEUEITEM pNotifierItem = (PDEVPORTNOTIFIERQUEUEITEM)pItem;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[pNotifierItem->iPort];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fAsyncInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Got notification from GC\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Notify the async IO thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventSignal(pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync unsigned idx = 0;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint32_t u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx = ASMBitFirstSetU32(u32Tasks);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync while (idx)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AHCITXDIR enmTxDir;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pAhciReq;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Decrement to get the slot number. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx--;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /*
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Check if there is already an allocated task struct in the cache.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Allocate a new task otherwise.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (!pAhciPort->aCachedTasks[idx])
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxState = AHCITXSTATE_FREE;
585b7e94d7ac014b1d59f95ccff3f84cc2d9082bvboxsync pAhciPort->aCachedTasks[idx] = pAhciReq;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq = pAhciPort->aCachedTasks[idx];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync bool fXchg;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE, fXchg);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(fXchg, ("Task is already active\n"));
b28326220af580dde4a61f15930f51fe584dc896vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fFlags = 0;
595985b5ba8b80bfcd0da89e0a359e782b480ee7vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Set current command slot */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uTag = idx;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhciPort->regSACT & (1 << idx))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fQueued = true;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fQueued = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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 {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->fResetDevice = true;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(fXchg, ("Task is not active\n"));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync return true;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(fXchg, ("Task is not active\n"));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync return true;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else /* We are not in a reset state update the control registers. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("There are more than 32 requests active"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicIncU32(&pAhciPort->cTasksActive);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (enmTxDir != AHCITXDIR_NONE)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if ( enmTxDir != AHCITXDIR_FLUSH
6308f6770d7f8fb842b437338e31554e913e6773vboxsync && enmTxDir != AHCITXDIR_TRIM)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciIoBufAllocate(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->cbTransfer);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (RT_FAILURE(rc))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync if (enmTxDir == AHCITXDIR_FLUSH)
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq);
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync }
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync else if (enmTxDir == AHCITXDIR_TRIM)
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync if (RT_SUCCESS(rc))
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.cRanges, pAhciReq);
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync }
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync }
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync else if (enmTxDir == AHCITXDIR_READ)
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &pAhciReq->u.Io.DataSeg, 1,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq);
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync }
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync else
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync {
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync &pAhciReq->u.Io.DataSeg, 1,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync if (rc == VINF_VD_ASYNC_IO_FINISHED)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);
f4aad55f8addd816ef005845842a2418bbdc3ea2vboxsync }
595985b5ba8b80bfcd0da89e0a359e782b480ee7vboxsync }
595985b5ba8b80bfcd0da89e0a359e782b480ee7vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* Command */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx = ASMBitFirstSetU32(u32Tasks);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* while tasks available */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* fUseAsyncInterface */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* The async IO thread for one port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciAsyncIOLoop(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync PAHCIREQ pAhciReq;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t u64StartTime = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t u64StopTime = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uIORequestsProcessed = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uIOsPerSec = 0;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync uint32_t fTasksToProcess = 0;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync unsigned idx = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We use only one task structure. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!pAhciReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Failed to allocate task state memory\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxState = AHCITXSTATE_FREE;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
fa65f915725c271afa39d64ce9de684549a4959avboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* New run to get number of I/O requests per second?. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (!u64StartTime)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync u64StartTime = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhci->fSignalIdle)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (rc == VERR_TIMEOUT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* No I/O requests in-between. Reset statistics and wait again. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->StatIORequestsPerSecond.c = 0;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Go to sleep again if we are in redo mode. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (RT_UNLIKELY(pAhciPort->fRedo))
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync continue;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fTasksToProcess = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx = ASMBitFirstSetU32(fTasksToProcess);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Process commands. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync while ( idx
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && RT_LIKELY(!pAhciPort->fPortReset))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx--;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegStatus = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uATARegError = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fFlags = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uTag = idx;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(pAhciReq->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number %u!!\n", __FUNCTION__, pAhciReq->uTag));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync bool fXchg;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE, fXchg);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(fXchg, ("Task is already active\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync /* Set current command slot */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* 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. */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhciPort->regSACT & (1 << idx))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fQueued = true;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->fQueued = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciPortTaskGetCommandFis(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciReq->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If the reset bit is set put the device into reset state. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fResetDevice = true;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciSendD2HFis(pAhciPort, pAhciReq, &pAhciReq->cmdFis[0], true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* TODO: We are not in a reset state update the control registers. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicCmpXchgSize(&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(fXchg, ("Task is already free\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync ("There are more than 32 requests active"));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ASMAtomicIncU32(&pAhciPort->cTasksActive);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, &pAhciReq->cmdFis[0]);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->enmTxDir = enmTxDir;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir == AHCITXDIR_FLUSH)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync else if (enmTxDir == AHCITXDIR_TRIM)
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync if (RT_SUCCESS(rc))
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync {
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
af994abc6cd33a5038cfbc3974fb05a8eca41165vboxsync rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.paRanges,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Trim.cRanges);
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
e2ebb3d022edb845fd1158d6338e3def1d0e2159vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else if (enmTxDir != AHCITXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync uint64_t uOffset = 0;
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync size_t cbTransfer = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = ahciIoBufAllocate(pAhciPort->pDevInsR3, pAhciReq, pAhciReq->cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync /* Initialize all values. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uOffset = pAhciReq->uOffset;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer = pAhciReq->cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, b);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync AssertMsg(!(cbTransfer % 512), ("Number of bytes to process is not sector aligned %lu\n", cbTransfer));
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync if (enmTxDir == AHCITXDIR_READ)
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.pvSeg,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->Led.Actual.s.fReading = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbTransfer);
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync else
5b3f6f947bae7a25e7434b173114ecd113784532vboxsync {
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->u.Io.DataSeg.pvSeg,
6308f6770d7f8fb842b437338e31554e913e6773vboxsync cbTransfer);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbTransfer);
fa65f915725c271afa39d64ce9de684549a4959avboxsync }
6308f6770d7f8fb842b437338e31554e913e6773vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, b);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync ahciTransferComplete(pAhciPort, pAhciReq, rc, false /* fFreeReq */);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync uIORequestsProcessed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fa65f915725c271afa39d64ce9de684549a4959avboxsync if (!pAhciPort->fRedo)
fa65f915725c271afa39d64ce9de684549a4959avboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
fa65f915725c271afa39d64ce9de684549a4959avboxsync /* Be paranoid. */
6308f6770d7f8fb842b437338e31554e913e6773vboxsync memset(&pAhciReq->cmdHdr, 0, sizeof(CmdHdr));
6308f6770d7f8fb842b437338e31554e913e6773vboxsync memset(&pAhciReq->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->GCPhysCmdHdrAddr = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->uOffset = 0;
6308f6770d7f8fb842b437338e31554e913e6773vboxsync pAhciReq->cbTransfer = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fTasksToProcess &= ~(1 << idx);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync idx = ASMBitFirstSetU32(fTasksToProcess);
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync } /* while tasks to process */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u64StopTime = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if one second has passed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u64StopTime - u64StartTime >= 1000)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Calculate number of I/O requests per second. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uIOsPerSec = uIORequestsProcessed / ((u64StopTime - u64StartTime) / 1000);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Processed %u requests in %llu ms -> %u requests/s\n", __FUNCTION__, uIORequestsProcessed, u64StopTime - u64StartTime, uIOsPerSec));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u64StartTime = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uIORequestsProcessed = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* For the release statistics. There is no macro to set the counter to a specific value. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->StatIORequestsPerSecond.c = uIOsPerSec;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync } /* While running */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync if (pAhci->fSignalIdle)
9083f76e8c5709604766d0215a380de516e781eevboxsync PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync
6308f6770d7f8fb842b437338e31554e913e6773vboxsync RTMemFree(pAhciReq);
6308f6770d7f8fb842b437338e31554e913e6773vboxsync memset(pAhciPort->aCachedTasks, 0, sizeof(pAhciPort->aCachedTasks));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
fa65f915725c271afa39d64ce9de684549a4959avboxsync ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
fa65f915725c271afa39d64ce9de684549a4959avboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Unblock the async I/O thread so it can respond to a state change.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The pcnet device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThread The send thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciAsyncIOLoopWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = (PAHCIPort)pThread->pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return RTSemEventSignal(pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync/* -=-=-=-=- DBGF -=-=-=-=- */
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync/**
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync * AHCI status info callback.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync *
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pDevIns The device instance.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pHlp The output helpers.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * @param pszArgs The arguments.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync */
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsyncstatic DECLCALLBACK(void) ahciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync{
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync /*
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Show info.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync */
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync "%s#%d: mmio=%RGp ports=%u GC=%RTbool R0=%RTbool\n",
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pDevIns->pReg->szName,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pDevIns->iInstance,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pThis->MMIOBase,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pThis->cPortsImpl,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pThis->fGCEnabled ? true : false,
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pThis->fR0Enabled ? true : false);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync /*
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Show global registers.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync */
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
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync /*
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Per port data.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync */
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync for (unsigned i = 0; i < pThis->cPortsImpl; i++)
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync {
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync PAHCIPort pThisPort = &pThis->ahciPort[i];
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
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);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortAsyncIoThreadIdle=%RTbool\n", pThisPort->fAsyncIOThreadIdle);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "\n");
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync }
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync}
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- Helper -=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync/**
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync * Checks if all asynchronous I/O is finished, both AHCI and IDE.
9083f76e8c5709604766d0215a380de516e781eevboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * use of it in strict builds (which is why it's up here).
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
9083f76e8c5709604766d0215a380de516e781eevboxsync * @returns true if quiesced, false if busy.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance.
9083f76e8c5709604766d0215a380de516e781eevboxsync */
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic bool ahciR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9083f76e8c5709604766d0215a380de516e781eevboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pThis->ahciPort); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9083f76e8c5709604766d0215a380de516e781eevboxsync PAHCIPort pThisPort = &pThis->ahciPort[i];
9083f76e8c5709604766d0215a380de516e781eevboxsync if (pThisPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9083f76e8c5709604766d0215a380de516e781eevboxsync bool fFinished;
9083f76e8c5709604766d0215a380de516e781eevboxsync if (pThisPort->fAsyncInterface)
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fFinished = (pThisPort->cTasksActive == 0);
9083f76e8c5709604766d0215a380de516e781eevboxsync else
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync fFinished = ((pThisPort->cTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
9083f76e8c5709604766d0215a380de516e781eevboxsync if (!fFinished)
9083f76e8c5709604766d0215a380de516e781eevboxsync return false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9083f76e8c5709604766d0215a380de516e781eevboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- Saved State -=-=-=-=- */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @copydoc FNDEVSSMSAVEPREP
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9083f76e8c5709604766d0215a380de516e781eevboxsync Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @copydoc FNDEVSSMLOADPREP
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync Assert(ahciR3AllAsyncIOIsFinished(pDevIns));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * @copydoc FNDEVSSMLIVEEXEC
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* config. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->cPortsImpl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].pDrvBase != NULL);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szSerialNumber);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szFirmwareRevision);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutStrZ(pSSM, pThis->ahciPort[i].szModelNumber);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync uint32_t iPort;
928e1d6581a40f26932a8b35526773805bc69e47vboxsync int rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, iPort);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync return VINF_SSM_DONT_CALL_AGAIN;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync}
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/**
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync * @copydoc FNDEVSSMSAVEEXEC
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync{
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t i;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync Assert(!pThis->f8ByteMMIO4BytesWrittenSuccessfully);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The config */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The main device structure. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaCap);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaCtrl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaIs);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaPi);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaVs);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaCccCtl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->regHbaCccPorts);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU8(pSSM, pThis->uCccPortNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU64(pSSM, pThis->uCccTimeout);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->uCccNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->uCccCurrentNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->u32PortsInterrupted);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->fReset);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->f64BitAddr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->fR0Enabled);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->fGCEnabled);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync Assert(pThis->ahciPort[i].cTasksActive == 0);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regFB);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regFBU);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrClb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutGCPhys(pSSM, pThis->ahciPort[i].GCPhysAddrFb);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regIS);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regIE);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regCMD);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regTFD);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regSIG);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regSSTS);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regSCTL);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regSERR);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regSACT);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].regCI);
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 SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32TasksFinished);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32QueuedTasksFinished);
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync SSMR3PutU32(pSSM, pThis->ahciPort[i].u32CurrentCommandSlot);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync /* ATAPI saved state. */
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3PutBool(pSSM, pThis->ahciPort[i].fATAPI);
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync/**
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * Loads a saved legacy ATA emulated device state.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync *
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * @returns VBox status code.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync * @param pSSM The handle to the saved state.
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsyncint ahciR3LoadLegacyEmulationState(PSSMHANDLE pSSM)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync{
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync int rc;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync uint32_t u32Version;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync uint32_t u32;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync uint32_t u32IOBuffer;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Test for correct version. */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync rc = SSMR3GetU32(pSSM, &u32Version);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync AssertRCReturn(rc, rc);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync LogFlow(("LoadOldSavedStates u32Version = %d\n", u32Version));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32Version != ATA_CTL_SAVED_STATE_VERSION
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync && u32Version != ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync AssertMsgFailed(("u32Version=%d\n", u32Version));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 19 + 5 * sizeof(bool) + sizeof(BMDMAState));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync for (uint32_t j = 0; j < 2; j++)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 88 + 5 * sizeof(bool) );
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 64);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync else
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 2);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync /** @todo triple-check this hack after passthrough is working */
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 1);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32Version > ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, 4);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3Skip(pSSM, sizeof(PDMLED));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync SSMR3GetU32(pSSM, &u32IOBuffer);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32IOBuffer)
785120c56386c7584da3b8e8dd67a3038791db5avboxsync SSMR3Skip(pSSM, u32IOBuffer);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync rc = SSMR3GetU32(pSSM, &u32);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (RT_FAILURE(rc))
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync return rc;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (u32 != ~0U)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync AssertMsgFailed(("u32=%#x expected ~0\n", u32));
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync return rc;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync return VINF_SUCCESS;
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync}
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Loads a saved AHCI device state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d00ac6bac8066f17185a6319257f617ecd021b4bvboxsync if ( uVersion > AHCI_SAVED_STATE_VERSION
d00ac6bac8066f17185a6319257f617ecd021b4bvboxsync || uVersion < AHCI_SAVED_STATE_VERSION_VBOX_30)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Verify config. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (uVersion > AHCI_SAVED_STATE_VERSION_VBOX_30)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetU32(pSSM, &u32);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (u32 != pThis->cPortsImpl)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync LogRel(("AHCI: Config mismatch: cPortsImpl - saved=%u config=%u\n", u32, pThis->cPortsImpl));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if ( u32 < pThis->cPortsImpl
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync || u32 > AHCI_MAX_NR_PORTS_IMPL)
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: cPortsImpl - saved=%u config=%u"),
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync u32, pThis->cPortsImpl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync bool fInUse;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetBool(pSSM, &fInUse);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (fInUse != (pThis->ahciPort[i].pDrvBase != NULL))
e8ad3d010ce14b8afa8d2b5ecc59c4e89c16fe7avboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS,
e8ad3d010ce14b8afa8d2b5ecc59c4e89c16fe7avboxsync N_("The %s VM is missing a device on port %u. Please make sure the source and target VMs have compatible storage configurations"),
e8ad3d010ce14b8afa8d2b5ecc59c4e89c16fe7avboxsync fInUse ? "target" : "source", i );
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync char szSerialNumber[AHCI_SERIAL_NUMBER_LENGTH+1];
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szSerialNumber, sizeof(szSerialNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync char szFirmwareRevision[AHCI_FIRMWARE_REVISION_LENGTH+1];
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szFirmwareRevision, sizeof(szFirmwareRevision));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync char szModelNumber[AHCI_MODEL_NUMBER_LENGTH+1];
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetStrZ(pSSM, szModelNumber, sizeof(szModelNumber));
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
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 }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync static const char *s_apszIdeEmuPortNames[4] = { "PrimaryMaster", "PrimarySlave", "SecondaryMaster", "SecondarySlave" };
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (size_t i = 0; i < RT_ELEMENTS(s_apszIdeEmuPortNames); i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync uint32_t iPort;
928e1d6581a40f26932a8b35526773805bc69e47vboxsync rc = CFGMR3QueryU32Def(pDevIns->pCfg, s_apszIdeEmuPortNames[i], &iPort, i);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync uint32_t iPortSaved;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetU32(pSSM, &iPortSaved);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync AssertRCReturn(rc, rc);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (iPortSaved != iPort)
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IDE %s config mismatch: saved=%u config=%u"),
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync s_apszIdeEmuPortNames[i], iPortSaved, iPort);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (uPass == SSM_PASS_FINAL)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Restore data. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* The main device structure. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaCap);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaCtrl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaIs);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaPi);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaVs);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaCccCtl);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->regHbaCccPorts);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU8(pSSM, &pThis->uCccPortNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU64(pSSM, &pThis->uCccTimeout);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->uCccNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->fReset);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->f64BitAddr);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->fR0Enabled);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->fGCEnabled);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Now every port. */
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync PAHCIPort pAhciPort = &pThis->ahciPort[i];
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFB);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regFBU);
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, &pThis->ahciPort[i].regIE);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCMD);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regTFD);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSIG);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSSTS);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSCTL);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &pThis->ahciPort[i].regSERR);
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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (uVersion <= AHCI_SAVED_STATE_VERSION_VBOX_30)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion < AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync {
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync /* The old positions in the FIFO, not required. */
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync SSMR3Skip(pSSM, 2*sizeof(uint8_t));
543fd530ce618a1b55531ea76a785c7add7d072cvboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32TasksFinished);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32QueuedTasksFinished);
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion >= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
d00ac6bac8066f17185a6319257f617ecd021b4bvboxsync SSMR3GetU32(pSSM, (uint32_t *)&pThis->ahciPort[i].u32CurrentCommandSlot);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync if (uVersion > AHCI_SAVED_STATE_VERSION_PRE_ATAPI)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync {
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync SSMR3GetBool(pSSM, &pThis->ahciPort[i].fATAPI);
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 }
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync else if (pThis->ahciPort[i].fATAPI)
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
fa65f915725c271afa39d64ce9de684549a4959avboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync /* Check if we have tasks pending. */
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhciPort->u32TasksNew)
fa65f915725c271afa39d64ce9de684549a4959avboxsync {
fa65f915725c271afa39d64ce9de684549a4959avboxsync /*
fa65f915725c271afa39d64ce9de684549a4959avboxsync * There are tasks pending. The VM was saved after a task failed
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * because of non-fatal error. Set the redo flag.
fa65f915725c271afa39d64ce9de684549a4959avboxsync */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pAhciPort->fRedo = true;
fa65f915725c271afa39d64ce9de684549a4959avboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync if (uVersion <= AHCI_SAVED_STATE_VERSION_IDE_EMULATION)
1c14b7525891c8c3bbc9767497792894596a00f7vboxsync {
9ee86050975427444ed8f68e502d2aa9ddcbff1cvboxsync for (uint32_t i = 0; i < 2; i++)
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync {
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync rc = ahciR3LoadLegacyEmulationState(pSSM);
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync if(RT_FAILURE(rc))
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync return rc;
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync }
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync }
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync
f91ff89584929a0aee312f131927c63dc6639ad3vboxsync rc = SSMR3GetU32(pSSM, &u32);
0df0bb09b5473a52f430fa3bca214be7f542cae0vboxsync if (RT_FAILURE(rc))
0df0bb09b5473a52f430fa3bca214be7f542cae0vboxsync return rc;
0df0bb09b5473a52f430fa3bca214be7f542cae0vboxsync AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/* -=-=-=-=- device PDM interface -=-=-=-=- */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync uint32_t i;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhci->pDevInsRC += offDelta;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Relocate every port. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[i];
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->pAhciRC += offDelta;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->pDevInsRC += offDelta;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Destroy a driver instance.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * resources can be freed correctly.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int rc = VINF_SUCCESS;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync unsigned iActPort = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /*
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * At this point the async I/O thread is suspended and will not enter
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * this module again. So, no coordination is needed here and PDM
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * will take care of terminating and cleaning up the thread.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (PDMCritSectIsInitialized(&pAhci->lock))
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync Log(("%s: Destruct every port\n", __FUNCTION__));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (pAhciPort->pAsyncIOThread)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Destroy the event semaphore. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (RT_FAILURE(rc))
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Free all cached tasks. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (pAhciPort->aCachedTasks[i])
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync RTMemFree(pAhciPort->aCachedTasks[i]);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PDMR3CritSectDelete(&pAhci->lock);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return rc;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/**
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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic void ahciMediumRemoved(PAHCIPort pAhciPort)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_MEDIA_REMOVED);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/**
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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic void ahciMediumInserted(PAHCIPort pAhciPort)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t OldStatus, NewStatus;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync do
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync OldStatus = ASMAtomicReadU32(&pAhciPort->MediaEventStatus);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (OldStatus)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_CHANGED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case ATA_EVENT_STATUS_MEDIA_REMOVED:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* no change, we will send "medium removed" + "medium inserted" */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync NewStatus = ATA_EVENT_STATUS_MEDIA_CHANGED;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync NewStatus = ATA_EVENT_STATUS_MEDIA_NEW;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (!ASMAtomicCmpXchgU32(&pAhciPort->MediaEventStatus, NewStatus, OldStatus));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/**
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Called when a media is mounted.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync *
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Ignore the call if we're called while being attached. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (!pAhciPort->pDrvBlock)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPI)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogRel(("AHCI: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Report media changed in TEST UNIT and other (probably incorrect) places. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->cNotifiedMediaChange < 2)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cNotifiedMediaChange = 2;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciMediumInserted(pAhciPort);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/**
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Called when a media is unmounted
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log(("%s:\n", __FUNCTION__));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cTotalSectors = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPI)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /*
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.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cNotifiedMediaChange = 4;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciMediumRemoved(pAhciPort);
152d786a21a506f9e2a2e16ba8efdc2bcae133abvboxsync ataMediumTypeSet(pAhciPort, ATA_MEDIA_TYPE_UNKNOWN);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
0a3599702f0cfe19a23070ff9eddbcec0ae71298vboxsync AssertMsgFailed(("Hard disks don't have a mount interface!\n"));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Configure the attached device for a port.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Used by ahciR3Construct and ahciR3Attach.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
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.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync int rc = VINF_SUCCESS;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PDMBLOCKTYPE enmType;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /*
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Query the block and blockbios interfaces.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (!pAhciPort->pDrvBlock)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return VERR_PDM_MISSING_INTERFACE;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (!pAhciPort->pDrvBlockBios)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return VERR_PDM_MISSING_INTERFACE;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Try to get the optional async block interface. */
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /*
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Validate type.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if ( enmType != PDMBLOCKTYPE_HARD_DISK
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync && enmType != PDMBLOCKTYPE_CDROM
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync && enmType != PDMBLOCKTYPE_DVD)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync && !pAhciPort->pDrvMount)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return VERR_INTERNAL_ERROR;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (pAhciPort->fATAPI)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = 0;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cHeads = 0;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cSectors = 0;
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pAhciPort->iLUN, pAhciPort->cTotalSectors, (pAhciPort->fATAPIPassthrough ? "enabled" : "disabled")));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync else
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync &pAhciPort->PCHSGeometry);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = 0;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = VINF_SUCCESS;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync AssertRC(rc);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if ( pAhciPort->PCHSGeometry.cCylinders == 0
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync || pAhciPort->PCHSGeometry.cHeads == 0
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync || pAhciPort->PCHSGeometry.cSectors == 0)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cHeads = 16;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->PCHSGeometry.cSectors = 63;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Set the disk geometry information. Ignore errors. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync &pAhciPort->PCHSGeometry);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = VINF_SUCCESS;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
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,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->cTotalSectors));
76d0ab347ff09e78b52686e3fa7624f1686666ffvboxsync if (pAhciPort->pDrvBlock->pfnDiscard)
e91a1af7d4269cdd9c9bf82320fabeb475d68d8bvboxsync LogRel(("AHCI: LUN#%d: Enabled TRIM support\n", pAhciPort->iLUN));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return rc;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Callback employed by ahciR3Suspend and ahciR3PowerOff..
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @returns true if we've quiesced, false if we're still working.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (!ahciR3AllAsyncIOIsFinished(pDevIns))
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return false;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return true;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Common worker for ahciR3Suspend and ahciR3PowerOff.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, true);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (!ahciR3AllAsyncIOIsFinished(pDevIns))
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync else
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Suspend notification.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync Log(("ahciR3Suspend\n"));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3SuspendOrPowerOff(pDevIns);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Resume notification.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync *
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * @param pDevIns The device instance data.
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync{
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync /*
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Check if one of the ports has pending tasks.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Queue a notification item again in this case.
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync */
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[i];
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync if (pAhciPort->u32TasksNew)
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync {
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync Assert(pAhciPort->fRedo);
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync pAhciPort->fRedo = false;
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync pItem->iPort = pAhci->ahciPort[i].iLUN;
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync }
0d965a40e5d12447e940b5265aa9b6cd2ea59f6dvboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync Log(("%s:\n", __FUNCTION__));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync/**
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync * Initializes the VPD data of a attached device.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync *
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.
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsyncstatic int ahciR3VpdInit(PPDMDEVINS pDevIns, PAHCIPort pAhciPort, const char *pszName)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync{
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync int rc = VINF_SUCCESS;
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* Generate a default serial number. */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTUUID Uuid;
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (pAhciPort->pDrvBlock)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync else
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTUuidClear(&Uuid);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync pAhciPort->iLUN);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync else
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
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 szSerial);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync "1.0");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryBoolDef(pCfgNode, "NonRotationalMedium", &pAhciPort->fNonRotational, false);
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync /* There are three other identification strings for CD drives used for INQUIRY */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (pAhciPort->fATAPI)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync "VBOX");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIVendorId\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync "CD-ROM");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIProductId\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync "1.0");
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync {
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync N_("AHCI configuration error: failed to read \"ATAPIRevision\" as string"));
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync }
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return rc;
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync}
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Detach notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * One harddisk at one port has been unplugged.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The VM is suspended at this point.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fAsyncInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rcThread;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy the thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMR3ThreadDestroy(pAhciPort->pAsyncIOThread, &rcThread);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
52885caf093e0d00d1cceccfce54c2dd53a46776vboxsync pAhciPort->pAsyncIOThread = NULL;
52885caf093e0d00d1cceccfce54c2dd53a46776vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to destroy the event semaphore rc=%Rrc.\n", __FUNCTION__, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPI)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciMediumRemoved(pAhciPort);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync {
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync /*
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync * Inform the guest about the removed device.
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync */
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync pAhciPort->regSSTS = 0;
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync /*
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 */
2d04e048765b5cde38cc383c9c872b475224aa0bvboxsync ASMAtomicAndU32(&pAhciPort->regCMD, ~(AHCI_PORT_CMD_CPS | AHCI_PORT_CMD_CR));
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync ASMAtomicOrU32(&pAhciPort->regSERR, AHCI_PORT_SERR_N);
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync }
e4df369d452e04dd3aa3061a3c31c6f92b0bb2b9vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Zero some important members.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBase = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlock = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlockAsync = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlockBios = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach command.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This is called when we change block driver for one port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The VM is suspended at this point.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(int) ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[iLUN];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* the usual paranoia */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(iLUN < pAhci->cPortsImpl, ("iLUN=%u", iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRelease(!pAhciPort->pDrvBase);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRelease(!pAhciPort->pDrvBlock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRelease(!pAhciPort->pDrvBlockAsync);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(pAhciPort->iLUN == iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Try attach the block device and get the interfaces,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * required as well as optional.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBase = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlock = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync char szName[24];
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if ( pAhciPort->pDrvBlockAsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync && !pAhciPort->fATAPI)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->fAsyncInterface = true;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync }
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync else
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->fAsyncInterface = false;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Create event semaphore. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if (RT_FAILURE(rc))
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync return rc;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync }
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Create the async IO thread. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync RTTHREADTYPE_IO, szName);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if (RT_FAILURE(rc))
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync return rc;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync }
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync }
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /*
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync * Init vendor product data.
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if (RT_SUCCESS(rc))
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /* Inform the guest about the added device in case of hotplugging. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if ( RT_SUCCESS(rc)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync && !(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG))
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync {
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync /*
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync * Initialize registers
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync */
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
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if (pAhciPort->fATAPI)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->regSIG = AHCI_PORT_SIG_ATAPI;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync else
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->regSIG = AHCI_PORT_SIG_DISK;
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync pAhciPort->regSSTS = (0x01 << 8) | /* Interface is active. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync (0x02 << 4) | /* Generation 2 (3.0GBps) speed. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync (0x03 << 0); /* Device detected and communication established. */
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync if ( (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync || (pAhciPort->regIE & AHCI_PORT_IE_PCE)
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync || (pAhciPort->regIE & AHCI_PORT_IE_PRCE))
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN, VERR_IGNORED);
07022caee63a3c0f57f0ce7fef25bea10ad19d59vboxsync }
0df0bb09b5473a52f430fa3bca214be7f542cae0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9083f76e8c5709604766d0215a380de516e781eevboxsync * Common reset worker.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic int ahciR3ResetCommon(PPDMDEVINS pDevIns, bool fConstructor)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHBAReset(pAhci);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Hardware reset for the ports. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPortHwReset(&pAhci->ahciPort[i]);
9083f76e8c5709604766d0215a380de516e781eevboxsync return VINF_SUCCESS;
9083f76e8c5709604766d0215a380de516e781eevboxsync}
9083f76e8c5709604766d0215a380de516e781eevboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync/**
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync * Callback employed by ahciR3Reset.
9083f76e8c5709604766d0215a380de516e781eevboxsync *
9083f76e8c5709604766d0215a380de516e781eevboxsync * @returns true if we've quiesced, false if we're still working.
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance.
9083f76e8c5709604766d0215a380de516e781eevboxsync */
9083f76e8c5709604766d0215a380de516e781eevboxsyncstatic DECLCALLBACK(bool) ahciR3IsAsyncResetDone(PPDMDEVINS pDevIns)
9083f76e8c5709604766d0215a380de516e781eevboxsync{
9083f76e8c5709604766d0215a380de516e781eevboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9083f76e8c5709604766d0215a380de516e781eevboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync if (!ahciR3AllAsyncIOIsFinished(pDevIns))
9083f76e8c5709604766d0215a380de516e781eevboxsync return false;
9083f76e8c5709604766d0215a380de516e781eevboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
9083f76e8c5709604766d0215a380de516e781eevboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
9083f76e8c5709604766d0215a380de516e781eevboxsync return true;
9083f76e8c5709604766d0215a380de516e781eevboxsync}
9083f76e8c5709604766d0215a380de516e781eevboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync/**
9083f76e8c5709604766d0215a380de516e781eevboxsync * Reset notification.
9083f76e8c5709604766d0215a380de516e781eevboxsync *
9083f76e8c5709604766d0215a380de516e781eevboxsync * @param pDevIns The device instance data.
9083f76e8c5709604766d0215a380de516e781eevboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
9083f76e8c5709604766d0215a380de516e781eevboxsync{
9083f76e8c5709604766d0215a380de516e781eevboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9083f76e8c5709604766d0215a380de516e781eevboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, true);
9083f76e8c5709604766d0215a380de516e781eevboxsync if (!ahciR3AllAsyncIOIsFinished(pDevIns))
9083f76e8c5709604766d0215a380de516e781eevboxsync PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncResetDone);
9083f76e8c5709604766d0215a380de516e781eevboxsync else
9083f76e8c5709604766d0215a380de516e781eevboxsync {
9083f76e8c5709604766d0215a380de516e781eevboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
9083f76e8c5709604766d0215a380de516e781eevboxsync ahciR3ResetCommon(pDevIns, false /*fConstructor*/);
9083f76e8c5709604766d0215a380de516e781eevboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Poweroff notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns Pointer to the device instance
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsyncstatic DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync Log(("achiR3PowerOff\n"));
9083f76e8c5709604766d0215a380de516e781eevboxsync ahciR3SuspendOrPowerOff(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
cad8876b46f9e366c4a1007a40c27ca1df078950vboxsync * @interface_method_impl{PDMDEVREG,pfnConstruct}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsyncstatic DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMIBASE pBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned i = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fGCEnabled = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fR0Enabled = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbTotalBufferSize = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync LogFlowFunc(("pThis=%#p\n", pThis));
d9aa4de3f5ab154f8d65042d788b67e00bad28d9vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate and read configuration.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
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"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read GCEnabled as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read R0Enabled as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read PortCount as integer"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: cPortsImpl=%u\n", __FUNCTION__, pThis->cPortsImpl));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->cPortsImpl > AHCI_MAX_NR_PORTS_IMPL)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: PortCount=%u should not exceed %u"),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->cPortsImpl < 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: PortCount=%u should be at least 1"),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->cPortsImpl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync if (RT_FAILURE(rc))
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync N_("AHCI configuration error: failed to read Bootable as boolean"));
6a0b15b171dc10f072ec82f498d7b20d7c0eec6cvboxsync
3649373f921ada8549bf86c6edb03b340f2d214avboxsync rc = CFGMR3QueryU32Def(pCfg, "CmdSlotsAvail", &pThis->cCmdSlotsAvail, AHCI_NR_COMMAND_SLOTS);
3649373f921ada8549bf86c6edb03b340f2d214avboxsync if (RT_FAILURE(rc))
3649373f921ada8549bf86c6edb03b340f2d214avboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: failed to read CmdSlotsAvail as integer"));
3649373f921ada8549bf86c6edb03b340f2d214avboxsync Log(("%s: cCmdSlotsAvail=%u\n", __FUNCTION__, pThis->cCmdSlotsAvail));
3649373f921ada8549bf86c6edb03b340f2d214avboxsync if (pThis->cCmdSlotsAvail > AHCI_NR_COMMAND_SLOTS)
3649373f921ada8549bf86c6edb03b340f2d214avboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: CmdSlotsAvail=%u should not exceed %u"),
3649373f921ada8549bf86c6edb03b340f2d214avboxsync pThis->cPortsImpl, AHCI_NR_COMMAND_SLOTS);
3649373f921ada8549bf86c6edb03b340f2d214avboxsync if (pThis->cCmdSlotsAvail < 1)
3649373f921ada8549bf86c6edb03b340f2d214avboxsync return PDMDevHlpVMSetError(pDevIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
3649373f921ada8549bf86c6edb03b340f2d214avboxsync N_("AHCI configuration error: CmdSlotsAvail=%u should be at least 1"),
3649373f921ada8549bf86c6edb03b340f2d214avboxsync pThis->cCmdSlotsAvail);
3649373f921ada8549bf86c6edb03b340f2d214avboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->fR0Enabled = fR0Enabled;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->fGCEnabled = fGCEnabled;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pDevInsR3 = pDevIns;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
2e29d74fdcb3d8b2addc098119a729c0b3c7dbc3vboxsync PCIDevSetDeviceId (&pThis->dev, 0x2829); /* ICH-8M */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetCommand (&pThis->dev, 0x0000);
5ea2daf9bf716475ff7dca8d027fa366b874f16evboxsync#ifdef VBOX_WITH_MSI_DEVICES
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST);
8e6fc5ebe116c87b7cbc52f743ce6cbfaa6ffc07vboxsync PCIDevSetCapabilityList(&pThis->dev, 0xa0);
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync#else
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync PCIDevSetCapabilityList(&pThis->dev, 0x70);
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetRevisionId (&pThis->dev, 0x02);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetClassProg (&pThis->dev, 0x01);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetClassSub (&pThis->dev, 0x06);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetClassBase (&pThis->dev, 0x01);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetBaseAddress (&pThis->dev, 5, false, false, false, 0x00000000);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetInterruptLine(&pThis->dev, 0x00);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetInterruptPin (&pThis->dev, 0x01);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c8fa825f24555add43a7f0221dc4ad8320c4752dvboxsync pThis->dev.config[0x70] = VBOX_PCI_CAP_ID_PM; /* Capability ID: PCI Power Management Interface */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pThis->dev.config[0x71] = 0xa8; /* next */
c8fa825f24555add43a7f0221dc4ad8320c4752dvboxsync pThis->dev.config[0x72] = 0x03; /* version ? */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x90] = 0x40; /* AHCI mode. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x92] = 0x3f;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x94] = 0x80;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x95] = 0x01;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x97] = 0x78;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pThis->dev.config[0xa8] = 0x12; /* SATACR capability */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync pThis->dev.config[0xa9] = 0x00; /* next */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PCIDevSetWord(&pThis->dev, 0xaa, 0x0010); /* Revision */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync PCIDevSetDWord(&pThis->dev, 0xac, 0x00000028); /* SATA Capability Register 1 */
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Register the PCI device, it's I/O regions.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
5ea2daf9bf716475ff7dca8d027fa366b874f16evboxsync#ifdef VBOX_WITH_MSI_DEVICES
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync PDMMSIREG aMsiReg;
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync RT_ZERO(aMsiReg);
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync aMsiReg.cMsiVectors = 1;
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync aMsiReg.iMsiCapOffset = 0xa0;
0f1ee7c0c041f17c1c692fc7f09af458a62ceaeevboxsync aMsiReg.iMsiNextOffset = 0x70;
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg);
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync if (RT_FAILURE (rc))
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync {
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync LogRel(("Chipset cannot do MSI: %Rrc\n", rc));
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync PCIDevSetCapabilityList(&pThis->dev, 0x70);
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync /* That's OK, we can work without MSI */
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync }
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync#endif
e1b3d0780cefe2a5cc1745c3be2e213248ba2572vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3e4bc3e32bc6ac59335fae7115d09f7a2ca9dc4bvboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3IdxDataIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region for BMDMA"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI memory region for registers"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
021a33be84282e41b811563b5f60f3ada196af3evboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI#%u", iInstance);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Failed to create critical section.\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("pfnTMTimerCreate -> %Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pHbaCccTimerR0 = TMTimerR0Ptr(pThis->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pHbaCccTimerRC = TMTimerRCPtr(pThis->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Status LUN. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * Create the notification queue.
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync *
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync * We need 2 items for every port because of SMP races.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
f4f1486a0ea478a9cf75ad985f1d25915fa1f3a4vboxsync rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL*2, 0,
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialize static members on every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init members of the port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pThis->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDevInsR3 = pDevIns;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->iLUN = i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pAhciR3 = pThis;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pAhciR0 = PDMINS_2_DATA_R0PTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pAhciRC = PDMINS_2_DATA_RCPTR(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.u32Magic = PDMLED_MAGIC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBase = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Register statistics counter. */
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_WITH_STATISTICS
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->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time to map the guest buffers into R3.", "/Devices/SATA%d/Port%d/ProfileMapIntoR3", 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);
701a6c922821fe5fa1061a01258a7d9ad2efbe9fvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
d72aa6b0dab3e9b60aa78bfca99c767c48a406b0vboxsync "Amount of time to destroy the scatter gather list and free associated resources.", "/Devices/SATA%d/Port%d/ProfileDestroyScatterGatherList", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPortHwReset(pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Attach drivers to every available port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < pThis->cPortsImpl; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szName[24];
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync RTStrPrintf(szName, sizeof(szName), "Port%u", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pThis->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init interfaces.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync pAhciPort->IBase.pfnQueryInterface = ahciR3PortQueryInterface;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->IPortAsync.pfnTransferCompleteNotify = ahciTransferCompleteNotify;
cab115cfa31c584def7069312a1e23c3fc88533bvboxsync pAhciPort->IPort.pfnQueryDeviceLocation = ahciR3PortQueryDeviceLocation;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->IMountNotify.pfnMountNotify = ahciMountNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->IMountNotify.pfnUnmountNotify = ahciUnmountNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fAsyncIOThreadIdle = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach the block driver
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Failed to configure the %s.\n", __FUNCTION__, szName));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Mark that a device is present on that port */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (i < 6)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x93] |= (1 << i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init vendor product data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync rc = ahciR3VpdInit(pDevIns, pAhciPort, szName);
4ae37290cb50a39ea45112540ac89f0b12b172b8vboxsync if (RT_FAILURE(rc))
20699e832bd975f3af7e2ee0c264c33daeab6b48vboxsync return rc;
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlockAsync && pThis->fUseAsyncInterfaceIfAvailable)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI: LUN#%d: using async I/O\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fAsyncInterface = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI: LUN#%d: using normal I/O\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fAsyncInterface = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync RTTHREADTYPE_IO, szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBase = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("%s: no driver attached\n", szName));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI: Failed to attach drive to %s"), szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Attach status driver (optional).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync {
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
55d7f78467f8aefc7dff60f188bdf0f80523862cvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync NULL, ahciR3LiveExec, NULL,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3SavePrep, ahciR3SaveExec, NULL,
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3LoadPrep, ahciR3LoadExec, NULL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync /*
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * Register the info item.
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync */
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync char szTmp[128];
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "AHCI info", ahciR3Info);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync
9083f76e8c5709604766d0215a380de516e781eevboxsync return ahciR3ResetCommon(pDevIns, true /*fConstructor*/);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The device registration structure.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncconst PDMDEVREG g_DeviceAHCI =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32Version */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_VERSION,
2c8ee291fb75c4a6f05df160f5d67f4e9ef1cabcvboxsync /* szName */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahci",
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 |
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fClass */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_CLASS_STORAGE,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cMaxInstances */
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync ~0U,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cbInstance */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sizeof(AHCI),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnConstruct */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Construct,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDestruct */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Destruct,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnRelocate */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Relocate,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnIOCtl */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOn */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnReset */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Reset,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSuspend */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Suspend,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnResume */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Resume,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnAttach */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Attach,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDetach */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3Detach,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnQueryInterface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnInitComplete */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOff */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ahciR3PowerOff,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSoftReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32VersionEnd */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_VERSION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */