DevAHCI.cpp revision 6da7ae3144a7be1443dd37052b24370bf210fda1
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
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];
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATAPI sense key. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uATAPISenseKey;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** ATAPI additional sens code. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uATAPIASC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t cNotifiedMediaChange;
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
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
493189f09538207d222d646e7ddc76adb3c438eevboxsync uint32_t u32Alignment5[4];
493189f09538207d222d646e7ddc76adb3c438eevboxsync
493189f09538207d222d646e7ddc76adb3c438eevboxsync#if HC_ARCH_BITS == 32
493189f09538207d222d646e7ddc76adb3c438eevboxsync uint32_t u32Alignment6;
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__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPCISetIrqNoWait(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__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPCISetIrqNoWait(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__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPCISetIrqNoWait(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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPCISetIrqNoWait(ahci->CTX_SUFF(pDevIns), 0, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpPCISetIrqNoWait(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
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATAPISenseKey = SCSI_SENSE_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATAPIASC = SCSI_ASC_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void atapiCmdError(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = uATAPISenseKey << 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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATAPISenseKey = uATAPISenseKey;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->uATAPIASC = uATAPIASC;
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 *);
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 *);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync//static 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,
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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync //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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiIdentifySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiInquirySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiMechanismStatusSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiModeSenseErrorRecoverySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiModeSenseCDStatusSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadCapacitySS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadDiscInformationSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCNormalSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCMultiSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTOCRawSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadTrackInformationSS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiRequestSenseSS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync //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[75] = RT_H2LE_U16(1); /* queue depth 1 */
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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
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 uint8_t aBuf[18];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&aBuf[0], 0, 18);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[0] = 0x70 | (1 << 7);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[2] = pAhciPort->uATAPISenseKey;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[7] = 10;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync aBuf[12] = pAhciPort->uATAPIASC;
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 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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiDoTransfer(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, ATAPIFN iSourceSink)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int cbTransfered;
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);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync rc = ahciScatterGatherListCreateSafe(pAhciPort, pAhciPortTaskState, false, 0);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync AssertRC(rc);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int atapiParseCmdVirtualATAPI(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync int iTxDir = PDMBLOCKTXDIR_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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2048);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync iTxDir = 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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync iTxDir = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xf8:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* read all data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync iTxDir = AHCITXDIR_READ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI ATAPI: LUN#%d: CD-ROM sector format not supported\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = 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
4bc520c260844219a996679e2b2b0baaa5f47881vboxsync rc = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
4bc520c260844219a996679e2b2b0baaa5f47881vboxsync (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
b86f470658aa3bbcf32457fa815c99f1e576141avboxsync Assert(RT_SUCCESS(rc) || (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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_SUCCESS(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdOK(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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-- ;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiCmdError(pAhciPort, pAhciPortTaskState, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
99195a756879b8f6a7810e5b06ea505d766d3651vboxsync return iTxDir;
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. */
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 pAhciPortTaskState The state of the last task.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param fInterrupt If an interrupt should be asserted.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t sdbFis[2];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAssertIntr = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr);
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
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Set start address of the entries. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync GCPhysAddrPRDTLEntryStart = AHCI_RTGCPHYS_FROM_U32(pCmdHdr->u32CmdTblAddrUp, pCmdHdr->u32CmdTblAddr) + AHCI_CMDHDR_PRDT_OFFSET;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync do
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync {
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cSGLEntriesGCRead = (cSGLEntriesGCLeft < RT_ELEMENTS(aSGLEntry)) ? cSGLEntriesGCLeft : RT_ELEMENTS(aSGLEntry);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cSGLEntriesGCLeft -= cSGLEntriesGCRead;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Read the SG entries. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync PDMDevHlpPhysRead(pDevIns, GCPhysAddrPRDTLEntryStart, &aSGLEntry[0], cSGLEntriesGCRead * sizeof(SGLEntry));
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync for (cActualSGEntry = 0; cActualSGEntry < cSGLEntriesGCRead; cActualSGEntry++)
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync cbSGBuffers += (aSGLEntry[cActualSGEntry].u32DescInf & SGLENTRY_DESCINF_DBC) + 1;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync /* Set address to the next entries to read. */
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync GCPhysAddrPRDTLEntryStart += cSGLEntriesGCRead * sizeof(SGLEntry);
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync } while (cSGLEntriesGCLeft);
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
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync * data to transfer and the amount of guest memory reserved can differ
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync */
18539616b4498fd2e308fef0d3038afa5ece11edvboxsync if (pAhciPortTaskState->pfnPostProcess)
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;
4946f90c5c7016131555f0c925091d4ede6bdde0vboxsync int 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 }
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync ASMAtomicCmpXchgPtr((void * volatile *)&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));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr))
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
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (!cOutstandingTasks)
b28326220af580dde4a61f15930f51fe584dc896vboxsync ahciSendSDBFis(pAhciPort, 0, pAhciPortTaskState, 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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
824104c3b60b9c8d5c03c40658e33ecd6c4fa9e8vboxsync int rc2 = atapiParseCmdVirtualATAPI(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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"));
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->pTaskErr, NULL);
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync if (pTaskErr)
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync {
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[0] = pTaskErr->fQueued ? (1 << 7) | pTaskErr->uTag : 0;
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
6da7ae3144a7be1443dd37052b24370bf210fda1vboxsync aBuf[511] = ~uChkSum;
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;
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;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->fQueued)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicIncU32(&pAhciPort->uActTasksActive);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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
b28326220af580dde4a61f15930f51fe584dc896vboxsync bool 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))
8f8c8ff0bfe182cff047f8c028b2546b25087d44vboxsync ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, 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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Called when a media is mounted.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciMountNotify(PPDMIMOUNTNOTIFY pInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: changing LUN#%d\n", __FUNCTION__, pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Ignore the call if we're called while being attached. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->pDrvBlock)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Initialize registers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD |= AHCI_PORT_CMD_CPS;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSERR |= AHCI_PORT_SERR_N;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Called when a media is unmounted
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIMOUNTNOTIFY_2_PAHCIPORT(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cTotalSectors = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Inform the guest about the removed device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSSTS = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regCMD &= ~AHCI_PORT_CMD_CPS;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_CPDS | AHCI_PORT_IS_PRCS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regSERR |= AHCI_PORT_SERR_N;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_CPDE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciHbaSetInterrupt(pAhciPort->CTX_SUFF(pAhci), pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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
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);
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;
0d18f5b89ac6eb5d44c3e3d5453e55ab8cd7e804vboxsync LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
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
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
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char szName[24];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(szName, sizeof(szName), "Port%d", iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlockAsync)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fAsyncInterface = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fAsyncInterface = false;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create event semaphore. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventCreate(&pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Failed to create event semaphore for %s.\n", __FUNCTION__, szName));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create the async IO thread. */
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync RTTHREADTYPE_IO, szName);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
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. */
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ataControllerInit(pDevIns, pCtl, pThis->ahciPort[iPortMaster].pDrvBase, pThis->ahciPort[iPortSlave].pDrvBase,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &cbSSMState, szName, &pThis->ahciPort[iPortMaster].Led, &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
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 */