DevATA.cpp revision 94b9fffbd2877518c6e88b2ae3489c64dd4a770a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** @file
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * VBox storage devices:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA/ATAPI controller device (disk and cdrom).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Copyright (C) 2006-2007 innotek GmbH
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * available from http://www.virtualbox.org. This file is free software;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * General Public License as published by the Free Software Foundation,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync* Header Files *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync*******************************************************************************/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define LOG_GROUP LOG_GROUP_DEV_IDE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/pdmdev.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/assert.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/string.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <iprt/uuid.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <iprt/semaphore.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <iprt/thread.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <iprt/time.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync# include <iprt/alloc.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/critsect.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <iprt/asm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/stam.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/mm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/pgm.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include <VBox/scsi.h>
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include "Builtins.h"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include "PIIX3ATABmDma.h"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#include "ide.h"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Maximum number of sectors to transfer in a READ/WRITE MULTIPLE request.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Set to 1 to disable multi-sector read support. According to the ATA
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * specification this must be a power of 2 and it must fit in an 8 bit
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * value. Thus the only valid values are 1, 2, 4, 8, 16, 32, 64 and 128.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATA_MAX_MULT_SECTORS 128
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest PIO mode supported by the drive.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATA_PIO_MODE_MAX 4
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest MDMA mode supported by the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATA_MDMA_MODE_MAX 2
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Fastest UDMA mode supported by the drive.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#define ATA_UDMA_MODE_MAX 6
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The SSM saved state version.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATA_SAVED_STATE_VERSION 16
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** The maximum number of release log entries per device. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define MAX_LOG_REL_ERRORS 1024
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct ATADevState {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether the current command uses LBA48 mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fLBA48;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether this drive implements the ATAPI command set. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fATAPI;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Set if this interface has asserted the IRQ. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fIrqPending;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Currently configured number of sectors in a multi-sector transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t cMultSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** PCHS disk geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cCHSCylinders, cCHSHeads, cCHSSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Total number of sectors on this disk. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t cTotalSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Number of sectors to transfer per IRQ. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectorsPerIRQ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: feature (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegFeature;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: feature, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegFeatureHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 1: error (read-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegError;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 2: sector count (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 2: sector count, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegNSectorHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 3: sector (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 3: sector, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegSectorHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 4: cylinder low (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 4: cylinder low, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegLCylHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 5: cylinder high (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 5: cylinder high, high order byte. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegHCylHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 6: select drive/head (read/write). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegSelect;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 7: status (read-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegStatus;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI register 7: command (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegCommand;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI drive control register (write-only). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATARegDevCtl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Currently active transfer mode (MDMA/UDMA) and speed. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATATransferMode;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Current transfer direction. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uTxDir;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Index of callback for begin transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iBeginTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Index of callback for source/sink of data. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iSourceSink;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether the current command transfers data in DMA mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fDMA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Set to indicate that ATAPI transfer semantics must be used. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fATAPITransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Total ATA/ATAPI transfer size, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Elementary ATA/ATAPI transfer size, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Current read/write buffer position, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iIOBufferCur;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** First element beyond end of valid buffer content, shared PIO/DMA. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iIOBufferEnd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI current PIO read/write transfer position. Not shared with DMA for safety reasons. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iIOBufferPIODataStart;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATA/ATAPI current PIO read/write transfer end. Not shared with DMA for safety reasons. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iIOBufferPIODataEnd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current LBA position. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current sector size. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI current command. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI sense key. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATAPISenseKey;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** ATAPI additional sense code. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATAPIASC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** HACK: Countdown till we report a newly unmounted drive as mounted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t cNotifiedMediaChange;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The status LED state for this drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMLED Led;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Size of I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbIOBuffer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3R0PTRTYPE(uint8_t *) pbIOBufferHC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the I/O buffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPTRTYPE(uint8_t *) pbIOBufferGC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if HC_ARCH_BITS == 64 && GC_ARCH_BITS != 64
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPTR Aligmnent0; /**< Align the statistics at an 8-byte boundrary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * No data that is part of the saved state after this point!!!!!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATA DMA commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatATADMA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATA PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatATAPIO;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATAPI PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatATAPIDMA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Release statistics: number of ATAPI PIO commands. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatATAPIPIO;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of read operations and the time spent reading. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMPROFILEADV StatReads;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of bytes read. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatBytesRead;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of write operations and the time spent writing. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMPROFILEADV StatWrites;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of bytes written. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMCOUNTER StatBytesWritten;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Statistics: number of flush operations and the time spend flushing. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMPROFILE StatFlushes;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Enable passing through commands directly to the ATAPI drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fATAPIPassthrough;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Number of errors we've reported to the release log.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is to prevent flooding caused by something going horribly wrong.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this value against MAX_LOG_REL_ERRORS in places likely to cause floods
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * like the ones we currently seeing on the linux smoke tests (2006-11-10). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cErrors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Timestamp of last started command. 0 if no command pending. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64CmdTS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's base interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3PTRTYPE(PPDMIBASE) pDrvBase;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's block interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3PTRTYPE(PPDMIBLOCK) pDrvBlock;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's block bios interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3PTRTYPE(PPDMIBLOCKBIOS) pDrvBlockBios;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to the attached driver's mount interface.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is NULL if the driver isn't a removable unit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3PTRTYPE(PPDMIMOUNT) pDrvMount;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The base interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMIBASE IBase;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The block port interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMIBLOCKPORT IPort;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The mount notify interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMIMOUNTNOTIFY IMountNotify;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The LUN #. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTUINT iLUN;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if HC_ARCH_BITS == 64
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTUINT Alignment2; /**< Align pDevInsHC correctly. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to controller instance. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync R3R0PTRTYPE(struct ATACONTROLLER *) pControllerHC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPTRTYPE(PPDMDEVINS) pDevInsGC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to controller instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync GCPTRTYPE(struct ATACONTROLLER *) pControllerGC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync} ATADevState;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct ATATransferRequest
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iBeginTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iSourceSink;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uTxDir;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync} ATATransferRequest;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct ATAAbortRequest
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t iIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fResetDrive;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync} ATAAbortRequest;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef enum
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Begin a new transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATA_AIO_NEW = 0,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Continue a DMA transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATA_AIO_DMA,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Continue a PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATA_AIO_PIO,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Reset the drives on current controller, stop all transfer activity. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATA_AIO_RESET_ASSERTED,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Reset the drives on current controller, resume operation. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATA_AIO_RESET_CLEARED,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Abort the current transfer of a particular drive. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATA_AIO_ABORT
09f4b412099acda62997fd82c8608075c453b3ebvboxsync} ATAAIO;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsynctypedef struct ATARequest
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATAAIO ReqType;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync union
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATATransferRequest t;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATAAbortRequest a;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync } u;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync} ATARequest;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsynctypedef struct ATACONTROLLER
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The base of the first I/O Port range. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTIOPORT IOPortBase1;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The base of the second I/O Port range. (0 if none) */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTIOPORT IOPortBase2;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The assigned IRQ. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTUINT irq;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Access critical section */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync PDMCRITSECT lock;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Selected drive. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t iSelectedIf;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The interface on which to handle async I/O. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t iAIOIf;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The state of the async I/O thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t uAsyncIOState;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag indicating whether the next transfer is part of the current command. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fChainedTransfer;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Set when the reset processing is currently active on this controller. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fReset;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the current transfer needs to be redone. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fRedo;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the redo suspend has been finished. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fRedoIdle;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Flag whether the DMA operation to be redone is the final transfer. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fRedoDMALastDesc;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The BusMaster DMA state. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync BMDMAState BmDma;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to first DMA descriptor. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTGCPHYS pFirstDMADesc;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to last DMA descriptor. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTGCPHYS pLastDMADesc;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to current DMA buffer (for redo operations). */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTGCPHYS pRedoDMABuffer;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Size of current DMA buffer (for redo operations). */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint32_t cbRedoDMABuffer;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The ATA/ATAPI interfaces of this controller. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATADevState aIfs[2];
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to device instance. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Pointer to device instance. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync GCPTRTYPE(PPDMDEVINS) pDevInsGC;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Set when the destroying the device instance and the thread must exit. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint32_t volatile fShutdown;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The async I/O thread handle. NIL_RTTHREAD if no thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTTHREAD AsyncIOThread;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The event semaphore the thread is waiting on for requests. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync RTSEMEVENT AsyncIOSem;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The request queue for the AIO thread. One element is always unused. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ATARequest aAsyncIORequests[4];
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The position at which to insert a new request for the AIO thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t AsyncIOReqHead;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The position at which to get a new request for the AIO thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t AsyncIOReqTail;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint8_t Alignment3[2]; /**< Explicit padding of the 2 byte gap. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** Magic delay before triggering interrupts in DMA mode. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint32_t DelayIRQMillies;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The mutex protecting the request queue. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSEMMUTEX AsyncIORequestMutex;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /** The event semaphore the thread is waiting on during suspended I/O. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSEMEVENT SuspendIOSem;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if HC_ARCH_BITS == 32
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t Alignment0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Statistics */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync STAMCOUNTER StatAsyncOps;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint64_t StatAsyncMinWait;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uint64_t StatAsyncMaxWait;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync STAMCOUNTER StatAsyncTimeUS;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync STAMPROFILEADV StatAsyncTime;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAMPROFILE StatLockWait;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync} ATACONTROLLER, *PATACONTROLLER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsynctypedef struct PCIATAState {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIDEVICE dev;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** The controllers. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER aCts[2];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Pointer to device instance. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PPDMDEVINSR3 pDevIns;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Status Port - Base interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMIBASE IBase;
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync /** Status Port - Leds interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMILEDPORTS ILeds;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Partner of ILeds. */
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag whether GC is enabled. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fGCEnabled;
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync /** Flag whether R0 is enabled. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fR0Enabled;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** Flag indicating whether PIIX4 or PIIX3 is being emulated. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fPIIX4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool Alignment0[HC_ARCH_BITS == 64 ? 6 : 2]; /**< Align the struct size. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync} PCIATAState;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATADEVSTATE_2_CONTROLLER(pIf) ( (pIf)->CTXSUFF(pController) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATADEVSTATE_2_DEVINS(pIf) ( (pIf)->CTXSUFF(pDevIns) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define CONTROLLER_2_DEVINS(pController) ( (pController)->CTXSUFF(pDevIns) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBASE_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, IBase)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMILEDPORTS_2_PCIATASTATE(pInterface) ( (PCIATAState *)((uintptr_t)(pInterface) - RT_OFFSETOF(PCIATAState, ILeds)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBASE_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IBase)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIBLOCKPORT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IPort)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIMOUNT_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMount)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PDMIMOUNTNOTIFY_2_ATASTATE(pInterface) ( (ATADevState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ATADevState, IMountNotify)) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define PCIDEV_2_PCIATASTATE(pPciDev) ( (PCIATAState *)(pPciDev) )
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define ATACONTROLLER_IDX(pController) ( (pController) - PDMINS2DATA(CONTROLLER_2_DEVINS(pController), PCIATAState *)->aCts )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*******************************************************************************
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Internal Functions *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ******************************************************************************/
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync__BEGIN_DECLS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, unsigned *pcTransfer, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync__END_DECLS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataSetStatusValue(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (!pCtl->fReset)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->uATARegStatus = stat;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataSetStatus(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (!pCtl->fReset)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->uATARegStatus |= stat;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncDECLINLINE(void) ataUnsetStatus(ATADevState *s, uint8_t stat)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Freeze status register contents while processing RESET. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (!pCtl->fReset)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->uATARegStatus &= ~stat;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync#ifdef IN_RING3
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsynctypedef void (*PBeginTransferFunc)(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsynctypedef bool (*PSourceSinkFunc)(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataReadWriteSectorsBT(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataPacketBT(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void atapiCmdBT(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void atapiPassthroughCmdBT(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataIdentifySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataFlushSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataReadSectorsSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataWriteSectorsSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataExecuteDeviceDiagnosticSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool ataPacketSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiGetConfigurationSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiIdentifySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiInquirySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiMechanismStatusSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadCapacitySS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadTOCNormalSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadTOCMultiSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadTOCRawSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiRequestSenseSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic bool atapiPassthroughSS(ATADevState *);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Begin of transfer function indexes for g_apfnBeginTransFuncs.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsynctypedef enum ATAFNBT
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_NULL = 0,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_READ_WRITE_SECTORS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_PACKET,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_ATAPI_CMD,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_ATAPI_PASSTHROUGH_CMD,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_BT_MAX
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync} ATAFNBT;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Array of end transfer functions, the index is ATAFNET.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Make sure ATAFNET and this array match!
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const PBeginTransferFunc g_apfnBeginTransFuncs[ATAFN_BT_MAX] =
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync NULL,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataReadWriteSectorsBT,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataPacketBT,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiCmdBT,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiPassthroughCmdBT,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync};
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Source/sink function indexes for g_apfnSourceSinkFuncs.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsynctypedef enum ATAFNSS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_NULL = 0,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_IDENTIFY,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_FLUSH,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_READ_SECTORS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_WRITE_SECTORS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_PACKET,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_GET_CONFIGURATION,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_IDENTIFY,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_INQUIRY,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_MECHANISM_STATUS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_CAPACITY,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_DISC_INFORMATION,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_TOC_NORMAL,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_TOC_MULTI,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_TOC_RAW,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_READ_TRACK_INFORMATION,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_REQUEST_SENSE,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_ATAPI_PASSTHROUGH,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ATAFN_SS_MAX
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync} ATAFNSS;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Array of source/sink functions, the index is ATAFNSS.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Make sure ATAFNSS and this array match!
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const PSourceSinkFunc g_apfnSourceSinkFuncs[ATAFN_SS_MAX] =
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync NULL,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataIdentifySS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataFlushSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataReadSectorsSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataWriteSectorsSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataExecuteDeviceDiagnosticSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataPacketSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiGetConfigurationSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiIdentifySS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiInquirySS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiMechanismStatusSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiModeSenseErrorRecoverySS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiModeSenseCDStatusSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadCapacitySS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadDiscInformationSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadTOCNormalSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadTOCMultiSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadTOCRawSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiReadTrackInformationSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiRequestSenseSS,
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync atapiPassthroughSS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync};
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataDMARequest = { ATA_AIO_DMA, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataPIORequest = { ATA_AIO_PIO, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataResetARequest = { ATA_AIO_RESET_ASSERTED, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest ataResetCRequest = { ATA_AIO_RESET_CLEARED, };
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIOClearRequests(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqHead = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqTail = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIOPutRequest(PATACONTROLLER pCtl, const ATARequest *pReq)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert((pCtl->AsyncIOReqHead + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests) != pCtl->AsyncIOReqTail);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync memcpy(&pCtl->aAsyncIORequests[pCtl->AsyncIOReqHead], pReq, sizeof(*pReq));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqHead++;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqHead %= RT_ELEMENTS(pCtl->aAsyncIORequests);
bf7ab711aa3580b3a587dcbc4653fe78c99fff37vboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogBird(("ata: %x: signalling\n", pCtl->IOPortBase1));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (VBOX_FAILURE(rc))
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogBird(("ata: %x: schedule failed, rc=%Vrc\n", pCtl->IOPortBase1, rc));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemEventSignal(pCtl->AsyncIOSem);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic const ATARequest *ataAsyncIOGetCurrentRequest(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync const ATARequest *pReq;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pReq = &pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail];
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pReq = NULL;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync return pReq;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Remove the request with the given type, as it's finished. The request
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * is not removed blindly, as this could mean a RESET request that is not
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * yet processed (but has cleared the request queue) is lost.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pCtl Controller for which to remove the request.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param ReqType Type of the request to remove.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIORemoveCurrentRequest(PATACONTROLLER pCtl, ATAAIO ReqType)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail && pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail].ReqType == ReqType)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqTail++;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->AsyncIOReqTail %= RT_ELEMENTS(pCtl->aAsyncIORequests);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync}
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync/**
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * Dump the request queue for a particular controller. First dump the queue
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * contents, then the already processed entries, as long as they haven't been
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * overwritten.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync *
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * @param pCtl Controller for which to dump the queue.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsyncstatic void ataAsyncIODumpRequests(PATACONTROLLER pCtl)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync uint8_t curr;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync AssertRC(rc);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("PIIX3 ATA: Ctl#%d: request queue dump (topmost is current):\n", ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync curr = pCtl->AsyncIOReqTail;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync do
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (curr == pCtl->AsyncIOReqHead)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("PIIX3 ATA: Ctl#%d: processed requests (topmost is oldest):\n", ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync switch (pCtl->aAsyncIORequests[curr].ReqType)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync case ATA_AIO_NEW:
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("new transfer request, iIf=%d iBeginTransfer=%d iSourceSink=%d cbTotalTransfer=%d uTxDir=%d\n", pCtl->aAsyncIORequests[curr].u.t.iIf, pCtl->aAsyncIORequests[curr].u.t.iBeginTransfer, pCtl->aAsyncIORequests[curr].u.t.iSourceSink, pCtl->aAsyncIORequests[curr].u.t.cbTotalTransfer, pCtl->aAsyncIORequests[curr].u.t.uTxDir));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync case ATA_AIO_DMA:
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("dma transfer finished\n"));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync case ATA_AIO_PIO:
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("pio transfer finished\n"));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync case ATA_AIO_RESET_ASSERTED:
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("reset asserted request\n"));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync case ATA_AIO_RESET_CLEARED:
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("reset cleared request\n"));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case ATA_AIO_ABORT:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync LogRel(("abort request, iIf=%d fResetDrive=%d\n", pCtl->aAsyncIORequests[curr].u.a.iIf, pCtl->aAsyncIORequests[curr].u.a.fResetDrive));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync break;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync default:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync LogRel(("unknown request %d\n", pCtl->aAsyncIORequests[curr].ReqType));
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync curr = (curr + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync } while (curr != pCtl->AsyncIOReqTail);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Checks whether the request queue for a particular controller is empty
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * or whether a particular controller is idle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCtl Controller for which to check the queue.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fStrict If set then the controller is checked to be idle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataAsyncIOIsIdle(PATACONTROLLER pCtl, bool fStrict)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fIdle;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fIdle = pCtl->fRedoIdle;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fIdle)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync fIdle = (pCtl->AsyncIOReqHead == pCtl->AsyncIOReqTail);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fStrict)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fIdle &= (pCtl->uAsyncIOState == ATA_AIO_NEW);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return fIdle;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Send a transfer request to the async I/O thread.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param s Pointer to the ATA device state data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cbTotalTransfer Data transfer size.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param uTxDir Data transfer direction.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iBeginTransfer Index of BeginTransfer callback.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iSourceSink Index of SourceSink callback.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fChainedTransfer Whether this is a transfer that is part of the previous command/transfer.
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsyncstatic void ataStartTransfer(ATADevState *s, uint32_t cbTotalTransfer, uint8_t uTxDir, ATAFNBT iBeginTransfer, ATAFNSS iSourceSink, bool fChainedTransfer)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync{
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync ATARequest Req;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(PDMCritSectIsOwner(&pCtl->lock));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not issue new requests while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed new request as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* If the controller is already doing something else right now, ignore
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the command that is being submitted. Some broken guests issue commands
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: Ctl#%d: ignored command %#04x, controller state %d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegCommand, pCtl->uAsyncIOState));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 IDE: guest issued command %#04x while controller busy\n", s->uATARegCommand));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.ReqType = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fChainedTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.iIf = pCtl->iAIOIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.iIf = pCtl->iSelectedIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.cbTotalTransfer = cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.uTxDir = uTxDir;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.iBeginTransfer = iBeginTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.t.iSourceSink = iSourceSink;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_BUSY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fChainedTransfer = fChainedTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Kick the worker thread into action.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, new request\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &Req);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Send an abort command request to the async I/O thread.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param s Pointer to the ATA device state data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param fResetDrive Whether to reset the drive or just abort a command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataAbortCurrentCommand(ATADevState *s, bool fResetDrive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATARequest Req;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(PDMCritSectIsOwner(&pCtl->lock));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not issue new requests while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed aborting command as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.ReqType = ATA_AIO_ABORT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.a.iIf = pCtl->iSelectedIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Req.u.a.fResetDrive = fResetDrive;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_BUSY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, abort command on LUN#%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &Req);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSetIRQ(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PPDMDEVINS pDevIns = ATADEVSTATE_2_DEVINS(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(s->uATARegDevCtl & ATA_DEVCTL_DISABLE_IRQ))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ\n", __FUNCTION__, s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if the interrupt
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * line is asserted. It monitors the line for a rising edge. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->fIrqPending)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status |= BM_STATUS_INT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only actually set the IRQ line if updating the currently selected drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s == &pCtl->aIfs[pCtl->iSelectedIf])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo experiment with adaptive IRQ delivery: for reads it is
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * better to wait for IRQ delivery, as it reduces latency. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(pDevIns, pCtl->irq, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fIrqPending = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataUnsetIRQ(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PPDMDEVINS pDevIns = ATADEVSTATE_2_DEVINS(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(s->uATARegDevCtl & ATA_DEVCTL_DISABLE_IRQ))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ\n", __FUNCTION__, s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only actually unset the IRQ line if updating the currently selected drive. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s == &pCtl->aIfs[pCtl->iSelectedIf])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(pDevIns, pCtl->irq, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fIrqPending = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransferStart(ATADevState *s, uint32_t start, uint32_t size)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d start %d size %d\n", __FUNCTION__, s->iLUN, start, size));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataStart = start;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataEnd = start + size;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_DRQ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransferStop(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d\n", __FUNCTION__, s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPITransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fATAPITransfer = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataStart = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataEnd = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iBeginTransfer = ATAFN_BT_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransferLimitATAPI(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbLimit, cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbLimit = 0xfffe;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbLimit = s->uATARegLCyl | (s->uATARegHCyl << 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: byte count limit=%d\n", __FUNCTION__, cbLimit));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbLimit == 0xffff)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbLimit--;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->iIOBufferEnd - s->iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer > cbLimit)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* byte count limit must be even if this case */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbLimit & 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbLimit--;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cbLimit;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = cbTransfer >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataGetNSectors(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* 0 means either 256 (LBA28) or 65536 (LBA48) sectors. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fLBA48)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->uATARegNSector && !s->uATARegNSectorHOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 65536;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return s->uATARegNSectorHOB << 8 | s->uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->uATARegNSector)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return 256;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return s->uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPadString(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < cbSize; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (*pbSrc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbDst[i ^ 1] = *pbSrc++;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbDst[i ^ 1] = ' ';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < cbSize; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (*pbSrc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbDst[i] = *pbSrc++;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbDst[i] = ' ';
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U16(uint8_t *pbBuf, uint16_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = val >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[1] = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U24(uint8_t *pbBuf, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = val >> 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[1] = val >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataH2BE_U32(uint8_t *pbBuf, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = val >> 24;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[1] = val >> 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = val >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint16_t) ataBE2H_U16(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] << 8) | pbBuf[1];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataBE2H_U24(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataBE2H_U32(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync iATAPILBA += 150;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = (iATAPILBA / 75) / 60;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync pbBuf[1] = (iATAPILBA / 75) % 60;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = iATAPILBA % 75;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(uint32_t) ataMSF2LBA(const uint8_t *pbBuf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsyncstatic void ataCmdOK(ATADevState *s, uint8_t status)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = 0; /* Not needed by ATA spec, but cannot hurt. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_READY | status);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataCmdError(ATADevState *s, uint8_t uErrorCode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: code=%#x\n", __FUNCTION__, uErrorCode));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = uErrorCode;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->iIOBufferCur = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = 0;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->uTxDir = PDMBLOCKTXDIR_NONE;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->iBeginTransfer = ATAFN_BT_NULL;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataIdentifySS(ATADevState *s)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync{
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync uint16_t *p;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char aSerial[20];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync RTUUID Uuid;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync Assert(s->cbElementaryTransfer == 512);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (VBOX_FAILURE(rc) || RTUuidIsNull(&Uuid))
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Generate a predictable serial for drives which don't have a UUID. */
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync s->iLUN + ATADEVSTATE_2_DEVINS(s)->iInstance * 32,
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->IOPortBase1, pCtl->IOPortBase2);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync p = (uint16_t *)s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(p, 0, 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[0] = RT_H2LE_U16(0x0040);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[1] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[3] = RT_H2LE_U16(s->cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Block size; obsolete, but required for the BIOS. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[5] = RT_H2LE_U16(512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[6] = RT_H2LE_U16(s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[22] = RT_H2LE_U16(0); /* ECC bytes per sector */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 27), "VBOX HARDDISK", 40); /* model */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if ATA_MAX_MULT_SECTORS > 1
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[47] = RT_H2LE_U16(0x8000 | ATA_MAX_MULT_SECTORS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[48] = RT_H2LE_U16(1); /* dword I/O, used by the BIOS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[53] = RT_H2LE_U16(1 | 1 << 1 | 1 << 2); /* words 54-58,64-70,88 valid */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[54] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[55] = RT_H2LE_U16(s->cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[56] = RT_H2LE_U16(s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[57] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[58] = RT_H2LE_U16(RT_MIN(s->cCHSCylinders, 16383) * s->cCHSHeads * s->cCHSSectors >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cMultSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[59] = RT_H2LE_U16(0x100 | s->cMultSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cTotalSectors <= (1 << 28) - 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[60] = RT_H2LE_U16(s->cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[61] = RT_H2LE_U16(s->cTotalSectors >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report maximum number of sectors possible with LBA28 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[60] = RT_H2LE_U16(((1 << 28) - 1) & 0xffff);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[61] = RT_H2LE_U16(((1 << 28) - 1) >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cTotalSectors <= (1 << 28) - 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 12); /* supports FLUSH CACHE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync p[84] = RT_H2LE_U16(1 << 14);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (s->cTotalSectors <= (1 << 28) - 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[86] = RT_H2LE_U16(1 << 12); /* enabled FLUSH CACHE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[87] = RT_H2LE_U16(1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cTotalSectors > (1 << 28) - 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[100] = RT_H2LE_U16(s->cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[101] = RT_H2LE_U16(s->cTotalSectors >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[102] = RT_H2LE_U16(s->cTotalSectors >> 32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[103] = RT_H2LE_U16(s->cTotalSectors >> 48);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataFlushSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_NONE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!s->cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&s->StatFlushes, f);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnFlush(s->pDrvBlock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&s->StatFlushes, f);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiIdentifySS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint16_t *p;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync char aSerial[20];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTUUID Uuid;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer == 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock ? s->pDrvBlock->pfnGetUuid(s->pDrvBlock, &Uuid) : RTUuidClear(&Uuid);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc) || RTUuidIsNull(&Uuid))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Generate a predictable serial for drives which don't have a UUID. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%x-%04x%04x",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iLUN + ATADEVSTATE_2_DEVINS(s)->iInstance * 32,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->IOPortBase1, pCtl->IOPortBase2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTStrPrintf(aSerial, sizeof(aSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p = (uint16_t *)s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(p, 0, 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Removable CDROM, 50us response, 12 byte packets */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[0] = RT_H2LE_U16(2 << 14 | 5 << 8 | 1 << 7 | 2 << 5 | 0 << 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 10), aSerial, 20); /* serial number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[20] = RT_H2LE_U16(3); /* XXX: retired, cache type */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[21] = RT_H2LE_U16(512); /* XXX: retired, cache size in sectors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 23), "1.0", 8); /* firmware version */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPadString((uint8_t *)(p + 27), "VBOX CD-ROM", 40); /* model */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[49] = RT_H2LE_U16(1 << 11 | 1 << 9 | 1 << 8); /* DMA and LBA supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[50] = RT_H2LE_U16(1 << 14); /* No drive specific standby timer minimum */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[51] = RT_H2LE_U16(240); /* PIO transfer cycle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[52] = RT_H2LE_U16(240); /* DMA transfer cycle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[53] = RT_H2LE_U16(1 << 1 | 1 << 2); /* words 64-70,88 are valid */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[65] = RT_H2LE_U16(120); /* minimum DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[66] = RT_H2LE_U16(120); /* recommended DMA multiword tx cycle time */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[73] = RT_H2LE_U16(0x003e); /* ATAPI CDROM major */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[74] = RT_H2LE_U16(9); /* ATAPI CDROM minor */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[75] = RT_H2LE_U16(1); /* queue depth 1 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[80] = RT_H2LE_U16(0x7e); /* support everything up to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[81] = RT_H2LE_U16(0x22); /* conforms to ATA/ATAPI-6 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[82] = RT_H2LE_U16(1 << 4 | 1 << 9); /* supports packet command set and DEVICE RESET */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[83] = RT_H2LE_U16(1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[84] = RT_H2LE_U16(1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[85] = RT_H2LE_U16(1 << 4 | 1 << 9); /* enabled packet command set and DEVICE RESET */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[86] = RT_H2LE_U16(0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[87] = RT_H2LE_U16(1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p[93] = RT_H2LE_U16((1 | 1 << 1) << ((s->iLUN & 1) == 0 ? 0 : 8) | 1 << 13 | 1 << 14);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSetSignature(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSelect &= 0xf0; /* clear head */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* put signature */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSector = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = 0x14;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = 0xeb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = 0xff;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = 0xff;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
e6ad2e18e663b076aeabfec994947514566a7accvboxsyncstatic uint64_t ataGetSector(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
e6ad2e18e663b076aeabfec994947514566a7accvboxsync uint64_t iLBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uATARegSelect & 0x40)
e6ad2e18e663b076aeabfec994947514566a7accvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* any LBA variant */
e6ad2e18e663b076aeabfec994947514566a7accvboxsync if (s->fLBA48)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA48 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iLBA = ((uint64_t)s->uATARegHCylHOB << 40) |
e6ad2e18e663b076aeabfec994947514566a7accvboxsync ((uint64_t)s->uATARegLCylHOB << 32) |
e6ad2e18e663b076aeabfec994947514566a7accvboxsync ((uint64_t)s->uATARegSectorHOB << 24) |
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ((uint64_t)s->uATARegHCyl << 16) |
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ((uint64_t)s->uATARegLCyl << 8) |
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iLBA = ((s->uATARegSelect & 0x0f) << 24) | (s->uATARegHCyl << 16) |
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (s->uATARegLCyl << 8) | s->uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* CHS */
e6ad2e18e663b076aeabfec994947514566a7accvboxsync iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->cCHSHeads * s->cCHSSectors +
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync (s->uATARegSelect & 0x0f) * s->cCHSSectors +
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (s->uATARegSector - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return iLBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSetSector(ATADevState *s, uint64_t iLBA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cyl, r;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uATARegSelect & 0x40)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* any LBA variant */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fLBA48)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA48 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCylHOB = iLBA >> 40;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCylHOB = iLBA >> 32;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSectorHOB = iLBA >> 24;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = iLBA >> 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = iLBA >> 8;
dc959f60f6d3e0cba86f7da4d39aa475913a7e10vboxsync s->uATARegSector = iLBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* LBA */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | (iLBA >> 24);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = (iLBA >> 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = (iLBA >> 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSector = (iLBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* CHS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cyl = iLBA / (s->cCHSHeads * s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync r = iLBA % (s->cCHSHeads * s->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegHCyl = cyl >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegLCyl = cyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSelect = (s->uATARegSelect & 0xf0) | ((r / s->cCHSSectors) & 0x0f);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegSector = (r % s->cCHSSectors) + 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_START(&s->StatReads, r);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Actual.s.fReading = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_STOP(&s->StatReads, r);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesRead, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
e6ad2e18e663b076aeabfec994947514566a7accvboxsyncstatic int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
e6ad2e18e663b076aeabfec994947514566a7accvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_START(&s->StatWrites, w);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnWrite(s->pDrvBlock, u64Sector * 512, pvBuf, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Actual.s.fWriting = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_STOP(&s->StatWrites, w);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesWritten, cSectors * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataReadWriteSectorsBT(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors;
c58dc77ef4af214d7ae06910fa5ab18587d2ae08vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = s->cbTotalTransfer / 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cSectors > s->cSectorsPerIRQ)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = s->cSectorsPerIRQ * 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = cSectors * 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
c58dc77ef4af214d7ae06910fa5ab18587d2ae08vboxsyncstatic void ataWarningDiskFull(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Host disk full\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_DISKFULL",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataWarningFileTooBig(PPDMDEVINS pDevIns)
e6ad2e18e663b076aeabfec994947514566a7accvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync LogRel(("PIIX3 ATA: File too big\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_FILETOOBIG",
e6ad2e18e663b076aeabfec994947514566a7accvboxsync N_("Host system reported that the file size limit has been exceeded. VM execution is suspended. You need to move the file to a filesystem which allows bigger files"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataWarningISCSI(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: iSCSI target unavailable\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync false, "DevATA_ISCSIDOWN",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
e6ad2e18e663b076aeabfec994947514566a7accvboxsyncstatic bool ataReadSectorsSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
e6ad2e18e663b076aeabfec994947514566a7accvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t iLBA;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = s->cbElementaryTransfer / 512;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iLBA = ataGetSector(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataReadSectors(s, iLBA, s->CTXSUFF(pbIOBuffer), cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSector(s, iLBA + cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cbElementaryTransfer == s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_DISK_FULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_FILE_TOO_BIG)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* iSCSI connection abort (first error) or failure to reestablish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * connection (second error). Pause VM. On resume we'll retry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cErrors++ < MAX_LOG_REL_ERRORS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk read error (rc=%Vrc iSector=%#RX64 cSectors=%#RX32)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iLUN, rc, iLBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdError(s, ID_ERR);
e6ad2e18e663b076aeabfec994947514566a7accvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement redo for iSCSI */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
e6ad2e18e663b076aeabfec994947514566a7accvboxsyncstatic bool ataWriteSectorsSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t iLBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = s->cbElementaryTransfer / 512;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync Assert(cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iLBA = ataGetSector(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataWriteSectors(s, iLBA, s->CTXSUFF(pbIOBuffer), cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataSetSector(s, iLBA + cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_DISK_FULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_FILE_TOO_BIG)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* iSCSI connection abort (first error) or failure to reestablish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * connection (second error). Pause VM. On resume we'll retry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cErrors++ < MAX_LOG_REL_ERRORS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk write error (rc=%Vrc iSector=%#RX64 cSectors=%#RX32)\n",
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iLUN, rc, iLBA, cSectors));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataCmdError(s, ID_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement redo for iSCSI */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiCmdOK(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_READY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = (s->uATARegNSector & ~7)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | ((s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE) ? ATAPI_INT_REASON_IO : 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (!s->cbTotalTransfer ? ATAPI_INT_REASON_CD : 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATAPISenseKey = SCSI_SENSE_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATAPIASC = SCSI_ASC_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiCmdError(ATADevState *s, uint8_t uATAPISenseKey, uint8_t uATAPIASC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: sense=%#x asc=%#x\n", __FUNCTION__, uATAPISenseKey, uATAPIASC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = uATAPISenseKey << 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_READY | ATA_STAT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATAPISenseKey = uATAPISenseKey;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATAPIASC = uATAPIASC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uTxDir = PDMBLOCKTXDIR_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iBeginTransfer = ATAFN_BT_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiCmdBT(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fATAPITransfer = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = s->cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiPassthroughCmdBT(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* @todo implement an algorithm for correctly determining the read and
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * write sector size without sending additional commands to the drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This should be doable by saving processing the configuration requests
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * and replies. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t cmd = s->aATAPICmd[0];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cmd == SCSI_WRITE_10 || cmd == SCSI_WRITE_12 || cmd == SCSI_WRITE_AND_VERIFY_10)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t aModeSenseCmd[10];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t aModeSenseResult[16];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uDummySense;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = sizeof(aModeSenseResult);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[0] = SCSI_MODE_SENSE_10;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[1] = 0x08; /* disable block descriptor = 1 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[2] = (SCSI_PAGECONTROL_CURRENT << 6) | SCSI_MODEPAGE_WRITE_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[3] = 0; /* subpage code */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[4] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[5] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[6] = 0; /* reserved */
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync aModeSenseCmd[7] = cbTransfer >> 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[8] = cbTransfer & 0xff;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync aModeSenseCmd[9] = 0; /* control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aModeSenseCmd, PDMBLOCKTXDIR_FROM_DEVICE, aModeSenseResult, &cbTransfer, &uDummySense, 500);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_NONE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Select sector size based on the current data block type. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (aModeSenseResult[12] & 0x0f)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2352;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2368;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2448;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 8:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 9:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2336;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 11:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2056;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2324;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 13:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2332;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: sector size %d\n", __FUNCTION__, s->cbATAPISector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer *= s->cbATAPISector;
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync if (s->cbTotalTransfer == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uTxDir = PDMBLOCKTXDIR_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
e6ad2e18e663b076aeabfec994947514566a7accvboxsync#endif
e6ad2e18e663b076aeabfec994947514566a7accvboxsync atapiCmdBT(s);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync}
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsyncstatic bool atapiReadSS(ATADevState *s)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync{
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync int rc = VINF_SUCCESS;
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync uint32_t cbTransfer, cSectors;
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = RT_MIN(s->cbTotalTransfer, s->cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = cbTransfer / s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cSectors * s->cbATAPISector <= cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, s->iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_START(&s->StatReads, r);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (s->cbATAPISector)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2048:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTXSUFF(pbIOBuffer), s->cbATAPISector * cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2352:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = s->iATAPILBA; i < s->iATAPILBA + cSectors; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sync bytes */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pbBuf++ = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pbBuf, 0xff, 11);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf += 11;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* MSF */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(pbBuf, i);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf += 3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pbBuf++ = 0x01; /* mode 1 data */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* data */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)i * 2048, pbBuf, 2048);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf += 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* ECC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pbBuf, 0, 288);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf += 288;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_STOP(&s->StatReads, r);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Actual.s.fReading = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesRead, s->cbATAPISector * cSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The initial buffer end value has been set up based on the total
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer size. But the I/O buffer size limits what can actually be
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * done in one transfer, so set the actual value of the buffer end. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer >= s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iATAPILBA += cSectors;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync if (s->cErrors++ < MAX_LOG_REL_ERRORS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM read error, %d sectors at LBA %d\n", s->iLUN, cSectors, s->iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_MEDIUM_ERROR, SCSI_ASC_READ_ERROR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiPassthroughSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uATAPISenseKey;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PSTAMPROFILEADV pProf = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("ATAPI PT data write (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Simple heuristics: if there is at least one sector of data
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * to transfer, it's worth updating the LEDs. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer >= 2048)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fReading = s->Led.Actual.s.fReading = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pProf = &s->StatReads;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Asserted.s.fWriting = s->Led.Actual.s.fWriting = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pProf = &s->StatWrites;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pProf) { STAM_PROFILE_ADV_START(pProf, b); }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer > 100 * _1K)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Linux accepts commands with up to 100KB of data, but expects
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * us to handle commands with up to 128KB of data. The usual
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * imbalance of powers. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t aATAPICmd[ATAPI_PACKET_SIZE];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iATAPILBA, cSectors, cReqSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cbCurrTX;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync switch (s->aATAPICmd[0])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_10:
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync case SCSI_WRITE_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_AND_VERIFY_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(s->aATAPICmd + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U16(s->aATAPICmd + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(s->aATAPICmd + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U32(s->aATAPICmd + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(s->aATAPICmd + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U24(s->aATAPICmd + 6) / s->cbATAPISector;
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD_MSF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataMSF2LBA(s->aATAPICmd + 3);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataMSF2LBA(s->aATAPICmd + 6) - iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Don't know how to split command %#04x\n", s->aATAPICmd[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cErrors++ < MAX_LOG_REL_ERRORS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough split error\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(aATAPICmd, s->aATAPICmd, ATAPI_PACKET_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cReqSectors = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = cSectors; i > 0; i -= cReqSectors)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (i * s->cbATAPISector > 100 * _1K)
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync cReqSectors = (100 * _1K) / s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync cReqSectors = i;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbCurrTX = s->cbATAPISector * cReqSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (s->aATAPICmd[0])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_AND_VERIFY_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(aATAPICmd + 7, cReqSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(aATAPICmd + 2, iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(aATAPICmd + 6, cReqSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(s->aATAPICmd + 2, iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U24(s->aATAPICmd + 6, cbCurrTX);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD_MSF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(aATAPICmd + 3, iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, pbBuf, &cbCurrTX, &uATAPISenseKey, 30000 /**< @todo timeout */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA += cReqSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf += s->cbATAPISector * cReqSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, s->aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, s->CTXSUFF(pbIOBuffer), &cbTransfer, &uATAPISenseKey, 30000 /**< @todo timeout */);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pProf) { STAM_PROFILE_ADV_STOP(pProf, b); }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Update the LEDs and the read/write statistics. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer >= 2048)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Actual.s.fReading = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesRead, cbTransfer);
4c98b8b05f3783351cf256cc90cd4478fb28b62bvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->Led.Actual.s.fWriting = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&s->StatBytesWritten, cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cbTransfer <= s->cbTotalTransfer);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Reply with the same amount of data as the real drive. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->cbTotalTransfer = cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The initial buffer end value has been set up based on the total
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * transfer size. But the I/O buffer size limits what can actually be
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * done in one transfer, so set the actual value of the buffer end. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = cbTransfer;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (s->aATAPICmd[0] == SCSI_INQUIRY)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Make sure that the real drive cannot be identified.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Motivation: changing the VM configuration should be as
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * invisible as possible to the guest. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log3(("ATAPI PT inquiry data before (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 8, "VBOX", 8);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 16, "CD-ROM", 16);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataSCSIPadStr(s->CTXSUFF(pbIOBuffer) + 32, "1.0", 4);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (cbTransfer)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log3(("ATAPI PT data read (%d): %.*Vhxs\n", cbTransfer, cbTransfer, s->CTXSUFF(pbIOBuffer)));
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->iSourceSink = ATAFN_SS_NULL;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdOK(s);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync else
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (s->cErrors++ < MAX_LOG_REL_ERRORS)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync uint8_t u8Cmd = s->aATAPICmd[0];
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync do
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* don't log superflous errors */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ( rc == VERR_DEV_IO_ERROR
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync && ( u8Cmd == SCSI_TEST_UNIT_READY
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync || u8Cmd == SCSI_READ_CAPACITY
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || u8Cmd == SCSI_READ_TOC_PMA_ATIP))
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command (%#04x) error %d %Vrc\n", s->iLUN, u8Cmd, uATAPISenseKey, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync } while (0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, uATAPISenseKey, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This is a drive-reported error. atapiCmdError() sets both the error
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * error code in the ATA error register and in s->uATAPISenseKey. The
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * former is correct, the latter is not. Otherwise the drive would not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * get the next REQUEST SENSE command which is necessary to clear the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * error status of the drive. Easy fix: clear s->uATAPISenseKey. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->uATAPISenseKey = SCSI_SENSE_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATAPIASC = SCSI_ASC_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadSectors(ATADevState *s, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cSectors > 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iATAPILBA = iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = cbSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cSectors * cbSector, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadCapacitySS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(s->cbElementaryTransfer <= 8);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ataH2BE_U32(pbBuf, s->cTotalSectors - 1);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ataH2BE_U32(pbBuf + 4, 2048);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync s->iSourceSink = ATAFN_SS_NULL;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync atapiCmdOK(s);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return false;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync}
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadDiscInformationSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 34);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pbBuf, '\0', 34);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf, 32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = (0 << 4) | (3 << 2) | (2 << 0); /* not erasable, complete session, complete disc */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 1; /* number of first track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[4] = 1; /* number of sessions (LSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 1; /* first track number in last session (LSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[6] = 1; /* last track number in last session (LSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[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 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[8] = 0; /* disc type = CD-ROM */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[9] = 0; /* number of sessions (MSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[10] = 0; /* number of sessions (MSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[11] = 0; /* number of sessions (MSB) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(pbBuf + 16, 0x00ffffff); /* last session lead-in start time is not available */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(pbBuf + 20, 0x00ffffff); /* last possible start time for lead-out is not available */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadTrackInformationSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(s->cbElementaryTransfer <= 36);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Accept address/number type of 1 only, and only track 1 exists. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ((s->aATAPICmd[1] & 0x03) != 1 || ataBE2H_U32(&s->aATAPICmd[2]) != 1)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync memset(pbBuf, '\0', 36);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf, 34);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[2] = 1; /* track number (LSB) */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[3] = 1; /* session number (LSB) */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[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 */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(pbBuf + 8, 0); /* track start address is 0 */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(pbBuf + 24, s->cTotalSectors); /* track size */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[32] = 0; /* track number (MSB) */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[33] = 0; /* session number (MSB) */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->iSourceSink = ATAFN_SS_NULL;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdOK(s);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync}
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsyncstatic bool atapiGetConfigurationSS(ATADevState *s)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Assert(s->cbElementaryTransfer <= 32);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /* Accept valid request types only, and only starting feature 0. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if ((s->aATAPICmd[1] & 0x03) == 3 || ataBE2H_U16(&s->aATAPICmd[2]) != 0)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pbBuf, '\0', 32);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(pbBuf, 16);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync /** @todo implement switching between CD-ROM and DVD-ROM profile (the only
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * way to differentiate them right now is based on the image size). Also
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * implement signalling "no current profile" if no medium is loaded. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U16(pbBuf + 6, 0x08); /* current profile: read-only CD */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U16(pbBuf + 8, 0); /* feature 0: list of profiles supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[10] = (0 << 2) | (1 << 1) | (1 || 0); /* version 0, persistent, current */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[11] = 8; /* additional bytes for profiles */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The MMC-3 spec says that DVD-ROM read capability should be reported
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * before CD-ROM read capability. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf + 12, 0x10); /* profile: read-only DVD */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[14] = (0 << 0); /* NOT current profile */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf + 16, 0x08); /* profile: read only CD */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[18] = (1 << 0); /* current profile */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Other profiles we might want to add in the future: 0x40 (BD-ROM) and 0x50 (HDDVD-ROM) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiInquirySS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 36);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = 0x05; /* CD-ROM */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[1] = 0x80; /* removable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if 1/*ndef VBOX*/ /** @todo implement MESN + AENC. (async notification on removal and stuff.) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = 0x00; /* ISO */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = 0x00; /* ISO */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0x91; /* format 1, MESN=1, AENC=9 ??? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pbBuf[4] = 31; /* additional length */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[6] = 0; /* reserved */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[7] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSCSIPadStr(pbBuf + 8, "VBOX", 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSCSIPadStr(pbBuf + 16, "CD-ROM", 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSCSIPadStr(pbBuf + 32, "1.0", 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiModeSenseErrorRecoverySS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 16);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[0], 16 + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = 0x70;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[4] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[6] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[7] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[8] = 0x01;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[9] = 0x06;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[10] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[11] = 0x05;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[12] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[13] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[14] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[15] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiModeSenseCDStatusSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 40);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[0], 38);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = 0x70;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[4] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[6] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[7] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[8] = 0x2a;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[9] = 30; /* page length */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[10] = 0x08; /* DVD-ROM read support */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[11] = 0x00; /* no write support */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync /* The following claims we support audio play. This is obviously false,
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * but the Linux generic CDROM support makes many features depend on this
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * capability. If it's not set, this causes many things to be disabled. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[12] = 0x71; /* multisession support, mode 2 form 1/2 support, audio play */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[13] = 0x00; /* no subchannel reads supported */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (s->pDrvMount->pfnIsLocked(s->pDrvMount))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[14] |= 1 << 1; /* report lock state */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pbBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ataH2BE_U16(&pbBuf[16], 5632); /* (obsolete) claim 32x speed support */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[18], 2); /* number of audio volume levels */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[20], s->cbIOBuffer / _1K); /* buffer size supported in Kbyte */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[22], 5632); /* (obsolete) current read speed 32x */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[24] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[25] = 0; /* reserved for digital audio (see idx 15) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[26], 0); /* (obsolete) maximum write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[28], 0); /* (obsolete) current write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[30], 0); /* copy management revision supported 0=no CSS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[32] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[33] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[34] = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[35] = 1; /* rotation control CAV */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[36], 0); /* current write speed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(&pbBuf[38], 0); /* number of write speed performance descriptors */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiRequestSenseSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 18);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memset(pbBuf, 0, 18);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[0] = 0x70 | (1 << 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = s->uATAPISenseKey;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[7] = 10;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[12] = s->uATAPIASC;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiMechanismStatusSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->cbElementaryTransfer <= 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* no current LBA */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[2] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[3] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[4] = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf[5] = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf + 6, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool atapiReadTOCNormalSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer), *q, iStartTrack;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fMSF;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbSize;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fMSF = (s->aATAPICmd[1] >> 1) & 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iStartTrack = s->aATAPICmd[6];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iStartTrack > 1 && iStartTrack != 0xaa)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q = pbBuf + 2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* first session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* last session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iStartTrack <= 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* ADR, control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fMSF)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(q, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(q, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* lead out track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* ADR, control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0xaa; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fMSF)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(q, s->cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(q, s->cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync cbSize = q - pbBuf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf, cbSize - 2);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync if (cbSize < s->cbTotalTransfer)
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync s->cbTotalTransfer = cbSize;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync s->iSourceSink = ATAFN_SS_NULL;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync atapiCmdOK(s);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsyncstatic bool atapiReadTOCMultiSS(ATADevState *s)
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync bool fMSF;
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync Assert(s->cbElementaryTransfer <= 12);
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync fMSF = (s->aATAPICmd[1] >> 1) & 1;
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync /* multi session: only a single session defined */
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync/** @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. */
0cb5af53de7aed97b1b35311f93de8175756e4afvboxsync memset(pbBuf, 0, 12);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[1] = 0x0a;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[2] = 0x01;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[3] = 0x01;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[5] = 0x14; /* ADR, control */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[6] = 1; /* first track in last complete session */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync if (fMSF)
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync {
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync pbBuf[8] = 0; /* reserved */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync ataLBA2MSF(&pbBuf[9], 0);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync }
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync ataH2BE_U32(pbBuf + 8, 0);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync atapiCmdOK(s);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsyncstatic bool atapiReadTOCRawSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync uint8_t *pbBuf = s->CTXSUFF(pbIOBuffer), *q, iStartTrack;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync bool fMSF;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbSize;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync fMSF = (s->aATAPICmd[1] >> 1) & 1;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync iStartTrack = s->aATAPICmd[6];
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync q = pbBuf + 2;
6d9d4a12f6f9f341c968f711765c2c17c9a5a28cvboxsync *q++ = 1; /* first session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* last session */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* session number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* data track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0xa0; /* first track in program area */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* first track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x00; /* disk type CD-DA or CD data */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* session number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* data track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0xa1; /* last track in program area */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *q++ = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* last track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* session number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* data track */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0xa2; /* lead-out */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *q++ = 0; /* frame */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync if (fMSF)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(q, s->cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync ataH2BE_U32(q, s->cTotalSectors);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync q += 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* session number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0x14; /* ADR, control */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* track number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 1; /* point */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* min */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* sec */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* frame */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fMSF)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *q++ = 0; /* reserved */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataLBA2MSF(q, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sector 0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U32(q, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync q += 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbSize = q - pbBuf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataH2BE_U16(pbBuf, cbSize - 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbSize < s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = cbSize;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiParseCmdVirtualATAPI(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const uint8_t *pbPacket;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbMax;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbPacket = s->aATAPICmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pbPacket[0])
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_TEST_UNIT_READY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange-- > 2)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MODE_SENSE_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t uPageControl, uPageCode;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uPageControl = pbPacket[2] >> 6;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uPageCode = pbPacket[2] & 0x3f;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (uPageControl)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PAGECONTROL_CURRENT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (uPageCode)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MODEPAGE_ERROR_RECOVERY:
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync ataStartTransfer(s, RT_MIN(cbMax, 16), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY, true);
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MODEPAGE_CD_STATUS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 40), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto error_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PAGECONTROL_CHANGEABLE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto error_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PAGECONTROL_DEFAULT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto error_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PAGECONTROL_SAVED:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_REQUEST_SENSE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = pbPacket[4];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pbPacket[4] & 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->pDrvMount->pfnLock(s->pDrvMount);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->pDrvMount->pfnUnlock(s->pDrvMount);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync }
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors, iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pbPacket[0] == SCSI_READ_10)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U32(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cSectors == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync /* Rate limited logging, one log line per second. For
d64aa881df34a86dd70ab0e1b7b94ffa41be9731vboxsync * guests that insist on reading from places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static uint64_t uLastLogTS = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uLastLogTS = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiReadSectors(s, iATAPILBA, cSectors, 2048);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors, iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = (pbPacket[6] << 16) | (pbPacket[7] << 8) | pbPacket[8];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cSectors == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((uint64_t)iATAPILBA + cSectors > s->cTotalSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Rate limited logging, one log line per second. For
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * guests that insist on reading from places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static uint64_t uLastLogTS = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uLastLogTS = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pbPacket[9] & 0xf8)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x00:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* nothing */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* normal read */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiReadSectors(s, iATAPILBA, cSectors, 2048);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0xf8:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* read all data */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiReadSectors(s, iATAPILBA, cSectors, 2352);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM sector format not supported\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEEK_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iATAPILBA > s->cTotalSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Rate limited logging, one log line per second. For
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * guests that insist on seeking to places outside the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * valid area this often generates too many release log
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * entries otherwise. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static uint64_t uLastLogTS = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RTTimeMilliTS() >= uLastLogTS + 1000)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", s->iLUN, (uint64_t)iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uLastLogTS = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_SEEK); /* Linux expects this. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_START_STOP_UNIT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pbPacket[4] & 3)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: /* 00 - Stop motor */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1: /* 01 - Start motor */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2: /* 10 - Eject media */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This must be done from EMT. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PPDMDEVINS pDevIns = ATADEVSTATE_2_DEVINS(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMREQ pReq;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (PFNRT)s->pDrvMount->pfnUnmount, 2, s->pDrvMount, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync VMR3ReqFree(pReq);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3: /* 11 - Load media */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo rc = s->pDrvMount->pfnLoadMedia(s->pDrvMount) */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdOK(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MECHANISM_STATUS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MECHANISM_STATUS, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_TOC_PMA_ATIP:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t format;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* SCSI MMC-3 spec says format is at offset 2 (lower 4 bits),
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * but Linux kernel uses offset 9 (topmost 2 bits). Hope that
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the other field is clear... */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync format = (pbPacket[2] & 0xf) | (pbPacket[9] >> 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (format)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_NORMAL, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 12), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_MULTI, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_RAW, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync error_cmd:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CAPACITY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync }
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync ataStartTransfer(s, 8, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_CAPACITY, true);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync break;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync case SCSI_READ_DISC_INFORMATION:
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync if (s->cNotifiedMediaChange > 0)
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 34), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_DISC_INFORMATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_TRACK_INFORMATION:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cNotifiedMediaChange > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange-- ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (!s->pDrvMount->pfnIsMounted(s->pDrvMount))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_GET_CONFIGURATION:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* No media change stuff here, it can confuse Linux guests. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 32), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_CONFIGURATION, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_INQUIRY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbMax = pbPacket[4];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_INQUIRY, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/*
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Parse ATAPI commands, passing them directly to the CD/DVD drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiParseCmdPassthrough(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync const uint8_t *pbPacket;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *pbBuf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cSectors, iATAPILBA;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbTransfer = 0;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync PDMBLOCKTXDIR uTxDir = PDMBLOCKTXDIR_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbPacket = s->aATAPICmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbBuf = s->CTXSUFF(pbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pbPacket[0])
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_BLANK:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_CLOSE_TRACK_SESSION:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_ERASE_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync Log2(("ATAPI PT: lba %d\n", iATAPILBA));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_FORMAT_UNIT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync case SCSI_GET_CONFIGURATION:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync goto sendcmd;
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync case SCSI_GET_EVENT_STATUS_NOTIFICATION:
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync goto sendcmd;
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync case SCSI_GET_PERFORMANCE:
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync cbTransfer = s->uATARegLCyl | (s->uATARegHCyl << 8); /* use ATAPI transfer length */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_INQUIRY:
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync cbTransfer = pbPacket[4];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_LOAD_UNLOAD_MEDIUM:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MECHANISM_STATUS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MODE_SELECT_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_MODE_SENSE_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PAUSE_RESUME:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PLAY_AUDIO_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PLAY_AUDIO_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PLAY_AUDIO_MSF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo do not forget to unlock when a VM is shut down */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cSectors * s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U32(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cSectors * s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_BUFFER:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U24(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_BUFFER_CAPACITY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CAPACITY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = 8;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD:
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = ataBE2H_U24(pbPacket + 6) / s->cbATAPISector * s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_CD_MSF:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataMSF2LBA(pbPacket + 6) - ataMSF2LBA(pbPacket + 3);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cSectors > 32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = cSectors * s->cbATAPISector;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync goto sendcmd;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync case SCSI_READ_DISC_INFORMATION:
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_DVD_STRUCTURE:
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync goto sendcmd;
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync case SCSI_READ_FORMAT_CAPACITIES:
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_SUBCHANNEL:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_READ_TOC_PMA_ATIP:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_READ_TRACK_INFORMATION:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_REPAIR_TRACK:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_REPORT_KEY:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_REQUEST_SENSE:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = pbPacket[4];
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (s->uATAPISenseKey != SCSI_SENSE_NONE)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, RT_MIN(cbTransfer, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_RESERVE_TRACK:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SCAN:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEEK_10:
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEND_CUE_SHEET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U24(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEND_DVD_STRUCTURE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEND_EVENT:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_SEND_KEY:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 8);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_SEND_OPC_INFORMATION:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 7);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_SET_CD_SPEED:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_SET_READ_AHEAD:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_SET_STREAMING:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U16(pbPacket + 9);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_START_STOP_UNIT:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_STOP_PLAY_SCAN:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_SYNCHRONIZE_CACHE:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_TEST_UNIT_READY:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_VERIFY_10:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_WRITE_10:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cSectors = ataBE2H_U16(pbPacket + 7);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#if 0
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* The sector size is determined by the async I/O thread. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync s->cbATAPISector = 0;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* Preliminary, will be corrected once the sector size is known. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = cSectors;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#else
09f4b412099acda62997fd82c8608075c453b3ebvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cSectors * s->cbATAPISector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_12:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U32(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#if 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The sector size is determined by the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Preliminary, will be corrected once the sector size is known. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cSectors;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 2048; /**< @todo this size is not always correct */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = cSectors * s->cbATAPISector;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_AND_VERIFY_10:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iATAPILBA = ataBE2H_U32(pbPacket + 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cSectors = ataBE2H_U16(pbPacket + 7);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("ATAPI PT: lba %d sectors %d\n", iATAPILBA, cSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The sector size is determined by the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbATAPISector = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Preliminary, will be corrected once the sector size is known. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_WRITE_BUFFER:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (pbPacket[1] & 0x1f)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync case 0x04: /* download microcode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x05: /* download microcode and save */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync case 0x06: /* download microcode with offsets */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x07: /* download microcode with offsets and save */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x0e: /* download microcode with offsets and defer activation */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x0f: /* activate deferred microcode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = ataBE2H_U16(pbPacket + 6);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_TO_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync cbTransfer = ataBE2H_U32(pbPacket + 6);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync uTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto sendcmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case SCSI_REZERO_UNIT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Obsolete command used by cdrecord. What else would one expect?
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This command is not sent to the drive, it is handled internally,
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * as the Linux kernel doesn't like it (message "scsi: unknown
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * opcode 0x01" in syslog) and replies with a sense code of 0,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * which sends cdrecord to an endless loop. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync LogRel(("PIIX3 ATA: LUN#%d: passthrough unimplemented for command %#x\n", s->iLUN, pbPacket[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiCmdError(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync sendcmd:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Send a command to the drive, passing data in/out as required. */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync Log2(("ATAPI PT: max size %d\n", cbTransfer));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cbTransfer <= s->cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer == 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uTxDir = PDMBLOCKTXDIR_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void atapiParseCmd(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const uint8_t *pbPacket;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pbPacket = s->aATAPICmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef DEBUG
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d DMA=%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0], g_apszSCSICmdNames[pbPacket[0]]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !DEBUG */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d DMA=%d CMD=%#04x\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0]));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !DEBUG */
09f4b412099acda62997fd82c8608075c453b3ebvboxsync Log2(("%s: limit=%#x packet: %.*Vhxs\n", __FUNCTION__, s->uATARegLCyl | (s->uATARegHCyl << 8), ATAPI_PACKET_SIZE, pbPacket));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync if (s->fATAPIPassthrough)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync atapiParseCmdPassthrough(s);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiParseCmdVirtualATAPI(s);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataPacketSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fDMA = !!(s->uATARegFeature & 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(s->aATAPICmd, s->CTXSUFF(pbIOBuffer), ATAPI_PACKET_SIZE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uTxDir = PDMBLOCKTXDIR_NONE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync atapiParseCmd(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Called when a media is mounted.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataMountNotify(PPDMIMOUNTNOTIFY pInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIMOUNTNOTIFY_2_ATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: changing LUN#%d\n", __FUNCTION__, pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Ignore the call if we're called while being attached. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pIf->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report media changed in TEST UNIT and other (probably incorrect) places. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->cNotifiedMediaChange < 2)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cNotifiedMediaChange = 2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync/**
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * Called when a media is unmounted
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIMOUNTNOTIFY_2_ATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s:\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Whatever I do, XP will not use the GET MEDIA STATUS nor the EVENT stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * However, it will respond to TEST UNIT with a 0x6 0x28 (media changed) sense code.
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync * So, we'll give it 4 TEST UNIT command to catch up, two which the media is not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * present and 2 in which it is changed.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cNotifiedMediaChange = 4;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPacketBT(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->cbElementaryTransfer = s->cbTotalTransfer;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_CD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: interrupt reason %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_READY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataResetDevice(ATADevState *s)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->cMultSectors = ATA_MAX_MULT_SECTORS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cNotifiedMediaChange = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync s->uATARegSelect = 0x20;
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync ataSetStatusValue(s, ATA_STAT_READY);
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync ataSetSignature(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataStart = 0;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->iIOBufferPIODataEnd = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iBeginTransfer = ATAFN_BT_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fATAPITransfer = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = ATA_MODE_UDMA | 2; /* PIIX3 supports only up to UDMA2 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegFeature = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataExecuteDeviceDiagnosticSS(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSignature(s);
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync ataSetStatusValue(s, 0); /* NOTE: READY is _not_ set */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegError = 0x01;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync return false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataParseCmd(ATADevState *s, uint8_t cmd)
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync{
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync#ifdef DEBUG
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync Log(("%s: LUN#%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, cmd, g_apszATACmdNames[cmd]));
19c7039bc1a59c1680538d8459b2a09c3a7ae9fdvboxsync#else /* !DEBUG */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LUN#%d CMD=%#04x\n", __FUNCTION__, s->iLUN, cmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !DEBUG */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = false;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync s->fDMA = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cmd == ATA_IDLE_IMMEDIATE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Detect Linux timeout recovery, first tries IDLE IMMEDIATE (which
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * would overwrite the failing command unfortunately), then RESET. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int32_t uCmdWait = -1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t uNow = RTTimeNanoTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->u64CmdTS)
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync uCmdWait = (uNow - s->u64CmdTS) / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: IDLE IMMEDIATE, CmdIf=%#04x (%d usec ago)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iLUN, s->uATARegCommand, uCmdWait));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegCommand = cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (cmd)
a21a14c99f2698c3a8b6dc0a3086e087701fe719vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_IDENTIFY_DEVICE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->pDrvBlock && !s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_NULL, ATAFN_SS_IDENTIFY, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSignature(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdError(s, ABRT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_INITIALIZE_DEVICE_PARAMETERS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_RECALIBRATE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_SET_MULTIPLE_MODE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( s->uATARegNSector != 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && ( s->uATARegNSector > ATA_MAX_MULT_SECTORS
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || (s->uATARegNSector & (s->uATARegNSector - 1)) != 0))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdError(s, ABRT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: set multi sector count to %d\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cMultSectors = s->uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_VERIFY_SECTORS_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_VERIFY_SECTORS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* do sector number check ? */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_SECTORS_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_SECTORS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_SECTORS_WITHOUT_RETRIES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_SECTORS_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_SECTORS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_SECTORS_WITHOUT_RETRIES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_MULTIPLE_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_MULTIPLE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->cMultSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = s->cMultSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_MULTIPLE_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_MULTIPLE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->cMultSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = s->cMultSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_DMA_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_DMA:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_DMA_WITHOUT_RETRIES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = ATA_MAX_MULT_SECTORS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fDMA = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_DMA_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_DMA:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_WRITE_DMA_WITHOUT_RETRIES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cSectorsPerIRQ = ATA_MAX_MULT_SECTORS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fDMA = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_NATIVE_MAX_ADDRESS_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->fLBA48 = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSector(s, s->cTotalSectors - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_READ_NATIVE_MAX_ADDRESS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSector(s, RT_MIN(s->cTotalSectors, 1 << 28) - 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_CHECK_POWER_MODE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegNSector = 0xff; /* drive active or idle */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_SET_FEATURES:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: feature=%#x\n", __FUNCTION__, s->uATARegFeature));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (s->uATARegFeature)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x02: /* write cache enable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: write cache enable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0xaa: /* read look-ahead enable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: read look-ahead enable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x55: /* read look-ahead disable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: read look-ahead disable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0xcc: /* reverting to power-on defaults enable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: revert to power-on defaults enable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x66: /* reverting to power-on defaults disable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: revert to power-on defaults disable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x82: /* write cache disable */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: write cache disable\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* As per the ATA/ATAPI-6 specs, a write cache disable
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * command MUST flush the write buffers to disc. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_FLUSH, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x03: { /* set transfer mode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: transfer mode %#04x\n", __FUNCTION__, s->uATARegNSector));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (s->uATARegNSector & 0xf8)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x00: /* PIO default */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0x08: /* PIO mode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_MODE_MDMA: /* MDMA mode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_MDMA_MODE_MAX);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_MODE_UDMA: /* UDMA mode */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_UDMA_MODE_MAX);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * OS/2 workarond:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The OS/2 IDE driver from MCP2 appears to rely on the feature register being
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reset here. According to the specification, this is a driver bug as the register
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * contents are undefined after the call. This means we can just as well reset it.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uATARegFeature = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_FLUSH_CACHE_EXT:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_FLUSH_CACHE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock || s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_FLUSH, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_STANDBY_IMMEDIATE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdOK(s, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_IDLE_IMMEDIATE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: aborting current command\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAbortCurrentCommand(s, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* ATAPI commands */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_IDENTIFY_PACKET_DEVICE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_NULL, ATAFN_SS_ATAPI_IDENTIFY, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdError(s, ABRT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_EXECUTE_DEVICE_DIAGNOSTIC:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_DEVICE_RESET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->fATAPI)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: performing device RESET\n", s->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAbortCurrentCommand(s, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_PACKET:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* overlapping commands not supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uATARegFeature & 0x02)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync goto abort_cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync abort_cmd:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataCmdError(s, ABRT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s); /* Shortcut, do not use AIO thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Waits for a particular async I/O thread to complete whatever it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * is doing at the moment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns true on success.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns false when the thread is still processing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pData Pointer to the controller data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cMillies How long to wait (total).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64Start;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for any pending async operation to finish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync u64Start = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (;;)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (ataAsyncIOIsIdle(pCtl, false))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RTTimeMilliTS() - u64Start >= cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTThreadSleep(100);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataIOPortWriteU8(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: write addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync addr &= 7;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1: /* feature register */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* NOTE: data is written to the two drives */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegFeatureHOB = pCtl->aIfs[0].uATARegFeature;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegFeatureHOB = pCtl->aIfs[1].uATARegFeature;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegFeature = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegFeature = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2: /* sector count */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegNSectorHOB = pCtl->aIfs[0].uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegNSectorHOB = pCtl->aIfs[1].uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegNSector = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegNSector = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3: /* sector number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegSectorHOB = pCtl->aIfs[0].uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegSectorHOB = pCtl->aIfs[1].uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegSector = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegSector = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 4: /* cylinder low */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegLCylHOB = pCtl->aIfs[0].uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegLCylHOB = pCtl->aIfs[1].uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegLCyl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegLCyl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 5: /* cylinder high */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegHCylHOB = pCtl->aIfs[0].uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegHCylHOB = pCtl->aIfs[1].uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegHCyl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegHCyl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 6: /* drive/head */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegSelect = (val & ~0x10) | 0xa0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegSelect = (val | 0x10) | 0xa0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((((val >> 4)) & 1) != pCtl->iSelectedIf)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PPDMDEVINS pDevIns = CONTROLLER_2_DEVINS(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* select another drive */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->iSelectedIf = (val >> 4) & 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The IRQ line is multiplexed between the two drives, so
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * update the state when switching to another drive. Only need
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * to update interrupt line if it is enabled and there is a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * state change. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( !(pCtl->aIfs[pCtl->iSelectedIf].uATARegDevCtl & ATA_DEVCTL_DISABLE_IRQ)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && ( pCtl->aIfs[pCtl->iSelectedIf].fIrqPending
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync != pCtl->aIfs[pCtl->iSelectedIf ^ 1].fIrqPending))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[pCtl->iSelectedIf].fIrqPending)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the interrupt line is asserted. It monitors the line
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * for a rising edge. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status |= BM_STATUS_INT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(pDevIns, pCtl->irq, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(pDevIns, 0, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(pDevIns, pCtl->irq, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 7: /* command */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* ignore commands to non existant slave */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->iSelectedIf && !pCtl->aIfs[pCtl->iSelectedIf].pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Don't do anything complicated in GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_IOM_HC_IOPORT_WRITE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataParseCmd(&pCtl->aIfs[pCtl->iSelectedIf], val);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataIOPortReadU8(PATACONTROLLER pCtl, uint32_t addr, uint32_t *pu32)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fHOB = !!(s->uATARegDevCtl & (1 << 7));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (addr & 7)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: /* data register */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0xff;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1: /* error register */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The ATA specification is very terse when it comes to specifying
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the precise effects of reading back the error/feature register.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The error register (read-only) shares the register number with
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the feature register (write-only), so it seems that it's not
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * necessary to support the usual HOB readback here. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegError;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2: /* sector count */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (fHOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegNSectorHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegNSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3: /* sector number */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (fHOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegSectorHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 4: /* cylinder low */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (fHOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegLCylHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegLCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 5: /* cylinder high */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (fHOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegHCylHOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegHCyl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 6: /* drive/head */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This register must always work as long as there is at least
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * one drive attached to the controller. It is common between
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * both drives anyway (completely identical content). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pCtl->aIfs[0].pDrvBlock && !pCtl->aIfs[1].pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegSelect;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 7: /* primary status */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Counter for number of busy status seen in GC in a row. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync static unsigned cBusy = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegStatus;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Give the async I/O thread an opportunity to make progress,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * don't let it starve by guests polling frequently. EMT has a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * lower priority than the async I/O thread, but sometimes the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * host OS doesn't care. With some guests we are only allowed to
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * be busy for about 5 milliseconds in some situations. Note that
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this is no guarantee for any other VBox thread getting
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * scheduled, so this just lowers the CPU load a bit when drives
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are busy. It cannot help with timing problems. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (val & ATA_STAT_BUSY)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cBusy = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTThreadYield();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegStatus;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Cannot yield CPU in guest context. And switching to host
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * context for each and every busy status is too costly,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * especially on SMP systems where we don't gain much by
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * yielding the CPU to someone else. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (++cBusy >= 20)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cBusy = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_IOM_HC_IOPORT_READ;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cBusy = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pu32 = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataStatusRead(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((!pCtl->aIfs[0].pDrvBlock && !pCtl->aIfs[1].pDrvBlock) ||
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (pCtl->iSelectedIf == 1 && !s->pDrvBlock))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val = s->uATARegStatus;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataControlWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((val ^ pCtl->aIfs[0].uATARegDevCtl) & ATA_DEVCTL_RESET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_IOM_HC_IOPORT_WRITE; /* The RESET stuff is too complicated for GC. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* RESET is common for both drives attached to a controller. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(pCtl->aIfs[0].uATARegDevCtl & ATA_DEVCTL_RESET) &&
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (val & ATA_DEVCTL_RESET))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Software RESET low to high */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int32_t uCmdWait0 = -1, uCmdWait1 = -1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t uNow = RTTimeNanoTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[0].u64CmdTS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uCmdWait0 = (uNow - pCtl->aIfs[0].u64CmdTS) / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[1].u64CmdTS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uCmdWait1 = (uNow - pCtl->aIfs[1].u64CmdTS) / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER_IDX(pCtl), pCtl->iSelectedIf, pCtl->iAIOIf,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegCommand, uCmdWait0,
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync pCtl->aIfs[1].uATARegCommand, uCmdWait1));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync pCtl->fReset = true;
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* Everything must be done after the reset flag is set, otherwise
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync * there are unavoidable races with the currently executing request
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * (which might just finish in the mean time). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fChainedTransfer = false;
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pCtl->aIfs); i++)
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataResetDevice(&pCtl->aIfs[i]);
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* The following cannot be done using ataSetStatusValue() since the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reset flag is already set, which suppresses all status changes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[i].uATARegStatus = ATA_STAT_BUSY | ATA_STAT_SEEK;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, pCtl->aIfs[i].iLUN, pCtl->aIfs[i].uATARegStatus));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[i].uATARegError = 0x01;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync ataAsyncIOClearRequests(pCtl);
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, resetA\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (val & ATA_DEVCTL_HOB)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync val &= ~ATA_DEVCTL_HOB;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: ignored setting HOB\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &ataResetARequest);
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("RESET handling is too complicated for GC\n"));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync else if ((pCtl->aIfs[0].uATARegDevCtl & ATA_DEVCTL_RESET) &&
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync !(val & ATA_DEVCTL_RESET))
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync {
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#ifdef IN_RING3
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync /* Software RESET high to low */
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log(("%s: deasserting RESET\n", __FUNCTION__));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: Ctl#%d: message to async I/O thread, resetC\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync if (val & ATA_DEVCTL_HOB)
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync val &= ~ATA_DEVCTL_HOB;
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: ignored setting HOB\n", __FUNCTION__));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync }
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync ataAsyncIOPutRequest(pCtl, &ataResetCRequest);
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("RESET handling is too complicated for GC\n"));
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync#endif /* IN_RING3 */
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync }
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Change of interrupt disable flag. Update interrupt line if interrupt
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * is pending on the current interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((val ^ pCtl->aIfs[0].uATARegDevCtl) & ATA_DEVCTL_DISABLE_IRQ
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && pCtl->aIfs[pCtl->iSelectedIf].fIrqPending)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(val & ATA_DEVCTL_DISABLE_IRQ))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d asserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The BMDMA unit unconditionally sets BM_STATUS_INT if the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * interrupt line is asserted. It monitors the line for a rising
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * edge. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status |= BM_STATUS_INT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), 0, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), pCtl->irq, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: LUN#%d deasserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->irq == 16)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpPCISetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), 0, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpISASetIrqNoWait(CONTROLLER_2_DEVINS(pCtl), pCtl->irq, 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (val & ATA_DEVCTL_HOB)
935a8412cc9b46bc9b5fc1a3bfaa0f6c73092e65vboxsync Log2(("%s: set HOB\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegDevCtl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[1].uATARegDevCtl = val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataPIOTransfer(PATACONTROLLER pCtl)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s = &pCtl->aIfs[pCtl->iAIOIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: if=%p\n", __FUNCTION__, s));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cbTotalTransfer && s->iIOBufferCur > s->iIOBufferEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: %s data in the middle of a PIO transfer - VERY SLOW\n", s->iLUN, s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "loading" : "storing"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Any guest OS that triggers this case has a pathetic ATA driver.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * In a real system it would block the CPU via IORDY, here we do it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * very similarly by not continuing with the current instruction
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * until the transfer to/from the storage medium is completed. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iSourceSink != ATAFN_SS_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fRedo;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t status = s->uATARegStatus;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, ATA_STAT_BUSY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: calling source/sink function\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRedo = g_apfnSourceSinkFuncs[s->iSourceSink](s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fRedo = fRedo;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_UNLIKELY(fRedo))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(s, status);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPITransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferLimitATAPI(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE && s->cbElementaryTransfer > s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = s->cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: %s tx_size=%d elem_tx_size=%d index=%d end=%d\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync __FUNCTION__, s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "T2I" : "I2T",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer, s->cbElementaryTransfer,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur, s->iIOBufferEnd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStart(s, s->iIOBufferCur, s->cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer -= s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur += s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE && s->cbElementaryTransfer > s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = s->cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStop(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataPIOTransferFinish(PATACONTROLLER pCtl, ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not interfere with RESET processing if the PIO transfer finishes
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed continuing PIO transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || ( s->iSourceSink != ATAFN_SS_NULL
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && s->iIOBufferCur >= s->iIOBufferEnd))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Need to continue the transfer in the async I/O thread. This is
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the case for write operations or generally for not yet finished
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfers (some data might need to be read). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetStatus(s, ATA_STAT_READY | ATA_STAT_DRQ);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync ataSetStatus(s, ATA_STAT_BUSY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &ataPIORequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Either everything finished (though some data might still be pending)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * or some data is pending before the next read is due. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Continue a previously started transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetStatus(s, ATA_STAT_DRQ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_READY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* There is more to transfer, happens usually for large ATAPI
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * reads - the protocol limits the chunk size to 65534 bytes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: skipping message to async I/O thread, ending PIO transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finish PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!pCtl->fRedo);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataDataWrite(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, const uint8_t *pbBuf)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t *p;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p = s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* All but the last transfer unit is simple enough for GC, but
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * sending a request to the async IO thread is too complicated. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync memcpy(p, pbBuf, cbSize);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync s->iIOBufferPIODataStart += cbSize;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync }
87150caf549846b0edba30c50dabe5092df70b5fvboxsync else
87150caf549846b0edba30c50dabe5092df70b5fvboxsync return VINF_IOM_HC_IOPORT_WRITE;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#else /* IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync memcpy(p, pbBuf, cbSize);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync s->iIOBufferPIODataStart += cbSize;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync ataPIOTransferFinish(pCtl, s);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* !IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync }
87150caf549846b0edba30c50dabe5092df70b5fvboxsync else
87150caf549846b0edba30c50dabe5092df70b5fvboxsync Log2(("%s: DUMMY data\n", __FUNCTION__));
87150caf549846b0edba30c50dabe5092df70b5fvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
87150caf549846b0edba30c50dabe5092df70b5fvboxsync return VINF_SUCCESS;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync}
87150caf549846b0edba30c50dabe5092df70b5fvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsyncstatic int ataDataRead(PATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, uint8_t *pbBuf)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync{
87150caf549846b0edba30c50dabe5092df70b5fvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
87150caf549846b0edba30c50dabe5092df70b5fvboxsync uint8_t *p;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart < s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync {
87150caf549846b0edba30c50dabe5092df70b5fvboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync p = s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#ifndef IN_RING3
87150caf549846b0edba30c50dabe5092df70b5fvboxsync /* All but the last transfer unit is simple enough for GC, but
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * sending a request to the async IO thread is too complicated. */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart + cbSize < s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync {
87150caf549846b0edba30c50dabe5092df70b5fvboxsync memcpy(pbBuf, p, cbSize);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync s->iIOBufferPIODataStart += cbSize;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync }
87150caf549846b0edba30c50dabe5092df70b5fvboxsync else
87150caf549846b0edba30c50dabe5092df70b5fvboxsync return VINF_IOM_HC_IOPORT_READ;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#else /* IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync memcpy(pbBuf, p, cbSize);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync s->iIOBufferPIODataStart += cbSize;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync ataPIOTransferFinish(pCtl, s);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync#endif /* !IN_RING3 */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync }
87150caf549846b0edba30c50dabe5092df70b5fvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: DUMMY data\n", __FUNCTION__));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync memset(pbBuf, '\xff', cbSize);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, addr, cbSize, pbBuf));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* Attempt to guess the LCHS disk geometry from the MS-DOS master boot
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * record (partition table). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataGuessDiskLCHS(ATADevState *s, uint32_t *pcCylinders, uint32_t *pcHeads, uint32_t *pcSectors)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t aMBR[512], *p;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t iEndHead, iEndSector, cCHSCylinders, cCHSHeads, cCHSSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPI || !s->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INVALID_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = s->pDrvBlock->pfnRead(s->pDrvBlock, 0, aMBR, 1 * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Test MBR magic number. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (aMBR[510] != 0x55 || aMBR[511] != 0xaa)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INVALID_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < 4; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Figure out the start of a partition table entry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync p = &aMBR[0x1be + i * 16];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iEndHead = p[5];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iEndSector = p[6] & 63;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ((p[12] | p[13] | p[14] | p[15]) && iEndSector & iEndHead)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Assumption: partition terminates on a cylinder boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cCHSHeads = iEndHead + 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cCHSSectors = iEndSector;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cCHSCylinders = s->cTotalSectors / (cCHSHeads * cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cCHSCylinders >= 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcHeads = cCHSHeads;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcSectors = cCHSSectors;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcCylinders = cCHSCylinders;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: LCHS=%d %d %d\n", __FUNCTION__, cCHSCylinders, cCHSHeads, cCHSSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INVALID_PARAMETER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataDMATransferStop(ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iBeginTransfer = ATAFN_BT_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = ATAFN_SS_NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Perform the entire DMA transfer in one go (unless a source/sink operation
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * has to be redone or a RESET comes in between). Unlike the PIO counterpart
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * this function cannot handle empty transfers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param pCtl Controller for which to perform the transfer.
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataDMATransfer(PATACONTROLLER pCtl)
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync{
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync PPDMDEVINS pDevIns = CONTROLLER_2_DEVINS(pCtl);
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iAIOIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fRedo;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPHYS pDesc;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync uint32_t cbTotalTransfer, cbElementaryTransfer;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync uint32_t iIOBufferCur, iIOBufferEnd;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync uint32_t dmalen;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMBLOCKTXDIR uTxDir;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync bool fLastDesc = false;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(sizeof(BMDMADesc) == 8);
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fRedo = pCtl->fRedo;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync if (RT_LIKELY(!fRedo))
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync Assert(s->cbTotalTransfer);
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync uTxDir = (PDMBLOCKTXDIR)s->uTxDir;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync cbTotalTransfer = s->cbTotalTransfer;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync cbElementaryTransfer = s->cbElementaryTransfer;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync iIOBufferCur = s->iIOBufferCur;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync iIOBufferEnd = s->iIOBufferEnd;
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync /* The DMA loop is designed to hold the lock only when absolutely
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync * necessary. This avoids long freezes should the guest access the
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync * ATA registers etc. for some reason. */
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync PDMCritSectLeave(&pCtl->lock);
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync Log2(("%s: %s tx_size=%d elem_tx_size=%d index=%d end=%d\n",
6ee2125e4b083d65e10fa8b2ef8fc1d2303cedcbvboxsync __FUNCTION__, uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "T2I" : "I2T",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTotalTransfer, cbElementaryTransfer,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iIOBufferCur, iIOBufferEnd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (pDesc = pCtl->pFirstDMADesc; pDesc <= pCtl->pLastDMADesc; pDesc += sizeof(BMDMADesc))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync BMDMADesc DMADesc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPHYS pBuffer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cbBuffer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_UNLIKELY(fRedo))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pBuffer = pCtl->pRedoDMABuffer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer = pCtl->cbRedoDMABuffer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fLastDesc = pCtl->fRedoDMALastDesc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysRead(pDevIns, pDesc, &DMADesc, sizeof(BMDMADesc));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pBuffer = RT_LE2H_U32(DMADesc.pBuffer);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer = RT_LE2H_U32(DMADesc.cbBuffer);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync fLastDesc = !!(cbBuffer & 0x80000000);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer &= 0xfffe;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (cbBuffer == 0)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer = 0x10000;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (cbBuffer > cbTotalTransfer)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer = cbTotalTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync while (RT_UNLIKELY(fRedo) || (cbBuffer && cbTotalTransfer))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (RT_LIKELY(!fRedo))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync dmalen = RT_MIN(cbBuffer, iIOBufferEnd - iIOBufferCur);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Log2(("%s: DMA desc %#010x: addr=%#010x size=%#010x\n", __FUNCTION__,
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync (int)pDesc, pBuffer, cbBuffer));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysWrite(pDevIns, pBuffer, s->CTXSUFF(pbIOBuffer) + iIOBufferCur, dmalen);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync else
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMDevHlpPhysRead(pDevIns, pBuffer, s->CTXSUFF(pbIOBuffer) + iIOBufferCur, dmalen);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync iIOBufferCur += dmalen;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbTotalTransfer -= dmalen;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbBuffer -= dmalen;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pBuffer += dmalen;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if ( iIOBufferCur == iIOBufferEnd
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync && (uTxDir == PDMBLOCKTXDIR_TO_DEVICE || cbTotalTransfer))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (uTxDir == PDMBLOCKTXDIR_FROM_DEVICE && cbElementaryTransfer > cbTotalTransfer)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbElementaryTransfer = cbTotalTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync /* The RESET handler could have cleared the DMA transfer
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * state (since we didn't hold the lock until just now
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * the guest can continue in parallel). If so, the state
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * is already set up so the loop is exited immediately. */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (s->iSourceSink != ATAFN_SS_NULL)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync s->iIOBufferCur = iIOBufferCur;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync s->iIOBufferEnd = iIOBufferEnd;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync s->cbElementaryTransfer = cbElementaryTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync s->cbTotalTransfer = cbTotalTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Log2(("%s: calling source/sink function\n", __FUNCTION__));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync fRedo = g_apfnSourceSinkFuncs[s->iSourceSink](s);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (RT_UNLIKELY(fRedo))
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->pFirstDMADesc = pDesc;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->pRedoDMABuffer = pBuffer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->cbRedoDMABuffer = cbBuffer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->fRedoDMALastDesc = fLastDesc;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync else
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbTotalTransfer = s->cbTotalTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbElementaryTransfer = s->cbElementaryTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (uTxDir == PDMBLOCKTXDIR_TO_DEVICE && cbElementaryTransfer > cbTotalTransfer)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync cbElementaryTransfer = cbTotalTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync iIOBufferCur = 0;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync iIOBufferEnd = cbElementaryTransfer;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync pCtl->fRedo = fRedo;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This forces the loop to exit immediately. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pDesc = pCtl->pLastDMADesc + 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_UNLIKELY(fRedo))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
15cb9d6c0d4fb378cb7ee8ad6fe44412a9254459vboxsync if (RT_UNLIKELY(fRedo))
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync break;
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync /* end of transfer */
eb2d4958f7faf812c3bdb2d7587d815022f0bd55vboxsync if (!cbTotalTransfer || fLastDesc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync }
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync
706ec8d33965b04fc59fb0b1b0981b81ae23600dvboxsync if (!(pCtl->BmDma.u8Cmd & BM_CMD_START) || pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: ABORT DMA%s\n", ATACONTROLLER_IDX(pCtl), pCtl->fReset ? " due to RESET" : ""));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataDMATransferStop(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This forces the loop to exit immediately. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pDesc = pCtl->pLastDMADesc + 1;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_UNLIKELY(fRedo))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fLastDesc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status &= ~BM_STATUS_DMAING;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbTotalTransfer = cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->cbElementaryTransfer = cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur = iIOBufferCur;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = iIOBufferEnd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Suspend I/O operations on a controller. Also suspends EMT, because it's
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * waiting for I/O to make progress. The next attempt to perform an I/O
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * operation will be made when EMT is resumed up again (as the resume
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * callback below restarts I/O).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pCtl Controller for which to suspend I/O.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataSuspendRedo(PATACONTROLLER pCtl)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PPDMDEVINS pDevIns = CONTROLLER_2_DEVINS(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVMREQ pReq;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fRedoIdle = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), &pReq, RT_INDEFINITE_WAIT,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (PFNRT)pDevIns->pDevHlp->pfnVMSuspend, 1, pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync VMR3ReqFree(pReq);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/** Asynch I/O thread for an interface. Once upon a time this was readable
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * code with several loops and a different semaphore for each purpose. But
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * then came the "how can one save the state in the middle of a PIO transfer"
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * question. The solution was to use an ASM, which is what's there now. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataAsyncIOLoop(RTTHREAD ThreadSelf, void *pvUser)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync const ATARequest *pReq;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64TS = 0; /* shut up gcc */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t uWait;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = (PATACONTROLLER)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pReq = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fChainedTransfer = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (!pCtl->fShutdown)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Keep this thread from doing anything as long as EMT is suspended. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (pCtl->fRedoIdle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventWait(pCtl->SuspendIOSem, RT_INDEFINITE_WAIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc) || pCtl->fShutdown)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fRedoIdle = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Wait for work. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pReq == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: going to sleep...\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventWait(pCtl->AsyncIOSem, RT_INDEFINITE_WAIT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: waking up\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc) || pCtl->fShutdown)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pReq = ataAsyncIOGetCurrentRequest(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pReq == NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync continue;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATAAIO ReqType = pReq->ReqType;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync Log2(("%s: Ctl#%d: state=%d, req=%d\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), pCtl->uAsyncIOState, ReqType));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->uAsyncIOState != ReqType)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync /* The new state is not the state that was expected by the normal
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * state changes. This is either a RESET/ABORT or there's something
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync * really strange going on. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if ( (pCtl->uAsyncIOState == ATA_AIO_PIO || pCtl->uAsyncIOState == ATA_AIO_DMA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (ReqType == ATA_AIO_PIO || ReqType == ATA_AIO_DMA))
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* Incorrect sequence of PIO/DMA states. Dump request queue. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataAsyncIODumpRequests(pCtl);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsg(ReqType == ATA_AIO_RESET_ASSERTED || ReqType == ATA_AIO_RESET_CLEARED || ReqType == ATA_AIO_ABORT || pCtl->uAsyncIOState == ReqType, ("I/O state inconsistent: state=%d request=%d\n", pCtl->uAsyncIOState, ReqType));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do our work. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync STAM_PROFILE_START(&pCtl->StatLockWait, a);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogBird(("ata: %x: entering critsect\n", pCtl->IOPortBase1));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogBird(("ata: %x: entered\n", pCtl->IOPortBase1));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync STAM_PROFILE_STOP(&pCtl->StatLockWait, a);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->uAsyncIOState == ATA_AIO_NEW && !pCtl->fChainedTransfer)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync u64TS = RTTimeNanoTS();
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync#if defined(DEBUG) || defined(VBOX_WITH_STATISTICS)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync STAM_PROFILE_ADV_START(&pCtl->StatAsyncTime, a);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync switch (ReqType)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync case ATA_AIO_NEW:
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->iAIOIf = pReq->u.t.iIf;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s = &pCtl->aIfs[pCtl->iAIOIf];
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s->cbTotalTransfer = pReq->u.t.cbTotalTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->uTxDir = pReq->u.t.uTxDir;
bbe8d54f2bca31d98ce10c89506ca5a53c9d41b7vboxsync s->iBeginTransfer = pReq->u.t.iBeginTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iSourceSink = pReq->u.t.iSourceSink;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->u64CmdTS = u64TS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fChainedTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Only count the actual transfers, not the PIO
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer of the ATAPI command bytes. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fDMA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REL_COUNTER_INC(&s->StatATAPIDMA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REL_COUNTER_INC(&s->StatATAPIPIO);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fDMA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REL_COUNTER_INC(&s->StatATADMA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_REL_COUNTER_INC(&s->StatATAPIO);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fChainedTransfer = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iBeginTransfer != ATAFN_BT_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: calling begin transfer function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync g_apfnBeginTransFuncs[s->iBeginTransfer](s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iBeginTransfer = ATAFN_BT_NULL;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->uTxDir != PDMBLOCKTXDIR_FROM_DEVICE)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iIOBufferEnd = s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->cbElementaryTransfer = s->cbTotalTransfer;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iIOBufferEnd = s->cbTotalTransfer;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iIOBufferCur = 0;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->iSourceSink != ATAFN_SS_NULL)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync bool fRedo;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: Ctl#%d: calling source/sink function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync fRedo = g_apfnSourceSinkFuncs[s->iSourceSink](s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->fRedo = fRedo;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (RT_UNLIKELY(fRedo))
dfec9ba035ff0c77d470041bc230a60542d39e27vboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Operation failed at the initial transfer, restart
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * everything from scratch by resending the current
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * request. Occurs very rarely, not worth optimizing. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync LogRel(("%s: Ctl#%d: redo entire operation\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataAsyncIOPutRequest(pCtl, pReq);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataSuspendRedo(pCtl);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataCmdOK(s, 0);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync s->iIOBufferEnd = s->cbElementaryTransfer;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
dfec9ba035ff0c77d470041bc230a60542d39e27vboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Do not go into the transfer phase if RESET is asserted.
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * The CritSect is released while waiting for the host OS
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * to finish the I/O, thus RESET is possible here. Most
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * important: do not change uAsyncIOState. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync break;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->fDMA)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->cbTotalTransfer)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataSetStatus(s, ATA_STAT_DRQ);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->uAsyncIOState = ATA_AIO_DMA;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* If BMDMA is already started, do the transfer now. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (pCtl->BmDma.u8Cmd & BM_CMD_START)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer immediately\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataAsyncIOPutRequest(pCtl, &ataDMARequest);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finish DMA transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataDMATransferStop(s);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataPIOTransfer(pCtl);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(!pCtl->fRedo);
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync if (s->fATAPITransfer || s->uTxDir != PDMBLOCKTXDIR_TO_DEVICE)
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE || s->iSourceSink != ATAFN_SS_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Write operations and not yet finished transfers
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * must be completed in the async I/O thread. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->uAsyncIOState = ATA_AIO_PIO;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finished read operation can be handled inline
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * in the end of PIO transfer handling code. Linux
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * depends on this, as it waits only briefly for
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * devices to become ready after incoming data
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * transfer. Cannot find anything in the ATA spec
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * that backs this assumption, but as all kernels
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * are affected (though most of the time it does
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync * not cause any harm) this must work. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync }
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync /* Finish PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!pCtl->fRedo);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!s->fATAPITransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_AIO_DMA:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync BMDMAState *bm = &pCtl->BmDma;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATAFNSS iOriginalSourceSink = (ATAFNSS)s->iSourceSink; /* Used by the hack below, but gets reset by then. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(bm->u8Cmd & BM_CMD_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(!(bm->u8Cmd & BM_CMD_WRITE));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (RT_LIKELY(!pCtl->fRedo))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The specs say that the descriptor table must not cross a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * 4K boundary. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->pFirstDMADesc = bm->pvAddr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->pLastDMADesc = RT_ALIGN_32(bm->pvAddr + 1, _4K) - sizeof(BMDMADesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataDMATransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if (RT_UNLIKELY(pCtl->fRedo))
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogRel(("PIIX3 ATA: Ctl#%d: redo DMA operation\n", ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &ataDMARequest);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataSuspendRedo(pCtl);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* The infamous delay IRQ hack. */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if ( iOriginalSourceSink == ATAFN_SS_WRITE_SECTORS
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync && s->cbTotalTransfer == 0
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync && pCtl->DelayIRQMillies)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync /* Delay IRQ for writing. Required to get the Win2K
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * installation work reliably (otherwise it crashes,
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * usually during component install). So far no better
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync * solution has been found. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: delay IRQ hack\n", __FUNCTION__));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync PDMCritSectLeave(&pCtl->lock);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync RTThreadSleep(pCtl->DelayIRQMillies);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataUnsetStatus(s, ATA_STAT_DRQ);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Assert(!pCtl->fChainedTransfer);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Assert(s->iSourceSink == ATAFN_SS_NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->fATAPITransfer)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s->uATARegNSector = (s->uATARegNSector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Log2(("%s: Ctl#%d: interrupt reason %#04x\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), s->uATARegNSector));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s->fATAPITransfer = false;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataSetIRQ(s);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync break;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync case ATA_AIO_PIO:
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if (s->iSourceSink != ATAFN_SS_NULL)
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync bool fRedo;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync Log2(("%s: Ctl#%d: calling source/sink function\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync fRedo = g_apfnSourceSinkFuncs[s->iSourceSink](s);
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync pCtl->fRedo = fRedo;
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync if (RT_UNLIKELY(fRedo))
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync {
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync LogRel(("PIIX3 ATA: Ctl#%d: redo PIO operation\n", ATACONTROLLER_IDX(pCtl)));
5793d23a719d4902824a3649b6fef3822ddd5fc7vboxsync ataAsyncIOPutRequest(pCtl, &ataPIORequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSuspendRedo(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferCur = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferEnd = s->cbElementaryTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Continue a previously started transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetStatus(s, ATA_STAT_BUSY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_READY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* It is possible that the drives on this controller get RESET
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * during the above call to the source/sink function. If that's
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the case, don't restart the transfer and don't finish it the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * usual way. RESET handling took care of all that already.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Most important: do not change uAsyncIOState. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->cbTotalTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->uTxDir == PDMBLOCKTXDIR_TO_DEVICE || s->iSourceSink != ATAFN_SS_NULL)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Write operations and not yet finished transfers
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * must be completed in the async I/O thread. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_PIO;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finished read operation can be handled inline
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * in the end of PIO transfer handling code. Linux
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * depends on this, as it waits only briefly for
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * devices to become ready after incoming data
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * transfer. Cannot find anything in the ATA spec
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * that backs this assumption, but as all kernels
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are affected (though most of the time it does
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * not cause any harm) this must work. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Finish PIO transfer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransfer(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( !pCtl->fChainedTransfer
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && !s->fATAPITransfer
09f4b412099acda62997fd82c8608075c453b3ebvboxsync && s->uTxDir != PDMBLOCKTXDIR_FROM_DEVICE)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_AIO_RESET_ASSERTED:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_RESET_CLEARED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStop(&pCtl->aIfs[0]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStop(&pCtl->aIfs[1]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not change the DMA registers, they are not affected by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA controller reset logic. It should be sufficient to issue a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * new command, which is now possible as the state is cleared. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_AIO_RESET_CLEARED:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fReset = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d: finished processing RESET\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pCtl->aIfs); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[i].fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatusValue(&pCtl->aIfs[i], 0); /* NOTE: READY is _not_ set */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
09f4b412099acda62997fd82c8608075c453b3ebvboxsync ataSetStatusValue(&pCtl->aIfs[i], ATA_STAT_READY | ATA_STAT_SEEK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetSignature(&pCtl->aIfs[i]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case ATA_AIO_ABORT:
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /* Abort the current command only if it operates on the same interface. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->iAIOIf == pReq->u.a.iIf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s = &pCtl->aIfs[pCtl->iAIOIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->uAsyncIOState = ATA_AIO_NEW;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not change the DMA registers, they are not affected by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * ATA controller reset logic. It should be sufficient to issue a
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * new command, which is now possible as the state is cleared. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pReq->u.a.fResetDrive)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataResetDevice(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataExecuteDeviceDiagnosticSS(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferStop(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataUnsetStatus(s, ATA_STAT_BUSY | ATA_STAT_DRQ | ATA_STAT_SEEK | ATA_STAT_ERR);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetStatus(s, ATA_STAT_READY);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataSetIRQ(s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Undefined async I/O state %d\n", pCtl->uAsyncIOState));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIORemoveCurrentRequest(pCtl, ReqType);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pReq = ataAsyncIOGetCurrentRequest(pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->uAsyncIOState == ATA_AIO_NEW && !pCtl->fChainedTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if defined(DEBUG) || defined(VBOX_WITH_STATISTICS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_PROFILE_ADV_STOP(&pCtl->StatAsyncTime, a);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync u64TS = RTTimeNanoTS() - u64TS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uWait = u64TS / 1000;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: Ctl#%d: LUN#%d finished I/O transaction in %d microseconds\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), pCtl->aIfs[pCtl->iAIOIf].iLUN, (uint32_t)(uWait)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Mark command as finished. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[pCtl->iAIOIf].u64CmdTS = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Release logging of command execution times depends on the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * command type. ATAPI commands often take longer (due to CD/DVD
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * spin up time etc.) so the threshold is different.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[pCtl->iAIOIf].uATARegCommand != ATA_PACKET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (uWait > 8 * 1000 * 1000)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Command took longer than 8 seconds. This is close
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * enough or over the guest's command timeout, so place
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * an entry in the release log to allow tracking such
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * timing errors (which are often caused by the host).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: execution time for ATA command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].uATARegCommand, uWait / (1000 * 1000)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (uWait > 20 * 1000 * 1000)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Command took longer than 20 seconds. This is close
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * enough or over the guest's command timeout, so place
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * an entry in the release log to allow tracking such
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * timing errors (which are often caused by the host).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: execution time for ATAPI command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].aATAPICmd[0], uWait / (1000 * 1000)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if defined(DEBUG) || defined(VBOX_WITH_STATISTICS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (uWait < pCtl->StatAsyncMinWait || !pCtl->StatAsyncMinWait)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->StatAsyncMinWait = uWait;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (uWait > pCtl->StatAsyncMaxWait)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->StatAsyncMaxWait = uWait;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_ADD(&pCtl->StatAsyncTimeUS, uWait);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync STAM_COUNTER_INC(&pCtl->StatAsyncOps);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* DEBUG || VBOX_WITH_STATISTICS */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: %x: leaving critsect\n", pCtl->IOPortBase1));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Cleanup the state. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->AsyncIOSem)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSemEventDestroy(pCtl->AsyncIOSem);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->AsyncIOSem = NIL_RTSEMEVENT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->SuspendIOSem)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSemEventDestroy(pCtl->SuspendIOSem);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->SuspendIOSem = NIL_RTSEMEVENT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not destroy request mutex yet, still needed for proper shutdown. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->fShutdown = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* This must be last, as it also signals thread exit to EMT. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->AsyncIOThread = NIL_RTTHREAD;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: return %Vrc\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl), rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMACmdReadB(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t val = pCtl->BmDma.u8Cmd;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMACmdWriteB(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!(val & BM_CMD_START))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status &= ~BM_STATUS_DMAING;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Cmd = val & (BM_CMD_START | BM_CMD_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check whether the guest OS wants to change DMA direction in
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * mid-flight. Not allowed, according to the PIIX3 specs. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!(pCtl->BmDma.u8Status & BM_STATUS_DMAING) || !((val ^ pCtl->BmDma.u8Cmd) & 0x04));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status |= BM_STATUS_DMAING;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Cmd = val & (BM_CMD_START | BM_CMD_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not continue DMA transfers while the RESET line is asserted. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->fReset)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: suppressed continuing DMA transfer as RESET is active\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not start DMA transfers if there's a PIO transfer going on. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pCtl->aIfs[pCtl->iSelectedIf].fDMA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pCtl->aIfs[pCtl->iAIOIf].uATARegStatus & ATA_STAT_DRQ)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, continuing DMA transfer\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(pCtl, &ataDMARequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("DMA START handling is too complicated for GC\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMAStatusReadB(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t val = pCtl->BmDma.u8Status;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAStatusWriteB(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#04x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.u8Status = (val & (BM_STATUS_D0DMA | BM_STATUS_D1DMA))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (pCtl->BmDma.u8Status & BM_STATUS_DMAING)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (pCtl->BmDma.u8Status & ~val & (BM_STATUS_ERROR | BM_STATUS_INT));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic uint32_t ataBMDMAAddrReadL(PATACONTROLLER pCtl, uint32_t addr)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t val = (uint32_t)pCtl->BmDma.pvAddr;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return val;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteL(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.pvAddr = val & ~3;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteLowWord(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->BmDma.pvAddr = (pCtl->BmDma.pvAddr & 0xFFFF0000) | RT_LOWORD(val & ~3);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic void ataBMDMAAddrWriteHighWord(PATACONTROLLER pCtl, uint32_t addr, uint32_t val)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync Log2(("%s: addr=%#06x val=%#010x\n", __FUNCTION__, addr, val));
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync pCtl->BmDma.pvAddr = (RT_LOWORD(val) << 16) | RT_LOWORD(pCtl->BmDma.pvAddr);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#define VAL(port, size) ( ((port) & 7) | ((size) << 3) )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for bus master DMA IN operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTIN for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync int rc;
340ee06f35257fee1bd68223ab3504cf2b1d0c3evboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (VAL(Port, cb))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(0, 1): *pu32 = ataBMDMACmdReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(0, 2): *pu32 = ataBMDMACmdReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 1): *pu32 = ataBMDMAStatusReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 2): *pu32 = ataBMDMAStatusReadB(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 4): *pu32 = ataBMDMAAddrReadL(pCtl, Port); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("%s: Unsupported read from port %x size=%d\n", __FUNCTION__, Port, cb));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_IOM_IOPORT_UNUSED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for bus master DMA OUT operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUT for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataBMDMAIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (VAL(Port, cb))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(0, 1):
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (u32 & BM_CMD_START)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_IOM_HC_IOPORT_WRITE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataBMDMACmdWriteB(pCtl, Port, u32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(2, 1): ataBMDMAStatusWriteB(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 4): ataBMDMAAddrWriteL(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(4, 2): ataBMDMAAddrWriteLowWord(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case VAL(6, 2): ataBMDMAAddrWriteHighWord(pCtl, Port, u32); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default: AssertMsgFailed(("%s: Unsupported write to port %x size=%d val=%x\n", __FUNCTION__, Port, cb, u32)); break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#undef VAL
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Callback function for mapping an PCI I/O region.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @return VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iRegion The region number.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * I/O port, else it's a physical address.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This address is *NOT* relative to pci_mem_base like earlier!
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmType One of the PCI_ADDRESS_SPACE_* values.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataBMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PCIDEV_2_PCIATASTATE(pPciDev);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(enmType == PCI_ADDRESS_SPACE_IO);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(iRegion == 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Register the port range. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc2 = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTHCPTR)i, ataBMDMAIOPortWrite, ataBMDMAIOPortRead, NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc2 < rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->fGCEnabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = PDMDevHlpIOPortRegisterGC(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTGCPTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead", NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc2 < rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->fR0Enabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc2 = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress + i * 8, 8,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync (RTR0PTR)i, "ataBMDMAIOPortWrite", "ataBMDMAIOPortRead", NULL, NULL, "ATA Bus Master DMA");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc2 < rc)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = rc2;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Reset notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataReset(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].iSelectedIf = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].iAIOIf = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].BmDma.u8Cmd = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Report that both drives present on the bus are in DMA mode. This
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * pretends that there is a BIOS that has set it up. Normal reset
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * default is 0x00. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].BmDma.u8Status = (pData->aCts[i].aIfs[0].pDrvBase != NULL ? BM_STATUS_D0DMA : 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync | (pData->aCts[i].aIfs[1].pDrvBase != NULL ? BM_STATUS_D1DMA : 0);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].BmDma.pvAddr = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].fReset = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].fRedo = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].fRedoIdle = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOClearRequests(&pData->aCts[i]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log2(("%s: Ctl#%d: message to async I/O thread, reset controller\n", __FUNCTION__, i));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(&pData->aCts[i], &ataResetARequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataAsyncIOPutRequest(&pData->aCts[i], &ataResetCRequest);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!ataWaitForAsyncIOIsIdle(&pData->aCts[i], 30000))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsgFailed(("Async I/O thread busy after reset\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataResetDevice(&pData->aCts[i].aIfs[j]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- PCIATAState::IBase -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Queries an interface to the driver.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns Pointer to interface.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns NULL if the interface was not supported by the device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to ATADevState::IBase.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param enmInterface The requested interface identification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void *) ataStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMIBASE_2_PCIATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (enmInterface)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case PDMINTERFACE_BASE:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return &pData->IBase;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case PDMINTERFACE_LED_PORTS:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return &pData->ILeds;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync default:
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- PCIATAState::ILeds -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Gets the pointer to the status LED of a unit.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The unit which status LED we desire.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param ppLed Where to store the LED pointer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMILEDPORTS_2_PCIATASTATE(pInterface);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (iLUN >= 0 && iLUN <= 4)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync switch (iLUN)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 0: *ppLed = &pData->aCts[0].aIfs[0].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 1: *ppLed = &pData->aCts[0].aIfs[1].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 2: *ppLed = &pData->aCts[1].aIfs[0].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync case 3: *ppLed = &pData->aCts[1].aIfs[1].Led; break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_PDM_LUN_NOT_FOUND;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/* -=-=-=-=-=- ATADevState::IBase -=-=-=-=-=- */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Queries an interface to the driver.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync *
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns Pointer to interface.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @returns NULL if the interface was not supported by the device.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param pInterface Pointer to ATADevState::IBase.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @param enmInterface The requested interface identification.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncstatic DECLCALLBACK(void *) ataQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = PDMIBASE_2_ATASTATE(pInterface);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync switch (enmInterface)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync case PDMINTERFACE_BASE:
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return &pIf->IBase;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync case PDMINTERFACE_BLOCK_PORT:
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return &pIf->IPort;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync case PDMINTERFACE_MOUNT_NOTIFY:
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return &pIf->IMountNotify;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync default:
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return NULL;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync}
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync#endif /* IN_RING3 */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync/* -=-=-=-=-=- Wrappers -=-=-=-=-=- */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync/**
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range OUT operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTOUT for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(i < 2);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (rc != VINF_SUCCESS)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return rc;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (cb == 1)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = ataIOPortWriteU8(pCtl, Port, u32);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync else if (Port == pCtl->IOPortBase1)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync {
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(cb == 2 || cb == 4);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = ataDataWrite(pCtl, Port, cb, (const uint8_t *)&u32);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("ataIOPortWrite1: unsupported write to port %x val=%x size=%d\n", Port, u32, cb));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogBird(("ata: leaving critsect\n"));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PDMCritSectLeave(&pCtl->lock);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync LogBird(("ata: left critsect\n"));
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return rc;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range IN operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTIN for details.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync */
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsyncPDMBOTHCBDECL(int) ataIOPortRead1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync int rc = VINF_SUCCESS;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(i < 2);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (rc != VINF_SUCCESS)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync return rc;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync if (cb == 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataIOPortReadU8(pCtl, Port, pu32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (Port == pCtl->IOPortBase1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cb == 2 || cb == 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataDataRead(pCtl, Port, cb, (uint8_t *)pu32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cb == 2)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pu32 &= 0xffff;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("ataIOPortRead1: unsupported read from port %x size=%d\n", Port, cb));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_IOM_IOPORT_UNUSED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING0
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync/**
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * Port I/O Handler for primary port range IN string operations.
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync * @see FNIOMIOPORTINSTRING for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortReadStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, unsigned *pcTransfer, unsigned cb)
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync{
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync int rc = VINF_SUCCESS;
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync Assert(i < 2);
3a343ca21a267ec3c54e2317e2ed18fe99b8ebbbvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (Port == pCtl->IOPortBase1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cTransAvailable, cTransfer = *pcTransfer, cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPTR GCDst = *pGCPtrDst;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cb == 2 || cb == 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable--;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * They are not performance-critical and generally shouldn't occur at all. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cTransAvailable > cTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = cTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cTransAvailable * cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_GC
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < cbTransfer; i += cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMGCRamWriteNoTrapHandler((char *)GCDst + i, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysWriteGCPtrDirty(PDMDevHlpGetVM(pDevIns), GCDst, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(rc == VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataStart += cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pGCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCDst + cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcTransfer = cTransfer - cTransAvailable;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferFinish(pCtl, s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for primary port range OUT string operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUTSTRING for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortWriteStr1(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, unsigned *pcTransfer, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(i < 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (Port == pCtl->IOPortBase1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t cTransAvailable, cTransfer = *pcTransfer, cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTGCPTR GCSrc = *pGCPtrSrc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *s = &pCtl->aIfs[pCtl->iSelectedIf];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(cb == 2 || cb == 4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = (s->iIOBufferPIODataEnd - s->iIOBufferPIODataStart) / cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifndef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The last transfer unit cannot be handled in GC, as it involves thread communication. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable--;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Do not handle the dummy transfer stuff here, leave it to the single-word transfers.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * They are not performance-critical and generally shouldn't occur at all. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cTransAvailable > cTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cTransAvailable = cTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync cbTransfer = cTransAvailable * cb;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_GC
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < cbTransfer; i += cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync MMGCRamReadNoTrapHandler(s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart + i, (char *)GCSrc + i, cb);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else /* !IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PGMPhysReadGCPtr(PDMDevHlpGetVM(pDevIns), s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(rc == VINF_SUCCESS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_GC */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cbTransfer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log3(("%s: addr=%#x val=%.*Vhxs\n", __FUNCTION__, Port, cbTransfer, s->CTXSUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->iIOBufferPIODataStart += cbTransfer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pGCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCSrc + cbTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pcTransfer = cTransfer - cTransAvailable;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->iIOBufferPIODataStart >= s->iIOBufferPIODataEnd)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataPIOTransferFinish(pCtl, s);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* IN_RING3 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif /* !IN_RING0 */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for secondary port range OUT operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTOUT for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortWrite2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(i < 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cb != 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_WRITE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataControlWrite(pCtl, Port, u32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Port I/O Handler for secondary port range IN operations.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @see FNIOMIOPORTIN for details.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncPDMBOTHCBDECL(int) ataIOPortRead2(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t i = (uint32_t)(uintptr_t)pvUser;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(i < 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (cb != 1)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_IOM_IOPORT_UNUSED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMCritSectEnter(&pCtl->lock, VINF_IOM_HC_IOPORT_READ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VINF_SUCCESS)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *pu32 = ataStatusRead(pCtl, Port);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMCritSectLeave(&pCtl->lock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef IN_RING3
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Waits for all async I/O threads to complete whatever they
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * are doing at the moment.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns true on success.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns false when one or more threads is still processing.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pData Pointer to the instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param cMillies How long to wait (total).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, unsigned cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fVMLocked;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64Start;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fAllIdle = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* The only way to deal cleanly with the VM lock is to check whether
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * it is owned now (it always is owned by EMT, which is the current
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * thread). Since this function is called several times during VM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * shutdown, and the VM lock is only held for the first call (which
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * can be either from ataPowerOff or ataSuspend), there is no other
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * reasonable solution. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fVMLocked = VMMR3LockIsOwner(PDMDevHlpGetVM(pDevIns));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fVMLocked)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pDevIns->pDevHlp->pfnUnlockVM(pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for any pending async operation to finish
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync u64Start = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (;;)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Check all async I/O threads. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fAllIdle = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fAllIdle &= ataAsyncIOIsIdle(pCtl, false);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fAllIdle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( fAllIdle
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || RTTimeMilliTS() - u64Start >= cMillies)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTThreadSleep(100);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fVMLocked)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pDevIns->pDevHlp->pfnLockVM(pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!fAllIdle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: Ctl#%d is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATACONTROLLER_IDX(pCtl), pCtl->iSelectedIf, pCtl->iAIOIf,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl->aIfs[0].uATARegCommand, pCtl->aIfs[1].uATARegCommand));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync return fAllIdle;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncDECLINLINE(void) ataRelocBuffer(PPDMDEVINS pDevIns, ATADevState *s)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (s->pbIOBufferHC)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync s->pbIOBufferGC = MMHyperHC2GC(PDMDevHlpGetVM(pDevIns), s->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @copydoc FNPDMDEVRELOCATE
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].pDevInsGC += offDelta;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[0].pDevInsGC += offDelta;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[0].pControllerGC += offDelta;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataRelocBuffer(pDevIns, &pData->aCts[i].aIfs[0]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[1].pDevInsGC += offDelta;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[1].pControllerGC += offDelta;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataRelocBuffer(pDevIns, &pData->aCts[i].aIfs[1]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Destroy a driver instance.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * resources can be freed correctly.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataDestruct(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s:\n", __FUNCTION__));
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Terminate all async helper threads
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].AsyncIOThread != NIL_RTTHREAD)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ASMAtomicXchgU32(&pData->aCts[i].fShutdown, true);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventSignal(pData->aCts[i].AsyncIOSem);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Wait for them to complete whatever they are doing and then
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * for them to terminate.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t u64Start = RTTimeMilliTS();
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync bool fAllDone;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (;;)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* check */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fAllDone = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts) && fAllDone; i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fAllDone &= (pData->aCts[i].AsyncIOThread == NIL_RTTHREAD);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( fAllDone
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || RTTimeMilliTS() - u64Start >= 500)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync break;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Sleep for a bit. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTThreadSleep(100);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(fAllDone, ("Some of the async I/O threads are still running!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Async I/O is still busy!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Now the request mutexes are no longer needed. Free resources.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].AsyncIORequestMutex)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync RTSemMutexDestroy(pData->aCts[i].AsyncIORequestMutex);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].AsyncIORequestMutex = NIL_RTSEMEVENT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Detach notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The DVD drive has been unplugged.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The logical unit which is being detached.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataDetach(PPDMDEVINS pDevIns, unsigned iLUN)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pThis = PDMINS2DATA(pDevIns, PCIATAState *);
cf5a77c331ff5d2e6851345fef307d6ceee73097vboxsync PATACONTROLLER pCtl;
cf5a77c331ff5d2e6851345fef307d6ceee73097vboxsync ATADevState *pIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned iController;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned iInterface;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Locate the controller and stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iController = iLUN / RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl = &pThis->aCts[iController];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iInterface = iLUN % RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf = &pCtl->aIfs[iInterface];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Zero some important members.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBase = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlock = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvMount = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Configure a LUN.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pIf The ATA unit state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic int ataConfigLun(PPDMDEVINS pDevIns, ATADevState *pIf)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMBLOCKTYPE enmType;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Query Block, Bios and Mount interfaces.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlock = (PDMIBLOCK *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pIf->pDrvBlock)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_PDM_MISSING_INTERFACE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /** @todo implement the BIOS invisible code path. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios = (PDMIBLOCKBIOS *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pIf->pDrvBlockBios)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pIf->iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_PDM_MISSING_INTERFACE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvMount = (PDMIMOUNT *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_MOUNT);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Validate type.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync enmType = pIf->pDrvBlock->pfnGetType(pIf->pDrvBlock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( enmType != PDMBLOCKTYPE_CDROM
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && enmType != PDMBLOCKTYPE_DVD
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && enmType != PDMBLOCKTYPE_HARD_DISK)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd-rom. enmType=%d\n", pIf->iLUN, enmType));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( ( enmType == PDMBLOCKTYPE_DVD
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || enmType == PDMBLOCKTYPE_CDROM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && !pIf->pDrvMount)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Internal error: cdrom without a mountable interface, WTF???!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_INTERNAL_ERROR;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->fATAPI = enmType == PDMBLOCKTYPE_DVD || enmType == PDMBLOCKTYPE_CDROM;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->fATAPIPassthrough = pIf->fATAPI ? (pIf->pDrvBlock->pfnSendCmd != NULL) : false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Allocate I/O buffer.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PVM pVM = PDMDevHlpGetVM(pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->cbIOBuffer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Buffer is (probably) already allocated. Validate the fields,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * because memory corruption can also overwrite pIf->cbIOBuffer. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(pIf->cbIOBuffer == _128K);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(pIf->cbIOBuffer == ATA_MAX_MULT_SECTORS * 512);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pIf->pbIOBufferGC == MMHyperHC2GC(pVM, pIf->pbIOBufferHC));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cbIOBuffer = _128K;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cbIOBuffer = ATA_MAX_MULT_SECTORS * 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(!pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = MMHyperAlloc(pVM, pIf->cbIOBuffer, 1, MM_TAG_PDM_DEVICE_USER, (void **)&pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_NO_MEMORY;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pbIOBufferGC = MMHyperHC2GC(pVM, pIf->pbIOBufferHC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Init geometry.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->fATAPI)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 2048;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = 0; /* dummy */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSHeads = 0; /* dummy */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSSectors = 0; /* dummy */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc != VERR_PDM_MEDIA_NOT_MOUNTED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_NONE);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cTotalSectors = pIf->pDrvBlock->pfnGetSize(pIf->pDrvBlock) / 512;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetGeometry(pIf->pDrvBlockBios, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSHeads = 16; /*??*/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSSectors = 63; /*??*/
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMBIOSTRANSLATION enmTranslation;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_PDM_TRANSLATION_NOT_SET)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync enmTranslation = PDMBIOSTRANSLATION_AUTO;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if ( enmTranslation == PDMBIOSTRANSLATION_AUTO
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && ( pIf->cCHSCylinders == 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || pIf->cCHSHeads == 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || pIf->cCHSSectors == 0
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync )
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Image contains no geometry information, detect geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataGuessDiskLCHS(pIf, &pIf->cCHSCylinders, &pIf->cCHSHeads, &pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Caution: the above function returns LCHS, but the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * disk must report proper PCHS values for disks bigger
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * than approximately 512MB. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pIf->cCHSSectors == 63 && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = pIf->cTotalSectors / 63 / 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSHeads = 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSSectors = 63;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk CHS translation mode. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlockBios->pfnSetTranslation(pIf->pDrvBlockBios, PDMBIOSTRANSLATION_LBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk geometry information. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Flag geometry as invalid, will be replaced below by the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * default geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!pIf->cCHSCylinders)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* If there is no geometry, use standard physical disk geometry.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This uses LCHS to LBA translation in the BIOS (which selects
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the logical sector count 63 and the logical head count to be
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * the smallest of 16,32,64,128,255 which makes the logical
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * cylinder count smaller than 1024 - if that's not possible, it
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * uses 255 heads, so up to about 8 GByte maximum with the
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * standard int13 interface, which supports 1024 cylinders). */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = (uint32_t)RT_MAX(cCHSCylinders, 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSHeads = 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSSectors = 63;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Set the disk geometry information. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnSetGeometry(pIf->pDrvBlockBios, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMBIOSTRANSLATION enmTranslation;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = pIf->pDrvBlockBios->pfnGetTranslation(pIf->pDrvBlockBios, &enmTranslation);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (( rc == VERR_PDM_TRANSLATION_NOT_SET
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync || enmTranslation == PDMBIOSTRANSLATION_LBA)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && pIf->cCHSSectors == 63
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync && (pIf->cCHSHeads != 16 || pIf->cCHSCylinders >= 1024))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Use the official LBA physical CHS geometry. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint64_t cCHSCylinders = pIf->cTotalSectors / (16 * 63);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSCylinders = RT_MAX((uint32_t)RT_MIN(cCHSCylinders, 16383), 1);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSHeads = 16;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->cCHSSectors = 63;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* DO NOT write back the disk geometry information. This
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * intentionally sets the ATA geometry only. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("PIIX3 ATA: LUN#%d: disk, CHS=%d/%d/%d, total number of sectors %Ld\n", pIf->iLUN, pIf->cCHSCylinders, pIf->cCHSHeads, pIf->cCHSSectors, pIf->cTotalSectors));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Attach command.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * This is called when we change block driver for the DVD drive.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param iLUN The logical unit which is being detached.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataAttach(PPDMDEVINS pDevIns, unsigned iLUN)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pThis = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PATACONTROLLER pCtl;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned iController;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync unsigned iInterface;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Locate the controller and stuff.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iController = iLUN / RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pCtl = &pThis->aCts[iController];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync iInterface = iLUN % RT_ELEMENTS(pThis->aCts[0].aIfs);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf = &pCtl->aIfs[iInterface];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* the usual paranoia */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(!pIf->pDrvBase);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRelease(!pIf->pDrvBlock);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(ATADEVSTATE_2_CONTROLLER(pIf) == pCtl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pIf->iLUN == iLUN);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Try attach the block device and get the interfaces,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * required as well as optional.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpDriverAttach(pDevIns, pIf->iLUN, &pIf->IBase, &pIf->pDrvBase, NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_SUCCESS(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = ataConfigLun(pDevIns, pIf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Failed to attach LUN#%d. rc=%Vrc\n", pIf->iLUN, rc));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBase = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pIf->pDrvBlock = NULL;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Suspend notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataSuspend(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s:\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Resume notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataResume(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s:\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].fRedo && pData->aCts[i].fRedoIdle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = RTSemEventSignal(pData->aCts[i].SuspendIOSem);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertRC(rc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Power Off notification.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance data.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(void) ataPowerOff(PPDMDEVINS pDevIns)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s:\n", __FUNCTION__));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("Async I/O didn't stop in 20 seconds!\n"));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Prepare state save and load operation.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns Device instance of the device which registered the data unit.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSM SSM operation handle.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataSaveLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* sanity - the suspend notification will wait on the async stuff. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(ataAsyncIOIsIdle(&pData->aCts[i], false));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (!ataAsyncIOIsIdle(&pData->aCts[i], false))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_SSM_IDE_ASYNC_TIMEOUT;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Saves a state of the ATA device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSMHandle The handle to save the state to.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].iSelectedIf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].iAIOIf);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].uAsyncIOState);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fChainedTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fReset);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fRedo);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fRedoIdle);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].fRedoDMALastDesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].BmDma, sizeof(pData->aCts[i].BmDma));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pFirstDMADesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pLastDMADesc);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutGCPhys(pSSMHandle, pData->aCts[i].pRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].cbRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fLBA48);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fATAPI);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fIrqPending);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].cMultSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSCylinders);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cCHSSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cSectorsPerIRQ);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU64(pSSMHandle, pData->aCts[i].aIfs[j].cTotalSectors);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegFeature);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegFeatureHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegError);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegNSector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegNSectorHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSectorHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegLCyl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegLCylHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegHCyl);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegHCylHOB);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegSelect);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegStatus);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegCommand);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATARegDevCtl);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATATransferMode);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uTxDir);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].iBeginTransfer);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].iSourceSink);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fDMA);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync SSMR3PutBool(pSSMHandle, pData->aCts[i].aIfs[j].fATAPITransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbTotalTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferPIODataStart);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iIOBufferPIODataEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbATAPISector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATAPISenseKey);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].uATAPIASC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU8(pSSMHandle, pData->aCts[i].aIfs[j].cNotifiedMediaChange);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, &pData->aCts[i].aIfs[j].Led, sizeof(pData->aCts[i].aIfs[j].Led));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutU32(pSSMHandle, pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].aIfs[j].cbIOBuffer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer) == NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3PutBool(pSSMHandle, pData->fPIIX4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Loads a saved ATA device state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync *
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @returns VBox status code.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pDevIns The device instance.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param pSSMHandle The handle to the saved state.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * @param u32Version The data unit version number.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsyncstatic DECLCALLBACK(int) ataLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync{
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync int rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint32_t u32;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (u32Version != ATA_SAVED_STATE_VERSION)
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("u32Version=%d\n", u32Version));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Restore valid parts of the PCIATAState structure
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
87150caf549846b0edba30c50dabe5092df70b5fvboxsync {
87150caf549846b0edba30c50dabe5092df70b5fvboxsync /* integrity check */
87150caf549846b0edba30c50dabe5092df70b5fvboxsync if (!ataAsyncIOIsIdle(&pData->aCts[i], false))
87150caf549846b0edba30c50dabe5092df70b5fvboxsync {
87150caf549846b0edba30c50dabe5092df70b5fvboxsync AssertMsgFailed(("Async I/O for controller %d is active\n", i));
87150caf549846b0edba30c50dabe5092df70b5fvboxsync rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync return rc;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync }
87150caf549846b0edba30c50dabe5092df70b5fvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].iSelectedIf);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].iAIOIf);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].uAsyncIOState);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].fChainedTransfer);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fReset);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedo);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedoIdle);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, (bool *)&pData->aCts[i].fRedoDMALastDesc);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].BmDma, sizeof(pData->aCts[i].BmDma));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pFirstDMADesc);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pLastDMADesc);
441b60f8b0601cc1718368c9c3ef082223ad12a2vboxsync SSMR3GetGCPhys(pSSMHandle, &pData->aCts[i].pRedoDMABuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].cbRedoDMABuffer);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fLBA48);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fATAPI);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fIrqPending);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].cMultSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSCylinders);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSHeads);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cCHSSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cSectorsPerIRQ);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU64(pSSMHandle, &pData->aCts[i].aIfs[j].cTotalSectors);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegFeature);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegFeatureHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegError);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegNSector);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegNSectorHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSector);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSectorHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegLCyl);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegLCylHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegHCyl);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegHCylHOB);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegSelect);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegStatus);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegCommand);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATARegDevCtl);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATATransferMode);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uTxDir);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].iBeginTransfer);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].iSourceSink);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fDMA);
87150caf549846b0edba30c50dabe5092df70b5fvboxsync SSMR3GetBool(pSSMHandle, &pData->aCts[i].aIfs[j].fATAPITransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbTotalTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbElementaryTransfer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferCur);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferEnd);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferPIODataStart);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iIOBufferPIODataEnd);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].iATAPILBA);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbATAPISector);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].aIfs[j].aATAPICmd, sizeof(pData->aCts[i].aIfs[j].aATAPICmd));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATAPISenseKey);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].uATAPIASC);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &pData->aCts[i].aIfs[j].cNotifiedMediaChange);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, &pData->aCts[i].aIfs[j].Led, sizeof(pData->aCts[i].aIfs[j].Led));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU32(pSSMHandle, &pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].aIfs[j].cbIOBuffer)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetMem(pSSMHandle, pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer), pData->aCts[i].aIfs[j].cbIOBuffer);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync LogRel(("ATA: No buffer for %d/%d\n", i, j));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VERR_SSM_LOAD_CONFIG_MISMATCH;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* skip the buffer if we're loading for the debugger / animator. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync uint8_t u8Ignored;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync size_t cbLeft = pData->aCts[i].aIfs[j].cbIOBuffer;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync while (cbLeft-- > 0)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetU8(pSSMHandle, &u8Ignored);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(pData->aCts[i].aIfs[j].CTXSUFF(pbIOBuffer) == NULL);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync SSMR3GetBool(pSSMHandle, &pData->fPIIX4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = SSMR3GetU32(pSSMHandle, &u32);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (u32 != ~0U)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsgFailed(("u32=%#x expected ~0\n", u32));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return rc;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return VINF_SUCCESS;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync}
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
87150caf549846b0edba30c50dabe5092df70b5fvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync/**
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * Construct a device instance for a VM.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync *
09f4b412099acda62997fd82c8608075c453b3ebvboxsync * @returns VBox status.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param pDevIns The device instance data.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * If the registration structure is needed, pDevIns->pDevReg points to it.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param iInstance Instance number. Use this to figure out which registers and such to use.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * The device number is also found in pDevIns->iInstance, but since it's
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * likely to be freqently used PDM passes it as parameter.
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * of the device instance. It's also found in pDevIns->pCfgHandle, but like
87150caf549846b0edba30c50dabe5092df70b5fvboxsync * iInstance it's expected to be used a bit in this function.
09f4b412099acda62997fd82c8608075c453b3ebvboxsync */
09f4b412099acda62997fd82c8608075c453b3ebvboxsyncstatic DECLCALLBACK(int) ataConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
09f4b412099acda62997fd82c8608075c453b3ebvboxsync{
09f4b412099acda62997fd82c8608075c453b3ebvboxsync PCIATAState *pData = PDMINS2DATA(pDevIns, PCIATAState *);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync PPDMIBASE pBase;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync int rc;
09f4b412099acda62997fd82c8608075c453b3ebvboxsync bool fGCEnabled;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync bool fR0Enabled;
87150caf549846b0edba30c50dabe5092df70b5fvboxsync uint32_t DelayIRQMillies;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(iInstance == 0);
09f4b412099acda62997fd82c8608075c453b3ebvboxsync
09f4b412099acda62997fd82c8608075c453b3ebvboxsync /*
db31571ec38a249cccfa0712989d810a68a9300fvboxsync * Validate and read configuration.
db31571ec38a249cccfa0712989d810a68a9300fvboxsync */
db31571ec38a249cccfa0712989d810a68a9300fvboxsync if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0IRQDelay\0R0Enabled\0PIIX4\0"))
db31571ec38a249cccfa0712989d810a68a9300fvboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
db31571ec38a249cccfa0712989d810a68a9300fvboxsync N_("PIIX3 configuration error: unknown option specified."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fGCEnabled = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read GCEnabled as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync fR0Enabled = true;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read R0Enabled as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryU32(pCfgHandle, "IRQDelay", &DelayIRQMillies);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync DelayIRQMillies = 0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read IRQDelay as integer."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: DelayIRQMillies=%d\n", __FUNCTION__, DelayIRQMillies));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Assert(DelayIRQMillies < 50);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = CFGMR3QueryBool(pCfgHandle, "PIIX4", &pData->fPIIX4);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->fPIIX4 = false;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 configuration error: failed to read PIIX4 as boolean."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync Log(("%s: fPIIX4=%d\n", __FUNCTION__, pData->fPIIX4));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Initialize data (most of it anyway).
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* Status LUN. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->IBase.pfnQueryInterface = ataStatus_QueryInterface;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->ILeds.pfnQueryStatusLed = ataStatus_QueryStatusLed;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /* pci */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x00] = 0x86; /* Vendor: Intel */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x01] = 0x80;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (pData->fPIIX4)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x02] = 0x11; /* Device: PIIX4 IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x03] = 0x71;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x08] = 0x01; /* Revision: PIIX4E */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x48] = 0x00; /* UDMACTL */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x4A] = 0x00; /* UDMATIM */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x4B] = 0x00;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x02] = 0x10; /* Device: PIIX3 IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x03] = 0x70;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x09] = 0x8a; /* programming interface = PCI_IDE bus master is supported */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x0a] = 0x01; /* class_sub = PCI_IDE */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x0b] = 0x01; /* class_base = PCI_mass_storage */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->dev.config[0x0e] = 0x00; /* header_type */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->pDevIns = pDevIns;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->fGCEnabled = fGCEnabled;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->fR0Enabled = fR0Enabled;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].pDevInsHC = pDevIns;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].DelayIRQMillies = (uint32_t)DelayIRQMillies;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].iLUN = i * RT_ELEMENTS(pData->aCts) + j;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].pDevInsHC = pDevIns;
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
9cdd4d805ecb43126372f7cf12e4032836cb738avboxsync pData->aCts[i].aIfs[j].pControllerHC = &pData->aCts[i];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[j].pControllerGC = MMHyperHC2GC(PDMDevHlpGetVM(pDevIns), &pData->aCts[i]);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[i].aIfs[j].IBase.pfnQueryInterface = ataQueryInterface;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].IMountNotify.pfnMountNotify = ataMountNotify;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].IMountNotify.pfnUnmountNotify = ataUnmountNotify;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync pData->aCts[i].aIfs[j].Led.u32Magic = PDMLED_MAGIC;
e6ad2e18e663b076aeabfec994947514566a7accvboxsync }
e6ad2e18e663b076aeabfec994947514566a7accvboxsync }
e6ad2e18e663b076aeabfec994947514566a7accvboxsync
e6ad2e18e663b076aeabfec994947514566a7accvboxsync Assert(RT_ELEMENTS(pData->aCts) == 2);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[0].irq = 14;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[0].IOPortBase1 = 0x1f0;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[0].IOPortBase2 = 0x3f6;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[1].irq = 15;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[1].IOPortBase1 = 0x170;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync pData->aCts[1].IOPortBase2 = 0x376;
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Register the PCI device.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * N.B. There's a hack in the PIIX3 PCI bridge device to assign this
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * device the slot next to itself.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 cannot register PCI device."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync AssertMsg(pData->dev.devfn == 9 || iInstance != 0, ("pData->dev.devfn=%d\n", pData->dev.devfn));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ataBMDMAIORangeMap);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync N_("PIIX3 cannot register PCI I/O region for BMDMA."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync /*
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * Register the I/O ports.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync * The ports are all hardcoded and enforced by the PIIX3 host bridge controller.
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTHCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataIOPortWrite1, ataIOPortRead1, ataIOPortWriteStr1, ataIOPortReadStr1, "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register I/O handlers."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fGCEnabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTGCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", "ataIOPortWriteStr1", "ataIOPortReadStr1", "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register I/O handlers (GC)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fR0Enabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#if 1
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", NULL, NULL, "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#else
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase1, 8, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite1", "ataIOPortRead1", "ataIOPortWriteStr1", "ataIOPortReadStr1", "ATA I/O Base 1");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, "PIIX3 cannot register I/O handlers (R0).");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegister(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTHCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ataIOPortWrite2, ataIOPortRead2, NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fGCEnabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTGCPTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (GC)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (fR0Enabled)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, pData->aCts[i].IOPortBase2, 1, (RTR0PTR)i,
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync "ataIOPortWrite2", "ataIOPortRead2", NULL, NULL, "ATA I/O Base 2");
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync if (VBOX_FAILURE(rc))
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register base2 I/O handlers (R0)."));
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync for (uint32_t j = 0; j < RT_ELEMENTS(pData->aCts[i].aIfs); j++)
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync {
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync ATADevState *pIf = &pData->aCts[i].aIfs[j];
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATADMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA DMA transfers.", "/Devices/ATA%d/Unit%d/DMA", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATA PIO transfers.", "/Devices/ATA%d/Unit%d/PIO", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIDMA, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI DMA transfers.", "/Devices/ATA%d/Unit%d/AtapiDMA", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatATAPIPIO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of ATAPI PIO transfers.", "/Devices/ATA%d/Unit%d/AtapiPIO", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_STATISTICS /** @todo release too. */
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatReads, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the read operations.", "/Devices/ATA%d/Unit%d/Reads", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data read.", "/Devices/ATA%d/Unit%d/ReadBytes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatWrites, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the write operations.","/Devices/ATA%d/Unit%d/Writes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data written.", "/Devices/ATA%d/Unit%d/WrittenBytes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync PDMDevHlpSTAMRegisterF(pDevIns, &pIf->StatFlushes, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of the flush operations.","/Devices/ATA%d/Unit%d/Flushes", i, j);
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#endif
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync }
9055f61bb57d2a625c6434d55beac7565c3b3c0dvboxsync#ifdef VBOX_WITH_STATISTICS /** @todo release too. */
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncOps, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "The number of async operations.", "/Devices/ATA%d/Async/Operations", i);
/** @todo STAMUNIT_MICROSECS */
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncMinWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Minimum wait in microseconds.", "/Devices/ATA%d/Async/MinWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncMaxWait, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Maximum wait in microseconds.", "/Devices/ATA%d/Async/MaxWait", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncTimeUS, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE, "Total time spent in microseconds.","/Devices/ATA%d/Async/TotalTimeUS", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatAsyncTime, STAMTYPE_PROFILE_ADV, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of async operations.", "/Devices/ATA%d/Async/Time", i);
PDMDevHlpSTAMRegisterF(pDevIns, &pData->aCts[i].StatLockWait, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling of locks.", "/Devices/ATA%d/Async/LockWait", i);
#endif /* VBOX_WITH_STATISTICS */
/* Initialize per-controller critical section */
char szName[24];
RTStrPrintf(szName, sizeof(szName), "ATA%d", i);
rc = PDMDevHlpCritSectInit(pDevIns, &pData->aCts[i].lock, szName);
if (VBOX_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot initialize critical section."));
}
/*
* Attach status driver (optional).
*/
rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->IBase, &pBase, "Status Port");
if (VBOX_SUCCESS(rc))
pData->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
{
AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot attach to status driver."));
}
/*
* Attach the units.
*/
uint32_t cbTotalBuffer = 0;
for (uint32_t i = 0; i < RT_ELEMENTS(pData->aCts); i++)
{
PATACONTROLLER pCtl = &pData->aCts[i];
/*
* Start the worker thread.
*/
pCtl->uAsyncIOState = ATA_AIO_NEW;
rc = RTSemEventCreate(&pCtl->AsyncIOSem);
AssertRC(rc);
rc = RTSemEventCreate(&pCtl->SuspendIOSem);
AssertRC(rc);
rc = RTSemMutexCreate(&pCtl->AsyncIORequestMutex);
AssertRC(rc);
ataAsyncIOClearRequests(pCtl);
rc = RTThreadCreate(&pCtl->AsyncIOThread, ataAsyncIOLoop, (void *)pCtl, 128*1024, RTTHREADTYPE_IO, 0, "ATA");
AssertRC(rc);
Assert(pCtl->AsyncIOThread != NIL_RTTHREAD && pCtl->AsyncIOSem != NIL_RTSEMEVENT && pCtl->SuspendIOSem != NIL_RTSEMEVENT && pCtl->AsyncIORequestMutex != NIL_RTSEMMUTEX);
Log(("%s: controller %d AIO thread id %#x; sem %p susp_sem %p mutex %p\n", __FUNCTION__, i, pCtl->AsyncIOThread, pCtl->AsyncIOSem, pCtl->SuspendIOSem, pCtl->AsyncIORequestMutex));
for (uint32_t j = 0; j < RT_ELEMENTS(pCtl->aIfs); j++)
{
static const char *s_apszDescs[RT_ELEMENTS(pData->aCts)][RT_ELEMENTS(pCtl->aIfs)] =
{
{ "Primary Master", "Primary Slave" },
{ "Secondary Master", "Secondary Slave" }
};
/*
* Try attach the block device and get the interfaces,
* required as well as optional.
*/
ATADevState *pIf = &pCtl->aIfs[j];
rc = PDMDevHlpDriverAttach(pDevIns, pIf->iLUN, &pIf->IBase, &pIf->pDrvBase, s_apszDescs[i][j]);
if (VBOX_SUCCESS(rc))
rc = ataConfigLun(pDevIns, pIf);
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
pIf->pDrvBase = NULL;
pIf->pDrvBlock = NULL;
pIf->cbIOBuffer = 0;
pIf->pbIOBufferHC = NULL;
pIf->pbIOBufferGC = NIL_RTGCPHYS;
LogRel(("PIIX3 ATA: LUN#%d: no unit\n", pIf->iLUN));
}
else
{
AssertMsgFailed(("Failed to attach LUN#%d. rc=%Vrc\n", pIf->iLUN, rc));
switch (rc)
{
case VERR_ACCESS_DENIED:
/* Error already catched by DrvHostBase */
return rc;
default:
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_(
"PIIX3 cannot attach drive to the %s"), s_apszDescs[i][j]);
}
}
cbTotalBuffer += pIf->cbIOBuffer;
}
}
rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
ATA_SAVED_STATE_VERSION, sizeof(*pData) + cbTotalBuffer,
ataSaveLoadPrep, ataSaveExec, NULL,
ataSaveLoadPrep, ataLoadExec, NULL);
if (VBOX_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc, N_("PIIX3 cannot register save state handlers."));
/*
* Initialize the device state.
*/
ataReset(pDevIns);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DevicePIIX3IDE =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szDeviceName */
"piix3ide",
/* szGCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Intel PIIX3 ATA controller.\n"
" LUN #0 is primary master.\n"
" LUN #1 is primary slave.\n"
" LUN #2 is secondary master.\n"
" LUN #3 is secondary slave.\n"
" LUN #999 is the LED/Status connector.",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
/* fClass */
PDM_DEVREG_CLASS_STORAGE,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(PCIATAState),
/* pfnConstruct */
ataConstruct,
/* pfnDestruct */
ataDestruct,
/* pfnRelocate */
ataRelocate,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
ataReset,
/* pfnSuspend */
ataSuspend,
/* pfnResume */
ataResume,
/* pfnAttach */
ataAttach,
/* pfnDetach */
ataDetach,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
ataPowerOff
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */