DevAHCI.cpp revision b5d837811bf21f30a31748bbbcb28ee562bb2355
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VBox storage devices:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * AHCI controller device (disk).
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Implements the AHCI standard 1.1
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * additional information or have any questions.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This component implements an AHCI SATA controller.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The device is split into two parts. The first part implements the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * register interface for the guest and the second one does the data transfer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * the preferred one.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The second implements the I/O ports used for booting from the hard disk
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * port or using the new async completion interface which is still under development.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
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_SAVED_STATE_VERSION 2
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_NR_OF_ALLOWED_BIGGER_LISTS 100
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_SERIAL_NUMBER_LENGTH 20
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_FIRMWARE_REVISION_LENGTH 8
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define AHCI_MODEL_NUMBER_LENGTH 40
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t uTxDir;
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 /** Number of scatter gather list entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** How many entries would fit into the sg list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cSGListSize;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the first entry of the scatter gather list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDATASEG pSGListHead;
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} AHCIPORTTASKSTATE, *PAHCIPORTTASKSTATE;
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
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];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment5;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} AHCIPort, *PAHCIPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Main AHCI device state.
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The base interface */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMIBASE IBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Status Port - Leds interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMILEDPORTS ILeds;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** 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
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The critical section. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMCRITSECT lock;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Number of usable ports on this controller. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t cPortsImpl;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if HC_ARCH_BITS == 64
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t Alignment7;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} AHCI, *PAHCI;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* Scatter gather list entry. */
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);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciMMIOMap(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpMMIORegisterGC(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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciLegacyFakeIORangeMap(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterGC(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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciStatus_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/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Queries an interface to the driver.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns Pointer to interface.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns NULL if the interface was not supported by the device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pInterface Pointer to ATADevState::IBase.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param enmInterface The requested interface identification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (enmInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_BASE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhci->IBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_LED_PORTS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhci->ILeds;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Query interface method for the AHCI port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void *) ahciPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (enmInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_BASE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhciPort->IBase;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_BLOCK_PORT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhciPort->IPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_BLOCK_ASYNC_PORT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhciPort->IPortAsync;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case PDMINTERFACE_MOUNT_NOTIFY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return &pAhciPort->IMountNotify;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->pDevInsRC += offDelta;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Relocate every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pAhciRC += offDelta;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDevInsRC += offDelta;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Relocate emulated ATA controllers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerRelocate(&pAhci->aCts[i], offDelta);
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync | ((pAhciPortTaskState->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? 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 char aSerial[20];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTUUID Uuid;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock ? pAhciPort->pDrvBlock->pfnGetUuid(pAhciPort->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc) || RTUuidIsNull(&Uuid))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Generate a predictable serial for drives which don't have a UUID. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-1a2b3c4d",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->iLUN);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&p[0], sizeof(p));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataSCSIPadStr(aBuf + 8, "VBOX", 8);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataSCSIPadStr(aBuf + 16, "CD-ROM", 16);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataSCSIPadStr(aBuf + 32, "1.0", 4);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer in to the scatter gather list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], sizeof(aBuf));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, (void *)&aBuf[0], cbSize);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pcbData = 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create scatter gather list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Getting number of list elements failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rcSourceSink = g_apfnAtapiFuncs[iSourceSink](pAhciPortTaskState, pAhciPort, &cbTransfered);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = cbTransfered;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Destroying list failed rc=%Rrc\n", 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
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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("2352 read\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* @todo: This is quite difficult as the data transfer is not handled here
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync We need to add the sync bytes etc. here and modify the pointers
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync and size of the sg entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* sync bytes */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pbBuf++ = 0x00;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(pbBuf, 0xff, 11);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf += 11;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* MSF */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataLBA2MSF(pbBuf, i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf += 3;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *pbBuf++ = 0x01; /* mode 1 data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf += 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* ECC */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(pbBuf, 0, 288);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pbBuf += 288;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = iATAPILBA * 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = cSectors * 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
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{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = 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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_FROM_DEVICE;
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_FROM_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case 0xf8:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* read all data */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync atapiReadSectors(pAhciPort, pAhciPortTaskState, iATAPILBA, cSectors, 2352);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_FROM_DEVICE;
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 PVMREQ pReq;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync (PFNRT)pAhciPort->pDrvMount->pfnUnmount, 2, pAhciPort->pDrvMount, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertReleaseRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync VMR3ReqFree(pReq);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
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);
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);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sdbFis[1] = uFinishedTasks;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
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_SDBS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Check if we should assert an interrupt */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->regIE & AHCI_PORT_IE_SDBE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAssertIntr = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Update registers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->regTFD = (pAhciPortTaskState->uATARegError << 8) | pAhciPortTaskState->uATARegStatus;
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
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(cSGList * sizeof(PDMDATASEG));
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPortTaskState->pvBufferUnaligned)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_NO_MEMORY;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbBufferUnaligned = cbUnaligned;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Make debugging easier. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
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
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cSGEntriesR3 = 0; /* Needed scatter gather list entries in R3. */
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDATASEG pSGEntryCurr = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDATASEG 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
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;
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));
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
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++;
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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Creating mapping failed rc=%Rrc\n", rc));
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++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Creating mapping failed rc=%Rrc\n", rc));
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++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoPrev = pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGInfoCurr++;
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;
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
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
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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
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 *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDATASEG pSGEntry = &pAhciPortTaskState->pSGListHead[cSGEntry];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8Buf = (uint8_t *)pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cSGEntry < pAhciPortTaskState->cSGEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbToCopy = (cbBuf < pSGEntry->cbSeg) ? cbBuf : pSGEntry->cbSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbBuf -= cbToCopy;
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(!cbBuf, ("There is still data in the buffer\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Free system resources occupied by the scatter gather list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
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->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Actual.s.fReading = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
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));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!cOutstandingTasks)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
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.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return ahciTransferComplete(pAhciPort, pAhciPortTaskState);
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciProcessCmd(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, uint8_t *pCmdFis)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = PDMBLOCKTXDIR_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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pCmdFis[AHCI_CMDFIS_CMD])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_IDENTIFY_DEVICE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint16_t u16Temp[256];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Fill the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciIdentifySS(pAhciPort, u16Temp);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create scatter gather list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Copy the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Copying failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pCmdHdr->u32PRDBC = sizeof(u16Temp);
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
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:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = 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:
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_FROM_DEVICE;
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_TO_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_READ_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_FROM_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_WRITE_FPDMA_QUEUED:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMBLOCKTXDIR_TO_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* All not implemented commands go below. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SECURITY_FREEZE_LOCK:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SMART:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_NV_CACHE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case ATA_SLEEP: /* Powermanagement not supported. */
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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uTxDir = (pAhciPortTaskState->cmdHdr.u32DescInf & AHCI_CMDHDR_W) ? PDMBLOCKTXDIR_TO_DEVICE : PDMBLOCKTXDIR_FROM_DEVICE;
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int iTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATE pAhciPortTaskState;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* 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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iTxDir != PDMBLOCKTXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGEntries,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cbTransfer,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VINF_VD_ASYNC_IO_FINISHED)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
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);
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int iTxDir;
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iTxDir != PDMBLOCKTXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t uOffset;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDATASEG pSegCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_START(&pAhciPort->StatProfileReadWrite, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Cleanup. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_LIKELY(!pAhciPort->fPortReset))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegError = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
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--;
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync 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 }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Destroy a driver instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * resources can be freed correctly.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciDestruct(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned iActPort = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * At this point the async I/O thread is suspended and will not enter
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * this module again. So, no coordination is needed here and PDM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * will take care of terminating and cleaning up the thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (PDMCritSectIsInitialized(&pAhci->lock))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Destruct every port\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pAsyncIOThread)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy the event semaphore. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Free all cached tasks. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->aCachedTasks[i])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->aCachedTasks[i]->pSGListHead)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->aCachedTasks[i]->paSGEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(pAhciPort->aCachedTasks[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Destroy emulated ATA controllers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerDestroy(&pAhci->aCts[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMR3CritSectDelete(&pAhci->lock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Configure the attached device for a port.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pAhciPort The port for which the device is to be configured.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int ahciConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMBLOCKTYPE enmType;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Query the block and blockbios interfaces.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->pDrvBlock)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_PDM_MISSING_INTERFACE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!pAhciPort->pDrvBlockBios)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_PDM_MISSING_INTERFACE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Try to get the optional async block interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate type.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( enmType != PDMBLOCKTYPE_HARD_DISK
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && enmType != PDMBLOCKTYPE_CDROM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && enmType != PDMBLOCKTYPE_DVD)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync && !pAhciPort->pDrvMount)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_INTERNAL_ERROR;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fATAPI)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cCylinders = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cHeads = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cSectors = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pAhciPort->PCHSGeometry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cCylinders = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cHeads = 16; /*??*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cSectors = 63; /*??*/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertRC(rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( pAhciPort->PCHSGeometry.cCylinders == 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pAhciPort->PCHSGeometry.cHeads == 0
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || pAhciPort->PCHSGeometry.cSectors == 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cHeads = 16;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cSectors = 63;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Set the disk geometry information. Ignore errors. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync &pAhciPort->PCHSGeometry);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->cTotalSectors));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic bool ahciWaitForAllAsyncIOIsFinished(PPDMDEVINS pDevIns, unsigned cMillies)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint64_t u64Start;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync bool fAllFinished;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync u64Start = RTTimeMilliTS();
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (;;)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAllFinished = true;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort = &pAhci->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->pDrvBase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pAhciPort->fAsyncInterface)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAllFinished &= (pAhciPort->uActTasksActive == 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync fAllFinished &= ((pAhciPort->uActTasksActive == 0) && (pAhciPort->fAsyncIOThreadIdle));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!fAllFinished)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if ( fAllFinished
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync || RTTimeMilliTS() - u64Start >= cMillies)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Sleep a bit. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTThreadSleep(100);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return fAllFinished;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("One port is still active\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ataControllerSavePrep(&pAhci->aCts[i], pSSM);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ataControllerLoadPrep(&pAhci->aCts[i], pSSM);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Suspend notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciSuspend(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("AHCI: One port is still active\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerSuspend(&pAhci->aCts[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Resume notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciResume(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("%s:\n", __FUNCTION__));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerResume(&pAhci->aCts[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Saves a state of the AHCI device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pSSMHandle The handle to save the state to.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(!pAhci->f8ByteMMIO4BytesWrittenSuccessfully);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* First the main device structure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaCap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaCtrl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaIs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaPi);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaVs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaCccCtl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->regHbaCccPorts);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU8(pSSMHandle, pAhci->uCccPortNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU64(pSSMHandle, pAhci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->uCccNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->uCccCurrentNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->u32PortsInterrupted);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->fReset);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->f64BitAddr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->fR0Enabled);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->fGCEnabled);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Assert(pAhci->ahciPort[i].uActTasksActive == 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCLBU);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regFBU);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrClb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutGCPhys(pSSMHandle, pAhci->ahciPort[i].GCPhysAddrFb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regIE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCMD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regTFD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSIG);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSSTS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSCTL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSERR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regSACT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].regCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cCylinders);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cHeads);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].PCHSGeometry.cSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU64(pSSMHandle, pAhci->ahciPort[i].cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].cMultSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uATATransferMode);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fResetDevice);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].ahciIOTasks[uActTask]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActWritePos);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU8(pSSMHandle, pAhci->ahciPort[i].uActReadPos);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fPoweredOn);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutBool(pSSMHandle, pAhci->ahciPort[i].fSpunUp);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32TasksFinished);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3PutU32(pSSMHandle, pAhci->ahciPort[i].u32QueuedTasksFinished);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now the emulated ata controllers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ataControllerSaveExec(&pAhci->aCts[i], pSSMHandle);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Loads a saved AHCI device state.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pSSMHandle The handle to the saved state.
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync * @param uVersion The data unit version number.
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync * @param uPhase The data phase.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsyncstatic DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPhase)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t u32;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint32_t i;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync if (uVersion != AHCI_SAVED_STATE_VERSION)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync Assert(uPhase == SSM_PHASE_FINAL); NOREF(uPhase);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Restore data. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* First the main device structure. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaCap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaCtrl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaIs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaPi);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaVs);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccCtl);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->regHbaCccPorts);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU8(pSSMHandle, &pAhci->uCccPortNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU64(pSSMHandle, &pAhci->uCccTimeout);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->uCccNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->uCccCurrentNr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->u32PortsInterrupted);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->fReset);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->f64BitAddr);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->fR0Enabled);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->fGCEnabled);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now every port. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCLBU);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFB);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regFBU);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrClb);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetGCPhys(pSSMHandle, (RTGCPHYS *)&pAhci->ahciPort[i].GCPhysAddrFb);
23631945c9cb3df68ca51c69ed0b77e90164b402vboxsync SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regIS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regIE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regCMD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regTFD);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSIG);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSSTS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSCTL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].regSERR);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regSACT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].regCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cCylinders);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cHeads);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].PCHSGeometry.cSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU64(pSSMHandle, &pAhci->ahciPort[i].cTotalSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, &pAhci->ahciPort[i].cMultSectors);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uATATransferMode);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fResetDevice);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint8_t uActTask = 0; uActTask < AHCI_NR_COMMAND_SLOTS; uActTask++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU8(pSSMHandle, (uint8_t *)&pAhci->ahciPort[i].ahciIOTasks[uActTask]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActWritePos);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU8(pSSMHandle, &pAhci->ahciPort[i].uActReadPos);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fPoweredOn);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetBool(pSSMHandle, &pAhci->ahciPort[i].fSpunUp);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32TasksFinished);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SSMR3GetU32(pSSMHandle, (uint32_t *)&pAhci->ahciPort[i].u32QueuedTasksFinished);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Now the emulated ata controllers. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync int rc = ataControllerLoadExec(&pAhci->aCts[i], pSSMHandle);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync int rc = SSMR3GetU32(pSSMHandle, &u32);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciDetach(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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciAttach(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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciConfigureLUN(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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Reset notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciReset(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("AHCI: One port is still active\n"));
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]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Poweroff notification.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns Pointer to the device instance
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) ahciPowerOff(PPDMDEVINS pDevIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!ahciWaitForAllAsyncIOIsFinished(pDevIns, 20000))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("AHCI: One port is still active\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ataControllerPowerOff(&pAhci->aCts[i]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Construct a device instance for a VM.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDevIns The device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * If the registration structure is needed, pDevIns->pDevReg points to it.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param iInstance Instance number. Use this to figure out which registers and such to use.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The device number is also found in pDevIns->iInstance, but since it's
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * likely to be freqently used PDM passes it as parameter.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * of the device instance. It's also found in pDevIns->pCfgHandle, but like
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * iInstance it's expected to be used a bit in this function.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) ahciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
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;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Validate and read configuration.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "R0Enabled\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PrimaryMaster\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PrimarySlave\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SecondaryMaster\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SecondarySlave\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "PortCount\0"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "UseAsyncInterfaceIfAvailable\0");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: unknown option specified"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryBoolDef(pCfgHandle, "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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryBoolDef(pCfgHandle, "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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryU32Def(pCfgHandle, "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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryU32Def(pCfgHandle, "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"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryU32Def(pCfgHandle, "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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI I/O region for BMDMA"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciMMIOMap);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("AHCI cannot register PCI memory region for registers"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pThis->lock, "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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->IBase.pfnQueryInterface = ahciStatus_QueryInterface;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->ILeds.pfnQueryStatusLed = ahciStatus_QueryStatusLed;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Create the transmit queue.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
83df31c21044349888e688d5f793ce39007e6693vboxsync 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,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Number of DMA transfers.", "/Devices/SATA/Port%d/DMA", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of data read.", "/Devices/SATA/Port%d/ReadBytes", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of data written.", "/Devices/SATA/Port%d/WrittenBytes", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatIORequestsPerSecond, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Number of processed I/O requests per second.", "/Devices/SATA/Port%d/IORequestsPerSecond", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef VBOX_WITH_STATISTICS
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileProcessTime, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of time to process one request.", "/Devices/SATA/Port%d/ProfileProcessTime", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileMapIntoR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of time to map the guest buffers into R3.", "/Devices/SATA/Port%d/ProfileMapIntoR3", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileReadWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of time for the read/write operation to complete.", "/Devices/SATA/Port%d/ProfileReadWrite", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pAhciPort->StatProfileDestroyScatterGatherList, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_NS_PER_CALL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Amount of time to destroy the scatter gather list and free associated ressources.", "/Devices/SATA/Port%d/ProfileDestroyScatterGatherList", 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];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTStrPrintf(szName, sizeof(szName), "Port%d", i);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PAHCIPort pAhciPort = &pThis->ahciPort[i];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Init interfaces.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->IBase.pfnQueryInterface = ahciPortQueryInterface;
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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = ahciConfigureLUN(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. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, 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),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "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
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pAhciPort->ahciIOTasks[i] = 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))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryU32Def(pCfgHandle, 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
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = CFGMR3QueryU32Def(pCfgHandle, 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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterGC(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 {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync rc = PDMDevHlpIOPortRegisterGC(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,
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync NULL, NULL, NULL,
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync ahciSavePrep, ahciSaveExec, NULL,
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync ahciLoadPrep, ahciLoadExec, NULL);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciReset(pDevIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The device registration structure.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncconst PDMDEVREG g_DeviceAHCI =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32Version */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_VERSION,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* szDeviceName */
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 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciConstruct,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDestruct */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciDestruct,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnRelocate */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciRelocate,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnIOCtl */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOn */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciReset,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSuspend */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciSuspend,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnResume */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciResume,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnAttach */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciAttach,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDetach */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciDetach,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnQueryInterface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnInitComplete */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOff */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ahciPowerOff,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSoftReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32VersionEnd */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DEVREG_VERSION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* IN_RING3 */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */