DevAHCI.cpp revision 3689d0733b6efa19676293c493337c8b6948c8c8
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * VBox storage devices: AHCI controller device (disk and cdrom).
b450d7a1747c5f4fb7c917a8ec1f9ce8440d7ffevboxsync * Implements the AHCI standard 1.1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2009 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 *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The data is transfered in an asychronous 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/pdmdev.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/pdmqueue.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/pdmthread.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "ide.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "ATAController.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include "../Builtins.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_MAX_NR_PORTS_IMPL 30
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_NR_COMMAND_SLOTS 32
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_NR_OF_ALLOWED_BIGGER_LISTS 100
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync/** The current saved state version. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync#define AHCI_SAVED_STATE_VERSION 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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
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
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync/** ATAPI sense info size. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync#define ATAPI_SENSE_SIZE 64
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Command Header. */
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;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Scatter gather list entry data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCIPORTTASKSTATESGENTRY
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether the buffer in the list is from the guest or an
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * allocated temporary buffer because the segments in the guest
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * are not sector aligned.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fGuestMemory;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag dependent data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync union
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data to handle direct mappings of guest buffers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The page lock. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PGMPAGEMAPLOCK PageLock;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } direct;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Data to handle temporary buffers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync struct
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The first segment in the guest which is not sector aligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrBaseFirstUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of unaligned buffers in the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the start of the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync void *pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } temp;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } u;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} AHCIPORTTASKSTATESGENTRY, *PAHCIPORTTASKSTATESGENTRY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Pointer to a pointer of a scatter gather list entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef PAHCIPORTTASKSTATESGENTRY *PPAHCIPORTTASKSTATESGENTRY;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/** Pointer to a task state. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsynctypedef struct AHCIPORTTASKSTATE *PAHCIPORTTASKSTATE;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync/**
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Data processing callback
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * @returns VBox status.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * @param pAhciPortTaskState The task state.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsynctypedef DECLCALLBACK(int) FNAHCIPOSTPROCESS(PAHCIPORTTASKSTATE pAhciPortTaskState);
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 */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR_FLUSH
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync} AHCITXDIR;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * A task state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct AHCIPORTTASKSTATE
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The ATAPI comnmand 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;
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** How many entries would fit into the sg list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGListSize;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /** Number of used SG list entries. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cSGListUsed;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the first entry of the scatter gather list. */
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSGListHead;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /** Number of scatter gather list entries. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cSGEntries;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /** Total number of bytes the guest reserved for this request.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Sum of all SG entries. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cbSGBuffers;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the first mapping information entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY paSGEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Size of the temporary buffer for unaligned guest segments. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbBufferUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the temporary buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync void *pvBufferUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of times in a row the scatter gather list was too big. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGListTooBig;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /** Post processing callback.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * If this is set we will use a buffer for the data
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * and the callback copies the data to the destination. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync PFNAHCIPOSTPROCESS pfnPostProcess;
b28326220af580dde4a61f15930f51fe584dc896vboxsync#ifdef RT_STRICT
b28326220af580dde4a61f15930f51fe584dc896vboxsync /** Flag whether the task state is currently active - used for debugging */
b28326220af580dde4a61f15930f51fe584dc896vboxsync volatile bool fActive;
b28326220af580dde4a61f15930f51fe584dc896vboxsync#endif
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync} AHCIPORTTASKSTATE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Notifier queue item.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct DEVPORTNOTIFIERQUEUEITEM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The core part owned by the queue manager. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMQUEUEITEMCORE Core;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** On which port the async io thread should be put into action. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t iPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Which task to process. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t iTask;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether the task is queued. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t fQueued;
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;
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** If we use the new async interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAsyncInterface;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Async IO Thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMTHREAD pAsyncIOThread;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Request semaphore. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTSEMEVENT AsyncIORequestSem;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Task queue. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile uint8_t ahciIOTasks[2*AHCI_NR_COMMAND_SLOTS];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Actual write position. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uActWritePos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Actual read position. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uActReadPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Actual number of active tasks. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile uint32_t uActTasksActive;
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Attached device is a CD/DVD drive. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fATAPI;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** Passthrough SCSI commands. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync bool fATAPIPassthrough;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Device specific settings. */
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of total sectors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t cTotalSectors;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Currently configured number of sectors in a multi-sector transfer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cMultSectors;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uATATransferMode;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** ATAPI sense data. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abATAPISense[ATAPI_SENSE_SIZE];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t cNotifiedMediaChange;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /** The same for GET_EVENT_STATUS for mechanism */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync volatile uint32_t MediaEventStatus;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The LUN. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTUINT iLUN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag if we are in a device reset. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fResetDevice;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Bitmask for finished tasks. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile uint32_t u32TasksFinished;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Bitmask for finished queued tasks. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile uint32_t u32QueuedTasksFinished;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t u32Alignment6;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Array of cached tasks. The tag number is the index value.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Only used with the async interface.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync R3PTRTYPE(PAHCIPORTTASKSTATE) aCachedTasks[AHCI_NR_COMMAND_SLOTS];
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /** First task throwing an error. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync R3PTRTYPE(volatile PAHCIPORTTASKSTATE) pTaskErr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
020cf6a056a32ddea5c3404a83237467f386f64evboxsync#if HC_ARCH_BITS == 32
020cf6a056a32ddea5c3404a83237467f386f64evboxsync uint32_t u32Alignment7;
493189f09538207d222d646e7ddc76adb3c438eevboxsync#endif
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync
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 /** Flag whether a notification was already send to R3. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile bool fNotificationSend;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether this port is in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile bool fPortReset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether the I/O thread idles. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile bool fAsyncIOThreadIdle;
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
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment1[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Base address of the MMIO region. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS MMIOBase;
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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Needed values for the emulated ide channels. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCIATACONTROLLER aCts[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
8b82f5ce032cb07de31804c998483b0988530aebvboxsync /** The critical section. */
8b82f5ce032cb07de31804c998483b0988530aebvboxsync PDMCRITSECT lock;
8b82f5ce032cb07de31804c998483b0988530aebvboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Bitmask of ports which asserted an interrupt. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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;
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync bool afAlignment8[1];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of usable ports on this controller. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cPortsImpl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync uint32_t Alignment9;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync volatile bool f8ByteMMIO4BytesWrittenSuccessfully;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** At which number of I/O requests per second we consider having high I/O load. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cHighIOThreshold;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** How many milliseconds to sleep. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cMillisToSleep;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_PORT_FB_RESERVED 0x7fffff00 /* 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_TASK_IS_QUEUED(x) ((x) & 0x1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_TASK_GET_TAG(x) ((x) >> 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_TASK_SET(tag, queued) (((tag) << 1) | (queued))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciHBAReset(PAHCI pThis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciLegacyFakeRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciPostFisIntoMemory(PAHCIPort pAhciPort, unsigned uFisType, uint8_t *cmdFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPostFirstD2HFisIntoMemory(PAHCIPort pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsyncstatic void ahciScatterGatherListGetTotalBufferSize(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsyncstatic int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync bool fReadonly, unsigned cSGEntriesProcessed);
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)) )
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#if 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)(Lo) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciHbaSetInterrupt(PAHCI pAhci, uint8_t iPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("P%u: %s: Setting interrupt\n", iPort, __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMCritSectEnter(&pAhci->lock, VINF_SUCCESS);
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);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhci, pAhci->uCccPortNr);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhciPort->regCMD & AHCI_PORT_CMD_ST) && (u32Value > 0))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDEVPORTNOTIFIERQUEUEITEM pItem;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Mark the tasks set in the value as used. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint8_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Queue task if bit is set in written value and not already in progress. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (((u32Value >> i) & 0x01) && !(pAhciPort->regCI & (1 << i)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fAsyncInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Put the tag number of the task into the FIFO. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uTag = AHCI_TASK_SET(i, ((pAhciPort->regSACT & (1 << i)) ? 1 : 0));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicWriteU8(&pAhciPort->ahciIOTasks[pAhciPort->uActWritePos], uTag);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Before uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActWritePos++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: After uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicIncU32(&pAhciPort->uActTasksActive);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fNotificationSend = ASMAtomicXchgBool(&pAhciPort->fNotificationSend, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fNotificationSend)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Send new notification. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem->iPort = pAhciPort->iLUN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pItem, ("Allocating item for queue failed\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem->iPort = pAhciPort->iLUN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem->iTask = i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pItem->fQueued = !!(pAhciPort->regSACT & (1 << i)); /* Mark if the task is queued. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((u32Value & AHCI_PORT_SCTL_DET) == AHCI_PORT_SCTL_DET_INIT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicXchgBool(&pAhciPort->fPortReset, true);
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#ifndef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_IOM_HC_MMIO_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset queue. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActWritePos = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActReadPos = 0;
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSCTL = u32Value;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (pAhciPort->regCMD & AHCI_PORT_CMD_ISS) >> 13, (pAhciPort->regCMD & AHCI_PORT_CMD_CCS) >> 8,
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)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pu32Value = pAhciPort->regCMD;
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 int rc = VINF_SUCCESS;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set engine state to running. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Clear current command slot. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u32Value &= ~(AHCI_PORT_CMD_CCS_SHIFT(0xff));
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_IOM_HC_MMIO_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFirstD2HFisIntoMemory(pAhciPort);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_DHRS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_DHRE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fFirstD2HFisSend)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifndef IN_RING3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_IOM_HC_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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
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{
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regIE = (u32Value & AHCI_PORT_IE_READONLY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if some a interrupt status bit changed*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32IntrStatus = ASMAtomicReadU32(&pAhciPort->regIS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & u32IntrStatus)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(ahci, pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
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
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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_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
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMCritSectEnter(&ahci->lock, VINF_IOM_HC_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
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;
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
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{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regIS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regIE = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD = AHCI_PORT_CMD_CPD | /* Cold presence detection */
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->fNotificationSend = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->u32TasksFinished = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->u32QueuedTasksFinished = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActWritePos = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActReadPos = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActTasksActive = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = 0x101; /* Signature for SATA device. */
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#ifdef IN_RING3
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#endif
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("Reset the HBA controller\n"));
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AHCI_HBA_CAP_NCS_SET(AHCI_NR_COMMAND_SLOTS) | /* 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}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Memory mapped I/O Handler for read 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 store the result.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cb Number of bytes read.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Break up 64 bits reads into two dword reads. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cb == 8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciMMIORead(pDevIns, pvUser, GCPhysAddr, pv, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ahciMMIORead(pDevIns, pvUser, GCPhysAddr + 4, (uint8_t *)pv + 4, 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log2(("#%d ahciMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Rrc\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pDevIns->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uOffset = (GCPhysAddr - pAhci->MMIOBase);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iReg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uOffset < AHCI_HBA_GLOBAL_SIZE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iReg = uOffset >> 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uOffset -= AHCI_HBA_GLOBAL_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iRegOffset = (uOffset % 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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: unsupported access width cb=%d uOffset=%x iPort=%x iRegOffset=%x iReg=%x!!!\n", __FUNCTION__, cb, uOffset, iPort, iRegOffset, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iReg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uOffset < AHCI_HBA_GLOBAL_SIZE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("Write global HBA register\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iReg = uOffset >> 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iReg < RT_ELEMENTS(g_aOpRegs))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const AHCIOPREG *pReg = &g_aOpRegs[iReg];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pReg->pfnWrite(pAhci, iReg, *(uint32_t *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to write global register %u/%u!!!\n", __FUNCTION__, iReg, RT_ELEMENTS(g_aOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("Write Port register\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Calculate accessed port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uOffset -= AHCI_HBA_GLOBAL_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iPort = uOffset / AHCI_PORT_REGISTER_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iReg = (uOffset % AHCI_PORT_REGISTER_SIZE) >> 2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to write to port %u and register %u\n", __FUNCTION__, iPort, iReg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_LIKELY( iPort < pAhci->cPortsImpl
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && iReg < RT_ELEMENTS(g_aPortOpRegs)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const AHCIPORTOPREG *pPortReg = &g_aPortOpRegs[iReg];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pPortReg->pfnWrite(pAhci, &pAhci->ahciPort[iPort], iReg, *(uint32_t *)pv);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log3(("%s: Trying to write port %u register %u/%u!!!\n", __FUNCTION__, iPort, iReg, RT_ELEMENTS(g_aPortOpRegs)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortWrite1(pCtl, Port, u32, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortRead1(pCtl, Port, pu32, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortWrite2(pCtl, Port, u32, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortRead2(pCtl, Port, pu32, cb);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifndef IN_RING0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Port I/O Handler for primary port range IN string operations.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @see FNIOMIOPORTINSTRING for details.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrDst, pcTransfer, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Port I/O Handler for primary port range OUT string operations.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @see FNIOMIOPORTOUTSTRING for details.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncPDMBOTHCBDECL(int) ahciIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iChannel = (uint32_t)(uintptr_t)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pAhci->aCts[iChannel];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(iChannel < 2);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ataControllerIOPortReadStr1(pCtl, Port, pGCPtrSrc, pcTransfer, cb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* !IN_RING0 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciMMIOWrite, ahciMMIORead, NULL, "AHCI");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fR0Enabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciMMIOWrite", "ahciMMIORead", NULL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fGCEnabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciMMIOWrite", "ahciMMIORead", NULL);
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
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
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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type: H2D\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d bytes\n", __FUNCTION__, AHCI_CMDFIS_TYPE_H2D_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command register update\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Control register update\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CMD=%#04x \"%s\"\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CMD], ATACmdText(cmdFis[AHCI_CMDFIS_CMD])));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FEAT=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FET]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: SECTN=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTN]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CYLL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLL]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CYLH=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLH]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: HEAD=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_HEAD]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: SECTNEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTNEXP]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CYLLEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLLEXP]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CYLHEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CYLHEXP]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: FETEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_FETEXP]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: SECTC=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTC]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: SECTCEXP=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_SECTCEXP]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: CTL=%#04x\n", __FUNCTION__, cmdFis[AHCI_CMDFIS_CTL]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Reset bit is set\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_D2H:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type D2H\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_D2H_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_SETDEVBITS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type Set Device Bits\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMAACTD2H:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type DMA Activate H2D\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMAACTD2H_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMASETUP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type DMA Setup\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_DMASETUP_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_PIOSETUP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type PIO Setup\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis size: %d\n", __FUNCTION__, AHCI_CMDFIS_TYPE_PIOSETUP_SIZE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DATA:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Command Fis type Data\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort Poitner 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = (1 << 8) | ATA_STAT_SEEK | ATA_STAT_WRERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Post the FIS in the memory area allocated by the guest and set interrupt if neccessary.
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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrRecFis += AHCI_RECFIS_RFIS_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbFis = AHCI_CMDFIS_TYPE_D2H_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_SETDEVBITS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrRecFis += AHCI_RECFIS_SDBFIS_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbFis = AHCI_CMDFIS_TYPE_SETDEVBITS_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_DMASETUP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrRecFis += AHCI_RECFIS_DSFIS_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbFis = AHCI_CMDFIS_TYPE_DMASETUP_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case AHCI_CMDFIS_TYPE_PIOSETUP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrRecFis += AHCI_RECFIS_PSFIS_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbFis = AHCI_CMDFIS_TYPE_PIOSETUP_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void atapiCmdOK(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] & ~7)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync | ((pAhciPortTaskState->enmTxDir != AHCITXDIR_WRITE) ? ATAPI_INT_REASON_IO : 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync | (!pAhciPortTaskState->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
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, 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])));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->uATARegError = pabATAPISense[2] << 4;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdFis[AHCI_CMDFIS_SECTN] = (pAhciPortTaskState->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. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic void atapiCmdErrorSimple(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, 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;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, 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
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 */
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 << 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);
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 return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef int (*PAtapiFunc)(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiGetConfigurationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic int atapiGetEventStatusNotificationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiIdentifySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiInquirySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiMechanismStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadCapacitySS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCRawSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiRequestSenseSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic int atapiPassthroughSS(PAHCIPORTTASKSTATE, PAHCIPort, int *);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiIdentifySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadCapacitySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadDiscInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTrackInformationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[36];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Accept address/number type of 1 only, and only track 1 exists. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&pAhciPortTaskState->aATAPICmd[2]) != 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiGetConfigurationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[32];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Accept valid request types only, and only starting feature 0. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhciPortTaskState->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&pAhciPortTaskState->aATAPICmd[2]) != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(aBuf, '\0', 32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U32(aBuf, 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * way to differentiate them right now is based on the image size). Also
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * implement signalling "no current profile" if no medium is loaded. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf + 6, 0x08); /* current profile: read-only CD */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf + 8, 0); /* feature 0: list of profiles supported */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[11] = 8; /* additional bytes for profiles */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The MMC-3 spec says that DVD-ROM read capability should be reported
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * before CD-ROM read capability. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf + 12, 0x10); /* profile: read-only DVD */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[14] = (0 << 0); /* NOT current profile */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataH2BE_U16(aBuf + 16, 0x08); /* profile: read only CD */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[18] = (1 << 0); /* current profile */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic int atapiGetEventStatusNotificationSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abBuf[8];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Assert(pAhciPortTaskState->enmTxDir == AHCITXDIR_READ);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Assert(pAhciPortTaskState->cbTransfer <= 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (!(pAhciPortTaskState->aATAPICmd[1] & 1))
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* no asynchronous operation supported */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[3] = 0x5e; /* suppored = 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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[3] = 0x5e; /* suppored = 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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync abBuf[3] = 0x5e; /* suppored = 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
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&abBuf[0], sizeof(abBuf));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiInquirySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiModeSenseErrorRecoverySS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiModeSenseCDStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiRequestSenseSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, pAhciPort->abATAPISense, sizeof(pAhciPort->abATAPISense));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiMechanismStatusSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCNormalSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[20], *q, iStartTrack;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fMSF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSize;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iStartTrack = pAhciPortTaskState->aATAPICmd[6];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iStartTrack > 1 && iStartTrack != 0xaa)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCMultiSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t aBuf[12];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fMSF;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fMSF = (pAhciPortTaskState->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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadTOCRawSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fMSF = (pAhciPortTaskState->aATAPICmd[1] >> 1) & 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iStartTrack = pAhciPortTaskState->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. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync *pcbData = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic int atapiPassthroughSS(PAHCIPORTTASKSTATE pAhciPortTaskState, PAHCIPort pAhciPort, int *pcbData)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync int rc = VINF_SUCCESS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t abATAPISense[ATAPI_SENSE_SIZE];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cbTransfer;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = pAhciPortTaskState->cbTransfer;
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 {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->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;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t *pbBuf = (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Assert(pAhciPortTaskState->cSGListUsed == 1);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (pAhciPortTaskState->aATAPICmd[0])
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_AND_VERIFY_10:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U16(pAhciPortTaskState->aATAPICmd + 7);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_WRITE_12:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 6);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataBE2H_U32(pAhciPortTaskState->aATAPICmd + 2);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataBE2H_U24(pAhciPortTaskState->aATAPICmd + 6) / pAhciPortTaskState->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_READ_CD_MSF:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync iATAPILBA = ataMSF2LBA(pAhciPortTaskState->aATAPICmd + 3);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSectors = ataMSF2LBA(pAhciPortTaskState->aATAPICmd + 6) - iATAPILBA;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync default:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", pAhciPortTaskState->aATAPICmd[0]));
3689d0733b6efa19676293c493337c8b6948c8c8vboxsync if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
3689d0733b6efa19676293c493337c8b6948c8c8vboxsync LogRel(("AHCI: LUN#%d: CD-ROM passthrough split error\n", pAhciPort->iLUN));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return false;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync memcpy(aATAPICmd, pAhciPortTaskState->aATAPICmd, ATAPI_PACKET_SIZE);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cReqSectors = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (i * pAhciPortTaskState->cbATAPISector > SCSI_MAX_BUFFER_SIZE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cReqSectors = SCSI_MAX_BUFFER_SIZE / pAhciPortTaskState->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cReqSectors = i;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbCurrTX = pAhciPortTaskState->cbATAPISector * cReqSectors;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync switch (pAhciPortTaskState->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,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->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;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pbBuf += pAhciPortTaskState->cbATAPISector * cReqSectors;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PDMBLOCKTXDIR enmBlockTxDir = PDMBLOCKTXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_TO_DEVICE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_NONE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir = PDMBLOCKTXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AssertMsgFailed(("Invalid transfer direction %d\n", pAhciPortTaskState->enmTxDir));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = pAhciPort->pDrvBlock->pfnSendCmd(pAhciPort->pDrvBlock,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->aATAPICmd,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmBlockTxDir,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->pSGListHead[0].pvSeg,
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 {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->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 {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Assert(cbTransfer <= pAhciPortTaskState->cbTransfer);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Reply with the same amount of data as the real drive. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync *pcbData = cbTransfer;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->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. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 8, "VBOX", 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 16, "CD-ROM", 16);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ataSCSIPadStr((uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg + 32, "1.0", 4);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cbTransfer)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbTransfer, cbTransfer, (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->cErrors < MAX_LOG_REL_ERRORS)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint8_t u8Cmd = pAhciPortTaskState->aATAPICmd[0];
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync do
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* don't log superflous 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 }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, abATAPISense, sizeof(abATAPISense));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return false;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync int cbTransfered = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc, rcSourceSink;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /*
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Create scatter gather list. We use a safe mapping here because it is
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * possible that the buffer is not a multiple of 512. The normal
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * creator would assert later here.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->cbSGBuffers)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, false, 0);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AssertRC(rc);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync LogFlow(("cbTransfered=%d\n", cbTransfered));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPortTaskState->cbSGBuffers)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AssertRC(rc);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Write updated command header into memory of the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rcSourceSink;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsyncstatic int atapiReadSectors2352PostProcess(PAHCIPORTTASKSTATE pAhciPortTaskState)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync{
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cSectors = pAhciPortTaskState->cbTransfer / 2048;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t iATAPILBA = pAhciPortTaskState->uOffset / 2048;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint8_t *pbBufDst = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint8_t *pbBufSrc = (uint8_t *)pAhciPortTaskState->pSGListHead[0].pvSeg;
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
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync return VINF_SUCCESS;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync}
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiReadSectors(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, 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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = iATAPILBA * cbSector;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = cSectors * cbSector;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2352:
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pfnPostProcess = atapiReadSectors2352PostProcess;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->uOffset = iATAPILBA * 2048;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbTransfer = cSectors * 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Unsupported sectors size\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic AHCITXDIR atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR rc = AHCITXDIR_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync const uint8_t *pbPacket;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbMax;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbPacket = pAhciPortTaskState->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)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync case SCSI_GET_EVENT_STATUS_NOTIFICATION:
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
dba0e7f8f385de972564b6917e305b8f53ea3480vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODEPAGE_CD_STATUS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
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 }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, 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-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
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 }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pbPacket[9] & 0xf8)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x00:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* nothing */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0x10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* normal read */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xf8:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* read all data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, 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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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 }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* This must be done from EMT. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINS pDevIns = pAhci->CTX_SUFF(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc2 = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Assert(RT_SUCCESS(rc2) || (rc == VERR_PDM_MEDIA_LOCKED));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 3: /* 11 - Load media */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (RT_SUCCESS(rc2))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_NORMAL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 1:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_MULTI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 2:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_TOC_RAW);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync error_cmd:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_CAPACITY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_DISC_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_READ_DISC_INFORMATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_TRACK_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->cNotifiedMediaChange > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cNotifiedMediaChange-- ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (!pAhciPort->pDrvMount->pfnIsMounted(pAhciPort->pDrvMount))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_CONFIGURATION);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_INQUIRY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbMax = pbPacket[4];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_INQUIRY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic AHCITXDIR atapiParseCmdPassthrough(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync const uint8_t *pbPacket;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cSectors, iATAPILBA;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync uint32_t cbTransfer = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR enmTxDir = AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pbPacket = pAhciPortTaskState->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:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->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 {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbTransfer = RT_MIN(cbTransfer, 8);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync break;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync case SCSI_GET_PERFORMANCE:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors * pAhciPortTaskState->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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors * pAhciPortTaskState->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:
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6) / pAhciPortTaskState->cbATAPISector * pAhciPortTaskState->cbATAPISector;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync goto sendcmd;
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. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors * pAhciPortTaskState->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 {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbTransfer = cbTransfer;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->enmTxDir = AHCITXDIR_READ;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, 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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors * pAhciPortTaskState->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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbATAPISector = 2048; /**< @todo this size is not always correct */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbTransfer = cSectors * pAhciPortTaskState->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. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->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));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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]));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiCmdErrorSimple(pAhciPort, pAhciPortTaskState, 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;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->enmTxDir = enmTxDir;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPortTaskState->cbTransfer = cbTransfer;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_PASSTHROUGH);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync return AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync}
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsyncstatic AHCITXDIR atapiParseCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync{
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync AHCITXDIR enmTxDir = AHCITXDIR_NONE;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync const uint8_t *pbPacket;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pbPacket = pAhciPortTaskState->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 */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLL] | (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CYLH] << 8), ATAPI_PACKET_SIZE, pbPacket));
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPIPassthrough)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = atapiParseCmdPassthrough(pAhciPort, pAhciPortTaskState);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync enmTxDir = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState The state to get the tag number from.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciFinishStorageDeviceReset(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSIG = 0x101;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState 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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciSendD2HFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, 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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_STS] = pAhciPortTaskState->uATARegStatus;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync d2hFis[AHCI_CMDFIS_ERR] = pAhciPortTaskState->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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_D2H, d2hFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fAssertIntr)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
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);
c7ff622115966b69b482bd2896662e40d823b22fvboxsync PAHCIPORTTASKSTATE pTaskErr = ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE);
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
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync 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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhci, pAhciPort->iLUN);
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
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsyncstatic void ahciScatterGatherListGetTotalBufferSize(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync{
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync unsigned cActualSGEntry;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync unsigned cSGLEntriesGCRead;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cbSGBuffers = 0; /* Total number of bytes reserved for this request. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Retrieve the total number of bytes reserved for this request. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (cSGLEntriesGCLeft)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Set start address of the entries. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync do
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Read the SG entries. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync cbSGBuffers += (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /* Set address to the next entries to read. */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync } while (cSGLEntriesGCLeft);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbSGBuffers = cbSGBuffers;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync}
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListAllocate(PAHCIPORTTASKSTATE pAhciPortTaskState, uint32_t cSGList, uint32_t cbUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cSGListSize < cSGList)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The entries are not allocated yet or the number is too small. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cSGListSize)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->paSGEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Allocate R3 scatter gather list. */
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync pAhciPortTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(cSGList * sizeof(RTSGSEG));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPortTaskState->pSGListHead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(cSGList * sizeof(AHCIPORTTASKSTATESGENTRY));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPortTaskState->paSGEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Reset usage statistics. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListSize = cSGList;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListTooBig = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPortTaskState->cSGListSize > cSGList)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The list is too big. Increment counter.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * So that the destroying function can free
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the list if it is too big too many times
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * in a row.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListTooBig++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Needed entries matches current size.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset counter.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListTooBig = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGEntries = cSGList;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->pvBufferUnaligned)
d5d7895749466b5fde7d281964421b81a690f2d9vboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
d5d7895749466b5fde7d281964421b81a690f2d9vboxsync pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(cbUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPortTaskState->pvBufferUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Make debugging easier. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(RTSGSEG));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->pvBufferUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync/**
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * Fallback scatter gather list creator.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * Used if the normal one fails in PDMDevHlpPhysGCPhys2CCPtr() or
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * PDMDevHlpPhysGCPhys2CCPtrReadonly() or post processing
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * is used.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync *
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * returns VBox status code.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * @param pAhciPort The ahci port.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * @param pAhciPortTaskState The task state which contains the S/G list entries.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * @param fReadonly If the mappings should be readonly.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * @param cSGEntriesProcessed Number of entries the normal creator procecssed
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * before an error occurred. Used to free
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * any ressources allocated before.
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync * @thread EMT
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync */
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsyncstatic int ahciScatterGatherListCreateSafe(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState,
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync bool fReadonly, unsigned cSGEntriesProcessed)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync{
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync Assert(VALID_PTR(pAhciPortTaskState->pSGListHead) || !cSGEntriesProcessed);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync Assert(VALID_PTR(pAhciPortTaskState->paSGEntries) || !cSGEntriesProcessed);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync for (unsigned cSGEntryCurr = 0; cSGEntryCurr < cSGEntriesProcessed; cSGEntryCurr++)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync if (pSGInfoCurr->fGuestMemory)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Release the lock. */
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Go to the next entry. */
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync pSGInfoCurr++;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync if (pAhciPortTaskState->pvBufferUnaligned)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
d80744f56e143e4e0d971fb3c94bb87123e8d15fvboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pvBufferUnaligned = NULL;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (pAhciPortTaskState->pSGListHead)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead = NULL;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (pAhciPortTaskState->paSGEntries)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTMemFree(pAhciPortTaskState->paSGEntries);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->paSGEntries = NULL;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListTooBig = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGEntries = 1;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed = 1;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListSize = 1;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbSGBuffers;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Allocate new buffers and SG lists. */
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(pAhciPortTaskState->cbSGBuffers);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync if (!pAhciPortTaskState->pvBufferUnaligned)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return VERR_NO_MEMORY;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync pAhciPortTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(1 * sizeof(RTSGSEG));
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync if (!pAhciPortTaskState->pSGListHead)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
d80744f56e143e4e0d971fb3c94bb87123e8d15fvboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return VERR_NO_MEMORY;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync if (!pAhciPortTaskState->paSGEntries)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
d5d7895749466b5fde7d281964421b81a690f2d9vboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return VERR_NO_MEMORY;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Set pointers. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (pAhciPortTaskState->cbTransfer)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbTransfer;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Allocate a separate buffer if we have to do post processing . */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (pAhciPortTaskState->pfnPostProcess)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead[0].pvSeg = RTMemAlloc(pAhciPortTaskState->cbTransfer);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (!pAhciPortTaskState->pSGListHead[0].pvSeg)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTMemFree(pAhciPortTaskState->paSGEntries);
d80744f56e143e4e0d971fb3c94bb87123e8d15fvboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync return VERR_NO_MEMORY;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync else
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync else
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead[0].cbSeg = pAhciPortTaskState->cbBufferUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead[0].pvSeg = pAhciPortTaskState->pvBufferUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync pAhciPortTaskState->paSGEntries[0].fGuestMemory = false;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync pAhciPortTaskState->paSGEntries[0].u.temp.cUnaligned = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync pAhciPortTaskState->paSGEntries[0].u.temp.GCPhysAddrBaseFirstUnaligned = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
046b442a663e5ccd055b12ebc5b72c1b8469f003vboxsync pAhciPortTaskState->paSGEntries[0].u.temp.pvBuf = pAhciPortTaskState->pvBufferUnaligned;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync ahciCopyFromSGListIntoBuffer(pDevIns, &pAhciPortTaskState->paSGEntries[0]);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return VINF_SUCCESS;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync}
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Create scatter gather list descriptors.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The ahci port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState The task state which contains the S/G list entries.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fReadonly If the mappings should be readonly.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @thread EMT
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListCreate(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fReadonly)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cActualSGEntry;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync unsigned cSGEntriesR3 = 0; /* Needed scatter gather list entries in R3. */
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync unsigned cSGEntriesProcessed = 0; /* Number of SG entries procesed. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SGLEntry aSGLEntry[32]; /* Holds read sg entries from guest. Biggest seen number of entries a guest set up. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cSGLEntriesGCRead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cSGLEntriesGCLeft; /* Available scatter gather list entries in GC */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrPRDTLEntryStart; /* Start address to read the entries from. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSegment; /* Size of the current segments in bytes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fUnaligned; /* Flag whether the current buffer is unaligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbUnaligned; /* Size of the unaligned buffers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fDoMapping = false;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync uint32_t cbSGBuffers = 0; /* Total number of bytes reserved for this request. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSGEntryCurr = NULL;
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSGEntryPrev = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8BufferUnalignedPos = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbUnalignedComplete = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileMapIntoR3, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbSGBuffers = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /*
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * Create a safe mapping when doing post processing because the size of the
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * data to transfer and the amount of guest memory reserved can differ.
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync *
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * @fixme: Read performance is really bad on OS X hosts because there is no
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * S/G support and the I/O manager has to create a newrequest
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * for every segment. The default limit of active requests is 16 on OS X
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * which causes a the bad read performance (writes are not affected
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * because of the writeback cache).
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * For now we will always use an intermediate buffer until
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync * there is support for host S/G operations.
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync */
62216cc0be0cc0f0b57b124939d208d0a6007fdfvboxsync if (pAhciPortTaskState->pfnPostProcess || true)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync ahciLog(("%s: Request with post processing.\n", __FUNCTION__));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly, 0);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We need to calculate the number of SG list entries in R3 first because the data buffers in the guest don't need to be
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * page aligned. Hence the number of SG list entries in the guest can differ from the ones we need
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * because PDMDevHlpPhysGCPhys2CCPtr works only on a page base.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * In the first pass we calculate the number of segments in R3 and in the second pass we map the guest segments into R3.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (int i = 0; i < 2; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGLEntriesGCLeft = AHCI_CMDHDR_PRDTL_ENTRIES(pCmdHdr->u32DescInf);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: cSGEntriesGC=%u\n", __FUNCTION__, cSGLEntriesGCLeft));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set start address of the entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fUnaligned = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fDoMapping)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: cSGEntriesR3=%u\n", __FUNCTION__, cSGEntriesR3));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The number of needed SG entries in R3 is known. Allocate needed memory. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListAllocate(pAhciPortTaskState, cSGEntriesR3, cbUnalignedComplete);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We are now able to map the pages into R3. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr = pAhciPortTaskState->paSGEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr = pAhciPortTaskState->pSGListHead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev = pSGEntryCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialize first segment to remove the need for additional if checks later in the code. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->cbSeg = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->fGuestMemory= false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8BufferUnalignedPos = (uint8_t *)pAhciPortTaskState->pvBufferUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbSGBuffers = cbSGBuffers;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGLEntriesGCLeft -= cSGLEntriesGCRead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Read the SG entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrDataBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: cActualSGEntry=%u cSGEntriesR3=%u\n", __FUNCTION__, cActualSGEntry, cSGEntriesR3));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbDataToTransfer = (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: cbDataToTransfer=%u\n", __FUNCTION__, cbDataToTransfer));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cbSGBuffers += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if the buffer is sector aligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbDataToTransfer % 512 != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We are not in an unaligned buffer but this is the first unaligned one. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fUnaligned = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned = cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesR3++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Unaligned buffer found cb=%d\n", __FUNCTION__, cbDataToTransfer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We are already in an unaligned buffer and this one is unaligned too. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnalignedComplete += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else /* Guest segment size is sector aligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (cbUnaligned % 512 == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The last buffer started at an offset
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * not aligned to a sector boundary but this buffer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * is sector aligned. Check if the current size of all
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * unaligned segments is a multiple of a sector.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If that's the case we can now map the segments again into R3.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fUnaligned = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fDoMapping)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set up the entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->fGuestMemory = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->cbSeg = cbUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8BufferUnalignedPos += cbUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the transfer is to the device we need to copy the content of the not mapped guest
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * segments into the temporary buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Advance to next entry saving the pointers to the current ones. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev = pSGEntryCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr++;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed++;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync cSGEntriesProcessed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnalignedComplete += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The size of the guest segment is sector aligned but it is possible that the segment crosses
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * a page boundary in a way splitting the segment into parts which are not sector aligned.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We have to treat them like unaligned guest segments then.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntry[cActualSGEntry].u32DBAUp, aSGLEntry[cActualSGEntry].u32DBA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: GCPhysAddrDataBase=%RGp\n", __FUNCTION__, GCPhysAddrDataBase));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Check if the physical address is page aligned.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (GCPhysAddrDataBase & PAGE_OFFSET_MASK)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrDataNextPage = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase) + PAGE_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Difference from the buffer start to the next page boundary. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32GCPhysAddrDiff = GCPhysAddrDataNextPage - GCPhysAddrDataBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (u32GCPhysAddrDiff % 512 != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We are not in an unaligned buffer but this is the first unaligned one. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fUnaligned = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned = cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrPRDTLUnalignedStart = GCPhysAddrPRDTLEntryStart + cActualSGEntry * sizeof(SGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesR3++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Guest segment is sector aligned but crosses a page boundary cb=%d\n", __FUNCTION__, cbDataToTransfer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We are already in an unaligned buffer and this one is unaligned too. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnaligned += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cUnaligned++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbUnalignedComplete += cbDataToTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Align page: GCPhysAddrDataBase=%RGp GCPhysAddrDataNextPage=%RGp\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, GCPhysAddrDataBase, GCPhysAddrDataNextPage));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysBufferPageAligned = PHYS_PAGE_ADDRESS(GCPhysAddrDataBase);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if the mapping ends at the page boundary and set segment size accordingly. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbSegment = (cbDataToTransfer < u32GCPhysAddrDiff)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ? cbDataToTransfer
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync : u32GCPhysAddrDiff;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Subtract size of the buffer in the actual page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbDataToTransfer -= cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (GCPhysBufferPageAlignedPrev != GCPhysBufferPageAligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We don't need to map the buffer if it is in the same page as the previous one. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fDoMapping)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pbMapping;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->fGuestMemory = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create the mapping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fReadonly)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysBufferPageAligned,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 0, (const void **)&pbMapping,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pSGInfoCurr->u.direct.PageLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysBufferPageAligned,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 0, (void **)&pbMapping,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pSGInfoCurr->u.direct.PageLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Mapping failed. Fall back to a bounce buffer. */
046b442a663e5ccd055b12ebc5b72c1b8469f003vboxsync ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync __FUNCTION__, GCPhysBufferPageAligned, rc));
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync cSGEntriesProcessed);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pbMapping + (GCPhysAddrDataBase - GCPhysBufferPageAligned) == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryCurr->cbSeg)))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev->cbSeg += cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Merged mapping pbMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pbMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->cbSeg = cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Let pvBuf point to the start of the buffer in the page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg = pbMapping
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync + (GCPhysAddrDataBase - GCPhysBufferPageAligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev = pSGEntryCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr++;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync cSGEntriesProcessed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesR3++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (fDoMapping)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev->cbSeg += cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Buffer is already in previous mapping pvSeg=%#p. New size is cbSeg=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Let physical address point to the next page in the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrDataBase = GCPhysAddrDataNextPage;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysBufferPageAlignedPrev = GCPhysBufferPageAligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* The address is now page aligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cbDataToTransfer)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u cSGEntriesR3=%u\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer, cSGEntriesR3));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if this is the last page the buffer is in. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbSegment = (cbDataToTransfer < PAGE_SIZE) ? cbDataToTransfer : PAGE_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbDataToTransfer -= cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fDoMapping)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync void *pvMapping;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->fGuestMemory = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create the mapping. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fReadonly)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhysAddrDataBase, 0, (const void **)&pvMapping, &pSGInfoCurr->u.direct.PageLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrDataBase, 0, &pvMapping, &pSGInfoCurr->u.direct.PageLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync {
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync /* Mapping failed. Fall back to a bounce buffer. */
046b442a663e5ccd055b12ebc5b72c1b8469f003vboxsync ahciLog(("%s: Mapping guest physical address %RGp failed with rc=%Rrc\n",
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync __FUNCTION__, GCPhysAddrDataBase, rc));
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync return ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, fReadonly,
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync cSGEntriesProcessed);
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check for adjacent mappings. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pvMapping == ((uint8_t *)pSGEntryPrev->pvSeg + pSGEntryPrev->cbSeg)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && (pSGInfoPrev->fGuestMemory == true))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Yes they are adjacent. Just add the size of this mapping to the previous segment. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev->cbSeg += cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Merged mapping pvMapping=%#p into current segment pvSeg=%#p. New size is cbSeg=%d\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pvMapping, pSGEntryPrev->pvSeg, pSGEntryPrev->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No they are not. Use a new sg entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->cbSeg = cbSegment;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg = pvMapping;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pvSegBegin=%#p pvSegEnd=%#p\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryPrev = pSGEntryCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr++;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
b8c36c1c1ce39852b741fbb6eca62adb3f15a25evboxsync cSGEntriesProcessed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesR3++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysBufferPageAlignedPrev = GCPhysAddrDataBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Go to the next page. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrDataBase += PAGE_SIZE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } /* if (!fUnaligned) */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } /* if !fUnaligned */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } /* if guest segment is sector aligned. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } /* for SGEntries read */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set address to the next entries to read. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (cSGLEntriesGCLeft);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fDoMapping = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } /* for passes */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if the last processed segment was unaligned. We need to add it now. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (fUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set up the entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!(cbUnaligned % 512), ("Buffer is not sector aligned\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->fGuestMemory = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.GCPhysAddrBaseFirstUnaligned = GCPhysAddrPRDTLUnalignedStart;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.cUnaligned = cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr->u.temp.pvBuf = pu8BufferUnalignedPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->pvSeg = pu8BufferUnalignedPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntryCurr->cbSeg = cbUnaligned;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cSGListUsed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the transfer is to the device we need to copy the content of the not mapped guest
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * segments into the temporary buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileMapIntoR3, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Destroy a scatter gather list and free all occupied resources (mappings, etc.)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The ahci port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState The task state which contains the S/G list entries.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListDestroy(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = pAhciPortTaskState->paSGEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDEVINS pDevIns = pAhciPort->CTX_SUFF(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileDestroyScatterGatherList, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync if (pAhciPortTaskState->pfnPostProcess)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync int rc;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync rc = pAhciPortTaskState->pfnPostProcess(pAhciPortTaskState);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync AssertRC(rc);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pfnPostProcess = NULL;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Free the buffer holding the unprocessed data. They are not needed anymore. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync RTMemFree(pAhciPortTaskState->pSGListHead[0].pvSeg);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync }
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (unsigned cActualSGEntry = 0; cActualSGEntry < pAhciPortTaskState->cSGEntries; cActualSGEntry++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pSGInfoCurr->fGuestMemory)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Release the lock. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.direct.PageLock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the data into the guest segments now. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciCopyFromBufferIntoSGList(pDevIns, pSGInfoCurr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Go to the next entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Free allocated memory if the list was too big too many times. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cSGListTooBig >= AHCI_NR_OF_ALLOWED_BIGGER_LISTS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->paSGEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->pvBufferUnaligned)
d80744f56e143e4e0d971fb3c94bb87123e8d15fvboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListSize = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cSGListTooBig = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pSGListHead = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->paSGEntries = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pvBufferUnaligned = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbBufferUnaligned = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileDestroyScatterGatherList, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copy a temporary buffer into a part of the guest scatter gather list
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * described by the given descriptor entry.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns Pointer to the device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pSGInfo Pointer to the segment info structure which describes the guest segments
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to write to which are unaligned.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SGLEntry aSGLEntries[5];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ? cSGEntriesLeft
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync : RT_ELEMENTS(aSGLEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < cSGEntriesRead; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy into SG entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8Buf += cbCopied;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesLeft -= cSGEntriesRead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (cSGEntriesLeft);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copy a part of the guest scatter gather list into a temporary buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns Pointer to the device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pSGInfo Pointer to the segment info structure which describes the guest segments
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * to read from which are unaligned.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PAHCIPORTTASKSTATESGENTRY pSGInfo)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8Buf = (uint8_t *)pSGInfo->u.temp.pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SGLEntry aSGLEntries[5];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGEntriesLeft = pSGInfo->u.temp.cUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysPRDTLStart = pSGInfo->u.temp.GCPhysAddrBaseFirstUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGEntriesRead = (cSGEntriesLeft < RT_ELEMENTS(aSGLEntries))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ? cSGEntriesLeft
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync : RT_ELEMENTS(aSGLEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysPRDTLStart, &aSGLEntries[0], cSGEntriesRead * sizeof(SGLEntry));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < cSGEntriesRead; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrDataBase = AHCI_RTGCPHYS_FROM_U32(aSGLEntries[i].u32DBAUp, aSGLEntries[i].u32DBA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbCopied = (aSGLEntries[i].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy into buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pu8Buf, cbCopied);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8Buf += cbCopied;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysPRDTLStart += cSGEntriesRead * sizeof(SGLEntry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntriesLeft -= cSGEntriesRead;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (cSGEntriesLeft);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copy the content of a buffer to a scatter gather list.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * @returns Number of bytes transfered.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState The task state which contains the S/G list entries.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pvBuf Pointer to the buffer which should be copied.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cbBuf Size of the buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciScatterGatherListCopyFromBuffer(PAHCIPORTTASKSTATE pAhciPortTaskState, void *pvBuf, size_t cbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cSGEntry = 0;
87d9823b393efbc674b3f3b0ff96998ca89e89b7vboxsync size_t cbCopied = 0;
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8Buf = (uint8_t *)pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cSGEntry < pAhciPortTaskState->cSGEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync size_t cbToCopy = RT_MIN(cbBuf, pSGEntry->cbSeg);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbBuf -= cbToCopy;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cbCopied += cbToCopy;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We finished. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!cbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Advance the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8Buf += cbToCopy;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Go to the next entry in the list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntry++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntry++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync LogFlow(("%s: Copied %d bytes\n", __FUNCTION__, cbCopied));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync return cbCopied;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Complete a data transfer task by freeing all occupied ressources
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * and notifying the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort Pointer to the port where to request completed.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState Pointer to the task which finished.
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync * @param rcReq IPRT status code of the completed request.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsyncstatic int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Free system resources occupied by the scatter gather list. */
c1e8287e038e789c1eefcee00a2e63258ca22d48vboxsync if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
c1e8287e038e789c1eefcee00a2e63258ca22d48vboxsync ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync if (RT_FAILURE(rcReq))
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync {
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->uATARegError = ID_ERR;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync /* Log the error. */
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync {
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPort->iLUN, rcReq));
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync else
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPort->iLUN,
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync ? "Read"
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync : "Write",
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->uOffset,
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->cbTransfer, rcReq));
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync }
c7ff622115966b69b482bd2896662e40d823b22fvboxsync ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync }
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync else
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync {
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->uATARegError = 0;
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
3565326e022b689152f7d0c9b2b507a27950e10fvboxsync /* Write updated command header into memory of the guest. */
3565326e022b689152f7d0c9b2b507a27950e10fvboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
3565326e022b689152f7d0c9b2b507a27950e10fvboxsync &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
3565326e022b689152f7d0c9b2b507a27950e10fvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Actual.s.fReading = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->fQueued)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cOutstandingTasks;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
c7ff622115966b69b482bd2896662e40d823b22fvboxsync if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b28326220af580dde4a61f15930f51fe584dc896vboxsync#ifdef RT_STRICT
b28326220af580dde4a61f15930f51fe584dc896vboxsync bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
b28326220af580dde4a61f15930f51fe584dc896vboxsync AssertMsg(fXchg, ("Task is not active\n"));
b28326220af580dde4a61f15930f51fe584dc896vboxsync#endif
b28326220af580dde4a61f15930f51fe584dc896vboxsync
3f9a93c56fd9896836bf644a649862a091b24a6dvboxsync /* Always raise an interrupt after task completion; delaying
3f9a93c56fd9896836bf644a649862a091b24a6dvboxsync * this (interrupt coalescing) increases latency and has a significant
3f9a93c56fd9896836bf644a649862a091b24a6dvboxsync * impact on performance (see #5071)
3f9a93c56fd9896836bf644a649862a091b24a6dvboxsync */
3f9a93c56fd9896836bf644a649862a091b24a6dvboxsync ahciSendSDBFis(pAhciPort, 0, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
b28326220af580dde4a61f15930f51fe584dc896vboxsync {
b28326220af580dde4a61f15930f51fe584dc896vboxsync#ifdef RT_STRICT
b28326220af580dde4a61f15930f51fe584dc896vboxsync bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
b28326220af580dde4a61f15930f51fe584dc896vboxsync AssertMsg(fXchg, ("Task is not active\n"));
b28326220af580dde4a61f15930f51fe584dc896vboxsync#endif
b28326220af580dde4a61f15930f51fe584dc896vboxsync
74b7550a7abc285c92d813a0188aea3a6f677a92vboxsync ASMAtomicDecU32(&pAhciPort->uActTasksActive);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
b28326220af580dde4a61f15930f51fe584dc896vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Add the task to the cache. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync if (pAhciPort->uActTasksActive == 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 */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsyncstatic AHCITXDIR ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR rc = AHCITXDIR_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fLBA48 = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync CmdHdr *pCmdHdr = &pAhciPortTaskState->cmdHdr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pCmdFis[AHCI_CMDFIS_TYPE] == AHCI_CMDFIS_TYPE_H2D, ("FIS is not a host to device Fis!!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->cbTransfer = 0;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmdFis[AHCI_CMDFIS_CMD])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDENTIFY_DEVICE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync int rc2;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint16_t u16Temp[256];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Fill the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciIdentifySS(pAhciPort, u16Temp);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create scatter gather list. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (RT_FAILURE(rc2))
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy list. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (RT_FAILURE(rc2))
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Write updated command header into memory of the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync rc = atapiParseCmd(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDENTIFY_PACKET_DEVICE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiDoTransfer(pAhciPort, pAhciPortTaskState, ATAFN_SS_ATAPI_IDENTIFY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_DMA_EXT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fLBA48 = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_DMA:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_WRITE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_WRITE_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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];
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"));
c7ff622115966b69b482bd2896662e40d823b22fvboxsync PAHCIPORTTASKSTATE pTaskErr = ASMAtomicXchgPtrT(&pAhciPort->pTaskErr, NULL, PAHCIPORTTASKSTATE);
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 /* Create scatter gather list. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync int rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (RT_FAILURE(rc2))
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Copy the buffer. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &aBuf[offLogRead], cbLogRead);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Destroy list. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (RT_FAILURE(rc2))
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPortTaskState->uATARegError = 0;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync /* Write updated command header into memory of the guest. */
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync break;
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* All not implemented commands go below. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SECURITY_FREEZE_LOCK:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SMART:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_NV_CACHE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default: /* For debugging purposes. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Unknown command issued\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = ABRT_ERR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPortTaskState The state of the actual task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciPortTaskGetCommandFis(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->GCPhysCmdHdrAddr = pAhciPort->GCPhysAddrClb + pAhciPortTaskState->uTag * sizeof(CmdHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlow(("%s: PDMDevHlpPhysRead GCPhysAddrCmdLst=%RGp cbCmdHdr=%u\n", __FUNCTION__,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->GCPhysCmdHdrAddr, sizeof(CmdHdr)));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the command header. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciDumpCmdHdrInfo(pAhciPort, &pAhciPortTaskState->cmdHdr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrCmdTbl = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg((pAhciPortTaskState->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));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->cmdFis[0], AHCI_CMDFIS_TYPE_H2D_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set transfer direction. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState->enmTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? AHCITXDIR_WRITE : AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If this is an ATAPI command read the atapi command. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_A)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync GCPhysAddrCmdTbl += AHCI_CMDHDR_ACMD_OFFSET;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrCmdTbl, &pAhciPortTaskState->aATAPICmd[0], ATAPI_PACKET_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We "received" the FIS. Clear the BSY bit in regTFD. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ((pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_C) && (pAhciPortTaskState->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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD &= ~AHCI_PORT_TFD_BSY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print some infos about the FIS. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciDumpFisInfo(pAhciPort, &pAhciPortTaskState->cmdFis[0]);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync /* Print the PRDT */
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync RTGCPHYS GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pAhciPortTaskState->cmdHdr.u32CmdTblAddrUp, pAhciPortTaskState->cmdHdr.u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ahciLog(("PRDT address %RGp number of entries %u\n", GCPhysAddrPRDTLEntryStart, AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf)));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync for (unsigned i = 0; i < AHCI_CMDHDR_PRDTL_ENTRIES(pAhciPortTaskState->cmdHdr.u32DescInf); i++)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync {
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync SGLEntry SGEntry;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ahciLog(("Entry %u at address %RGp\n", i, GCPhysAddrPRDTLEntryStart));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync PDMDevHlpPhysRead(pAhciPort->CTX_SUFF(pDevIns), GCPhysAddrPRDTLEntryStart, &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
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync GCPhysAddrPRDTLEntryStart += 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 {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATE pAhciPortTaskState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b28326220af580dde4a61f15930f51fe584dc896vboxsync /*
b28326220af580dde4a61f15930f51fe584dc896vboxsync * Check if there is already an allocated task struct in the cache.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Allocate a new task otherwise.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b28326220af580dde4a61f15930f51fe584dc896vboxsync#ifdef RT_STRICT
b28326220af580dde4a61f15930f51fe584dc896vboxsync bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, true, false);
b28326220af580dde4a61f15930f51fe584dc896vboxsync AssertMsg(fXchg, ("Task is already active\n"));
b28326220af580dde4a61f15930f51fe584dc896vboxsync#endif
b28326220af580dde4a61f15930f51fe584dc896vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set current command slot */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uTag = pNotifierItem->iTask;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pNotifierItem->fQueued)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->fQueued = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->fQueued = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If the reset bit is set put the device into reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fResetDevice = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync#ifdef RT_STRICT
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync AssertMsg(fXchg, ("Task is not active\n"));
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync#ifdef RT_STRICT
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync AssertMsg(fXchg, ("Task is not active\n"));
35969850b67baa676a5f56fb4ee7a815985e5520vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else /* We are not in a reset state update the control registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir != AHCITXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
c1e8287e038e789c1eefcee00a2e63258ca22d48vboxsync pAhciPortTaskState->enmTxDir = enmTxDir;
c1e8287e038e789c1eefcee00a2e63258ca22d48vboxsync
74b7550a7abc285c92d813a0188aea3a6f677a92vboxsync ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
74b7550a7abc285c92d813a0188aea3a6f677a92vboxsync ASMAtomicIncU32(&pAhciPort->uActTasksActive);
74b7550a7abc285c92d813a0188aea3a6f677a92vboxsync ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir != AHCITXDIR_FLUSH)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (RT_FAILURE(rc))
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir == AHCITXDIR_FLUSH)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else if (enmTxDir == AHCITXDIR_READ)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VINF_VD_ASYNC_IO_FINISHED)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, VINF_SUCCESS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
f27e44a5e1633e2fb4c44f962a2c503c451c1418vboxsync rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
b28326220af580dde4a61f15930f51fe584dc896vboxsync#ifdef RT_STRICT
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
b28326220af580dde4a61f15930f51fe584dc896vboxsync AssertMsg(fXchg, ("Task is not active\n"));
b28326220af580dde4a61f15930f51fe584dc896vboxsync#endif
b28326220af580dde4a61f15930f51fe584dc896vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* There is nothing left to do. Notify the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Add the task to the cache. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATE pAhciPortTaskState;
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;
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Failed to allocate task state memory\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while(pThread->enmState == PDMTHREADSTATE_RUNNING)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t uQueuedTasksFinished = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* New run to get number of I/O requests per second?. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!u64StartTime)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u64StartTime = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
ad8fb8c920c36650d5ead020ef8e05b681dd4375vboxsync if (pAhci->fSignalIdle)
9083f76e8c5709604766d0215a380de516e781eevboxsync PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_TIMEOUT)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* No I/O requests inbetween. Reset statistics and wait again. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->StatIORequestsPerSecond.c = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * To maximize the throughput of the controller we try to minimize the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * number of world switches during interrupts by grouping as many
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * I/O requests together as possible.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * On the other side we want to get minimal latency if the I/O load is low.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Thatswhy the number of I/O requests per second is measured and if it is over
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * a threshold the thread waits for other requests from the guest.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uIOsPerSec >= pAhci->cHighIOThreshold)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync do
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Sleep some time. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTThreadSleep(pAhci->cMillisToSleep);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we got some new requests inbetween. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uActWritePosPrev != pAhciPort->uActWritePos)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uActWritePosPrev = pAhciPort->uActWritePos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Check if the queue is full. If that is the case
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * there is no point waiting another round.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( ( (pAhciPort->uActReadPos < uActWritePosPrev)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || ( (pAhciPort->uActReadPos > uActWritePosPrev)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Queue full -> leaving\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Another round\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else /* No change break out of the loop. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uQueuedTasks;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->uActReadPos < uActWritePosPrev)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync } while (true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Process commands. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while ( (cTasksToProcess > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && RT_LIKELY(!pAhciPort->fPortReset))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync AHCITXDIR enmTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uActTag;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Before uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uActTag = pAhciPort->ahciIOTasks[pAhciPort->uActReadPos];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uTag = AHCI_TASK_GET_TAG(uActTag);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number!!\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Set current command slot */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (AHCI_TASK_IS_QUEUED(uActTag))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->fQueued = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->fQueued = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Got command at slot %d\n", __FUNCTION__, pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* If the reset bit is set put the device into reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fResetDevice = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* TODO: We are not in a reset state update the control registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir == AHCITXDIR_FLUSH)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /* Log the error. */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if ( RT_FAILURE(rc)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPort->iLUN, rc));
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (RT_FAILURE(rc))
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState->uATARegError = ID_ERR;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState->uATARegError = 0;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (pAhciPortTaskState->fQueued)
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync /* Task is not queued send D2H FIS */
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync }
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync else if (enmTxDir != AHCITXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t uOffset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbTransfer;
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSegCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Initialize all values. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uOffset = pAhciPortTaskState->uOffset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTransfer = pAhciPortTaskState->cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSegCurr = &pAhciPortTaskState->pSGListHead[0];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr = pAhciPortTaskState->paSGEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, b);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync while (cbTransfer)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbProcess = (cbTransfer < pSegCurr->cbSeg) ? cbTransfer : pSegCurr->cbSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!(pSegCurr->cbSeg % 512), ("Buffer is not sector aligned cbSeg=%d\n", pSegCurr->cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync if (enmTxDir == AHCITXDIR_READ)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSegCurr->pvSeg, cbProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Actual.s.fReading = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, uOffset,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSegCurr->pvSeg, cbProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Actual.s.fWriting = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, cbProcess);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Go to the next entry. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uOffset += cbProcess;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTransfer -= cbProcess;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSegCurr++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, b);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync /* Log the error. */
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync if ( RT_FAILURE(rc)
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync && pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync {
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPort->iLUN,
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync enmTxDir == AHCITXDIR_READ
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync ? "Read"
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync : "Write",
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync uOffset, cbTransfer, rc));
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Cleanup. */
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync int rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync if (RT_FAILURE(rc2))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_LIKELY(!pAhciPort->fPortReset))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer - cbTransfer;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync if (RT_FAILURE(rc))
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync {
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->uATARegError = ID_ERR;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync else
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync {
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->uATARegError = 0;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Write updated command header into memory of the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->fQueued)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Task is not queued send D2H FIS */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uIORequestsProcessed++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Nothing left to do. Notify the guest. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileProcessTime, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Be paranoid. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Make the port number invalid making it easier to track down bugs. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActReadPos++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cTasksToProcess--;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync /* If we encountered an error notify the guest and continue with the next task. */
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync if (RT_FAILURE(rc))
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync {
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync uQueuedTasksFinished = 0;
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync }
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync else if (!cTasksToProcess)
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
c7b0001a9846d83269a0a71ee53736ae2ab6421fvboxsync ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uQueuedTasksFinished = 0;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Free task state memory */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->pSGListHead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pSGListHead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->paSGEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->paSGEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->pvBufferUnaligned)
d80744f56e143e4e0d971fb3c94bb87123e8d15fvboxsync RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
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/**
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync * LsiLogic 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);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortActWritePos=%u\n", pThisPort->uActWritePos);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortActReadPos=%u\n", pThisPort->uActReadPos);
21bb295abca4425cc9b6aa2fff6d3f5a8eba0cc3vboxsync pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->uActTasksActive);
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, "PortNotificationSend=%RTbool\n", pThisPort->fNotificationSend);
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)
9083f76e8c5709604766d0215a380de516e781eevboxsync fFinished = (pThisPort->uActTasksActive == 0);
9083f76e8c5709604766d0215a380de516e781eevboxsync else
9083f76e8c5709604766d0215a380de516e781eevboxsync fFinished = ((pThisPort->uActTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
9083f76e8c5709604766d0215a380de516e781eevboxsync if (!fFinished)
9083f76e8c5709604766d0215a380de516e781eevboxsync return false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync if (!ataControllerIsIdle(&pThis->aCts[i]))
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync return false;
fbad775ac7689eb33561f4f57ffe22cc85cc7714vboxsync
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 {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync Assert(pThis->ahciPort[i].uActTasksActive == 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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* No need to save */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU8(pSSM, pThis->ahciPort[i].uActWritePos);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3PutU8(pSSM, pThis->ahciPort[i].uActReadPos);
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now the emulated ata controllers. */
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = ataControllerSaveExec(&pThis->aCts[i], pSSM);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if ( uVersion != AHCI_SAVED_STATE_VERSION
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync && 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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU32(pSSM, &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 {
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
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActWritePos);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActReadPos);
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);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync /* Now the emulated ata controllers. */
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync {
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = ataControllerLoadExec(&pThis->aCts[i], pSSM);
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync if (RT_FAILURE(rc))
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync return rc;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync }
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync rc = SSMR3GetU32(pSSM, &u32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync 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 /* Relocate emulated ATA controllers. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ataControllerRelocate(&pAhci->aCts[i], offDelta);
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 {
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (pAhciPort->aCachedTasks[i]->pSGListHead)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync if (pAhciPort->aCachedTasks[i]->paSGEntries)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync RTMemFree(pAhciPort->aCachedTasks[i]);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync }
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync /* Destroy emulated ATA controllers. */
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ataControllerDestroy(&pAhci->aCts[i]);
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);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /*
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Initialize registers
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->regCMD |= AHCI_PORT_CMD_CPS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->regSERR |= AHCI_PORT_SERR_N;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
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);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync else
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync /*
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync * Inform the guest about the removed device.
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync */
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->regSSTS = 0;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync pAhciPort->regSERR |= AHCI_PORT_SERR_N;
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync }
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));
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
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync Log(("%s:\n", __FUNCTION__));
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync ataControllerResume(&pAhci->aCts[i]);
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync return;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync}
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync
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
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync /* Check if the changed port uses IDE emulation. */
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync bool fMaster = false;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync PAHCIATACONTROLLER pCtl = NULL;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync for (unsigned j = 0; j < RT_ELEMENTS(pAhci->aCts[0].aIfs); j++)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync PAHCIATACONTROLLER pTmp = &pAhci->aCts[i];
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (pTmp->aIfs[j].iLUN == iLUN)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync pCtl = pTmp;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync fMaster = j == 0 ? true : false;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (pCtl)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync ataControllerDetach(pCtl, fMaster);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (pAhciPort->fATAPI)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciMediumRemoved(pAhciPort);
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
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 {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync /* Check if the changed port uses IDE emulation. */
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync bool fMaster = false;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync PAHCIATACONTROLLER pCtl = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync for (unsigned j = 0; j < RT_ELEMENTS(pAhci->aCts[0].aIfs); j++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync PAHCIATACONTROLLER pTmp = &pAhci->aCts[i];
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (pTmp->aIfs[j].iLUN == iLUN)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync pCtl = pTmp;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync fMaster = j == 0 ? true : false;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync /* Attach to the controller if available */
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (pCtl)
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync rc = ataControllerAttach(pCtl, pAhciPort->pDrvBase, fMaster);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (RT_SUCCESS(rc))
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if ( pAhciPort->pDrvBlockAsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync && !pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync pAhciPort->fAsyncInterface = true;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync else
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync char szName[24];
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync pAhciPort->fAsyncInterface = false;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync /* Create event semaphore. */
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (RT_FAILURE(rc))
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync return rc;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync /* Create the async IO thread. */
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync RTTHREADTYPE_IO, szName);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync if (RT_FAILURE(rc))
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync {
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync return rc;
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync if (RT_SUCCESS(rc) && pAhciPort->fATAPI)
46a78ba0ce1d037aaed54f3df16ebd9c0b70ed39vboxsync ahciMediumInserted(pAhciPort);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerReset(&pAhci->aCts[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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate and read configuration.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "R0Enabled\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PrimaryMaster\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PrimarySlave\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SecondaryMaster\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SecondarySlave\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PortCount\0"
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync "UseAsyncInterfaceIfAvailable\0"
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync "HighIOThreshold\0"
6a795f9e75e30c7f1d75cd45e5de233c71662f58vboxsync "MillisToSleep\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"));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, "MillisToSleep", &pThis->cMillisToSleep, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read MillisToSleep as integer"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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);
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 pThis->dev.config[0x34] = 0x80; /* Capability pointer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetInterruptLine(&pThis->dev, 0x00);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCIDevSetInterruptPin (&pThis->dev, 0x01);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x70] = 0x01; /* Capability ID: PCI Power Management Interface */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x71] = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x72] = 0x03;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x80] = 0x05; /* Capability ID: Message Signaled Interrupts. Disabled. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->dev.config[0x81] = 0x70; /* next. */
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
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
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
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, 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 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
3e9c5c3e44de15c28695c7b570bc2551639187e3vboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, RT_SRC_POS, "AHCI");
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. */
4e27e4613f5f3a90c12ebf57c4d1480a39c790davboxsync /** @todo r=bird: Using the virtual sync clock needs some justification.
4e27e4613f5f3a90c12ebf57c4d1480a39c790davboxsync * Currently not an issue as this feature isn't used by any guest
4e27e4613f5f3a90c12ebf57c4d1480a39c790davboxsync * yet. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ahciCccTimer, pThis,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMTIMER_FLAGS_DEFAULT_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 /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Create the transmit queue.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Number of DMA transfers.", "/Devices/SATA%d/Port%d/DMA", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of data read.", "/Devices/SATA%d/Port%d/ReadBytes", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of data written.", "/Devices/SATA%d/Port%d/WrittenBytes", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Number of processed I/O requests per second.", "/Devices/SATA%d/Port%d/IORequestsPerSecond", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_WITH_STATISTICS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time to process one request.", "/Devices/SATA%d/Port%d/ProfileProcessTime", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time to map the guest buffers into R3.", "/Devices/SATA%d/Port%d/ProfileMapIntoR3", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time for the read/write operation to complete.", "/Devices/SATA%d/Port%d/ProfileReadWrite", iInstance, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
54cd98940b9280fb048259ef5d361865aa559fb4vboxsync "Amount of time to destroy the scatter gather list and free associated ressources.", "/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;
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Generate a default serial number. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szSerial[AHCI_SERIAL_NUMBER_LENGTH+1];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTUUID Uuid;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlock)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTUuidClear(&Uuid);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%x-1a2b3c4d",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Get user config if present using defaults otherwise. */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync PCFGMNODE pCfgNode = CFGMR3GetChild(pCfg, szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync szSerial);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: \"SerialNumber\" is longer than 20 bytes"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read \"SerialNumber\" as string"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "FirmwareRevision", pAhciPort->szFirmwareRevision, sizeof(pAhciPort->szFirmwareRevision),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "1.0");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: \"FirmwareRevision\" is longer than 8 bytes"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read \"FirmwareRevision\" as string"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ModelNumber", pAhciPort->szModelNumber, sizeof(pAhciPort->szModelNumber),
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync pAhciPort->fATAPI ? "VBOX CD-ROM" : "VBOX HARDDISK");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: \"ModelNumber\" is longer than 40 bytes"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read \"ModelNumber\" as string"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync /* There are three other identification strings for CD drives used for INQUIRY */
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (pAhciPort->fATAPI)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync {
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIVendorId", pAhciPort->szInquiryVendorId, sizeof(pAhciPort->szInquiryVendorId),
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync "VBOX");
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (RT_FAILURE(rc))
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync {
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: \"ATAPIVendorId\" is longer than 16 bytes"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: failed to read \"ATAPIVendorId\" as string"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync }
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIProductId", pAhciPort->szInquiryProductId, sizeof(pAhciPort->szInquiryProductId),
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync "CD-ROM");
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (RT_FAILURE(rc))
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync {
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: \"ATAPIProductId\" is longer than 16 bytes"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: failed to read \"ATAPIProductId\" as string"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync }
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync rc = CFGMR3QueryStringDef(pCfgNode, "ATAPIRevision", pAhciPort->szInquiryRevision, sizeof(pAhciPort->szInquiryRevision),
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync "1.0");
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (RT_FAILURE(rc))
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync {
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_INVALID_PARAMETER,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: \"ATAPIRevision\" is longer than 4 bytes"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync N_("PIIX3 configuration error: failed to read \"ATAPIRevision\" as string"));
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync }
75ef08b33f9c67a8dd50748ece1117aed8098d51vboxsync }
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#ifdef DEBUG
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync for (uint32_t j = 0; j < AHCI_NR_COMMAND_SLOTS; j++)
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync pAhciPort->ahciIOTasks[j] = 0xff;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
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))
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Setup IDE emulation.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * We only emulate the I/O ports but not bus master DMA.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the configuration values are not found the setup of the ports is as follows:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Primary Master: Port 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Primary Slave: Port 1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Secondary Master: Port 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Secondary Slave: Port 3
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Setup I/O ports for the PCI device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[0].irq = 12;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[0].IOPortBase1 = 0x1e8;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[0].IOPortBase2 = 0x3e6;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[1].irq = 11;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[1].IOPortBase1 = 0x168;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->aCts[1].IOPortBase2 = 0x366;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync for (i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIATACONTROLLER pCtl = &pThis->aCts[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t iPortMaster, iPortSlave;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cbSSMState = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync static const char *s_apszDescs[RT_ELEMENTS(pThis->aCts)][RT_ELEMENTS(pCtl->aIfs)] =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync { "PrimaryMaster", "PrimarySlave" },
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync { "SecondaryMaster", "SecondarySlave" }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync };
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][0], &iPortMaster, 2 * i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szName[24];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(szName, sizeof(szName), "EmulatedATA%d", i);
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync rc = ataControllerInit(pDevIns, pCtl,
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync iPortMaster, pThis->ahciPort[iPortMaster].pDrvBase,
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync iPortSlave, pThis->ahciPort[iPortSlave].pDrvBase,
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync &cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led,
28bf3a52b172f5b6608ce5fbb3b1ccc1ef88115bvboxsync &pThis->ahciPort[iPortMaster].StatBytesRead,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pThis->ahciPort[iPortMaster].StatBytesWritten);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbTotalBufferSize += cbSSMState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase1, 8, (RTHCPTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciIOPortWrite1, ahciIOPortRead1, ahciIOPortWriteStr1, ahciIOPortReadStr1, "AHCI");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fR0Enabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase1, 8, (RTR0PTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI R0");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fGCEnabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, pCtl->IOPortBase1, 8, (RTGCPTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciIOPortWrite1", "ahciIOPortRead1", NULL, NULL, "AHCI GC");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pCtl->IOPortBase2, 1, (RTHCPTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciIOPortWrite2, ahciIOPortRead2, NULL, NULL, "AHCI");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fR0Enabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pCtl->IOPortBase2, 1, (RTR0PTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI R0");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->fGCEnabled)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, pCtl->IOPortBase2, 1, (RTGCPTR)i,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "ahciIOPortWrite2", "ahciIOPortRead2", NULL, NULL, "AHCI GC");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ~0,
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 */