ATAController.cpp revision ad8fb8c920c36650d5ead020ef8e05b681dd4375
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync * DevATA, DevAHCI - Shared ATA/ATAPI controller code (disk and cdrom).
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * @todo Actually share this code?
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * you can redistribute it and/or modify it under the terms of the GNU
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * General Public License (GPL) as published by the Free Software
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * additional information or have any questions.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/*******************************************************************************
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync* Header Files *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#endif /* IN_RING3 */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * The SSM saved state version.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_FULL_SENSE 1
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define ATA_CTL_SAVED_STATE_VERSION_WITHOUT_EVENT_STATUS 2
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncDECLINLINE(void) ataSetStatusValue(AHCIATADevState *s, uint8_t stat)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync /* Freeze status register contents while processing RESET. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncDECLINLINE(void) ataSetStatus(AHCIATADevState *s, uint8_t stat)
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /* Freeze status register contents while processing RESET. */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncDECLINLINE(void) ataUnsetStatus(AHCIATADevState *s, uint8_t stat)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Freeze status register contents while processing RESET. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Log2(("%s: LUN#%d status %#04x\n", __FUNCTION__, s->iLUN, s->uATARegStatus));
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsynctypedef void (*PBeginTransferFunc)(AHCIATADevState *);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void ataReadWriteSectorsBT(AHCIATADevState *);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic void atapiPassthroughCmdBT(AHCIATADevState *);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic bool ataExecuteDeviceDiagnosticSS(AHCIATADevState *);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsyncstatic bool atapiGetConfigurationSS(AHCIATADevState *);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic bool atapiGetEventStatusNotificationSS(AHCIATADevState *);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic bool atapiMechanismStatusSS(AHCIATADevState *);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsyncstatic bool atapiModeSenseErrorRecoverySS(AHCIATADevState *);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsyncstatic bool atapiModeSenseCDStatusSS(AHCIATADevState *);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic bool atapiReadDiscInformationSS(AHCIATADevState *);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic bool atapiReadTOCNormalSS(AHCIATADevState *);
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic bool atapiReadTrackInformationSS(AHCIATADevState *);
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync * Begin of transfer function indexes for g_apfnBeginTransFuncs.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Array of end transfer functions, the index is ATAFNET.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Make sure ATAFNET and this array match!
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic const PBeginTransferFunc g_apfnBeginTransFuncs[ATAFN_BT_MAX] =
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Source/sink function indexes for g_apfnSourceSinkFuncs.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * Array of source/sink functions, the index is ATAFNSS.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Make sure ATAFNSS and this array match!
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic const PSourceSinkFunc g_apfnSourceSinkFuncs[ATAFN_SS_MAX] =
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsyncstatic const AHCIATARequest ataDMARequest = { AHCIATA_AIO_DMA, };
fe813b3594039ba864493438e78ee0e7132bc445vboxsyncstatic const AHCIATARequest ataPIORequest = { AHCIATA_AIO_PIO, };
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsyncstatic const AHCIATARequest ataResetARequest = { AHCIATA_AIO_RESET_ASSERTED, };
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsyncstatic const AHCIATARequest ataResetCRequest = { AHCIATA_AIO_RESET_CLEARED, };
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void ataAsyncIOClearRequests(PAHCIATACONTROLLER pCtl)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void ataAsyncIOPutRequest(PAHCIATACONTROLLER pCtl, const AHCIATARequest *pReq)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Assert((pCtl->AsyncIOReqHead + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests) != pCtl->AsyncIOReqTail);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync memcpy(&pCtl->aAsyncIORequests[pCtl->AsyncIOReqHead], pReq, sizeof(*pReq));
fe813b3594039ba864493438e78ee0e7132bc445vboxsync pCtl->AsyncIOReqHead %= RT_ELEMENTS(pCtl->aAsyncIORequests);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = PDMR3CritSectScheduleExitEvent(&pCtl->lock, pCtl->AsyncIOSem);
362838d79d234a41380be42aae9118850cc3c929vboxsyncstatic const AHCIATARequest *ataAsyncIOGetCurrentRequest(PAHCIATACONTROLLER pCtl)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
362838d79d234a41380be42aae9118850cc3c929vboxsync pReq = &pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail];
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * Remove the request with the given type, as it's finished. The request
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * is not removed blindly, as this could mean a RESET request that is not
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * yet processed (but has cleared the request queue) is lost.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @param pCtl Controller for which to remove the request.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @param ReqType Type of the request to remove.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void ataAsyncIORemoveCurrentRequest(PAHCIATACONTROLLER pCtl, AHCIATAAIO ReqType)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pCtl->AsyncIOReqHead != pCtl->AsyncIOReqTail && pCtl->aAsyncIORequests[pCtl->AsyncIOReqTail].ReqType == ReqType)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pCtl->AsyncIOReqTail %= RT_ELEMENTS(pCtl->aAsyncIORequests);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * Dump the request queue for a particular controller. First dump the queue
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * contents, then the already processed entries, as long as they haven't been
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * overwritten.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync * @param pCtl Controller for which to dump the queue.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncstatic void ataAsyncIODumpRequests(PAHCIATACONTROLLER pCtl)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogRel(("ATA: Ctl: request queue dump (topmost is current):\n"));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync LogRel(("ATA: Ctl: processed requests (topmost is oldest):\n"));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync 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));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync LogRel(("abort request, iIf=%d fResetDrive=%d\n", pCtl->aAsyncIORequests[curr].u.a.iIf, pCtl->aAsyncIORequests[curr].u.a.fResetDrive));
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync LogRel(("unknown request %d\n", pCtl->aAsyncIORequests[curr].ReqType));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync curr = (curr + 1) % RT_ELEMENTS(pCtl->aAsyncIORequests);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Checks whether the request queue for a particular controller is empty
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * or whether a particular controller is idle.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * @param pCtl Controller for which to check the queue.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * @param fStrict If set then the controller is checked to be idle.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic bool ataAsyncIOIsIdle(PAHCIATACONTROLLER pCtl, bool fStrict)
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync fIdle = (pCtl->AsyncIOReqHead == pCtl->AsyncIOReqTail);
cba6719bd64ec749967bbe931230452664109857vboxsync * Send a transfer request to the async I/O thread.
30adc6dd25ed9fef4d800a6d9f1ab7e765b4c340vboxsync * @param s Pointer to the ATA device state data.
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync * @param cbTotalTransfer Data transfer size.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param uTxDir Data transfer direction.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param iBeginTransfer Index of BeginTransfer callback.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param iSourceSink Index of SourceSink callback.
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * @param fChainedTransfer Whether this is a transfer that is part of the previous command/transfer.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsyncstatic void ataStartTransfer(AHCIATADevState *s, uint32_t cbTotalTransfer, uint8_t uTxDir, ATAFNBT iBeginTransfer, ATAFNSS iSourceSink, bool fChainedTransfer)
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync /* Do not issue new requests while the RESET line is asserted. */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync Log2(("%s: Ctl: suppressed new request as RESET is active\n", __FUNCTION__));
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync /* If the controller is already doing something else right now, ignore
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * the command that is being submitted. Some broken guests issue commands
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * twice (e.g. the Linux kernel that comes with Acronis True Image 8). */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync if (!fChainedTransfer && !ataAsyncIOIsIdle(pCtl, true))
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync Log(("%s: Ctl: ignored command %#04x, controller state %d\n", __FUNCTION__, s->uATARegCommand, pCtl->uAsyncIOState));
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync LogRel(("IDE: guest issued command %#04x while controller busy\n", s->uATARegCommand));
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Kick the worker thread into action.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Log2(("%s: Ctl: message to async I/O thread, new request\n", __FUNCTION__));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Send an abort command request to the async I/O thread.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param s Pointer to the ATA device state data.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param fResetDrive Whether to reset the drive or just abort a command.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void ataAbortCurrentCommand(AHCIATADevState *s, bool fResetDrive)
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Do not issue new requests while the RESET line is asserted. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync Log2(("%s: Ctl: suppressed aborting command as RESET is active\n", __FUNCTION__));
cba6719bd64ec749967bbe931230452664109857vboxsync Log2(("%s: Ctl: message to async I/O thread, abort command on LUN#%d\n", __FUNCTION__, s->iLUN));
if (!s->fIrqPending)
s->fIrqPending = true;
s->fIrqPending = false;
#ifdef IN_RING3
if (s->fATAPITransfer)
ataSetIRQ(s);
s->fATAPITransfer = false;
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferPIODataStart = 0;
s->iIOBufferPIODataEnd = 0;
if (cbLimit == 0)
cbLimit--;
cbLimit--;
if (s->fLBA48)
if (!s->uATARegNSector)
return s->uATARegNSector;
if (*pbSrc)
if (*pbSrc)
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferCur = 0;
s->iIOBufferEnd = 0;
uint16_t *p;
int rc;
if (s->cMultSectors)
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[82] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* supports power management, write cache and look-ahead */
p[83] = RT_H2LE_U16(1 << 14 | 1 << 10 | 1 << 12 | 1 << 13); /* supports LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[85] = RT_H2LE_U16(1 << 3 | 1 << 5 | 1 << 6); /* enabled power management, write cache and look-ahead */
p[86] = RT_H2LE_U16(1 << 10 | 1 << 12 | 1 << 13); /* enabled LBA48, FLUSH CACHE and FLUSH CACHE EXT */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
int rc;
ataCmdOK(s, 0);
uint16_t *p;
int rc;
p[63] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_MDMA, ATA_MDMA_MODE_MAX, s->uATATransferMode)); /* MDMA modes supported / mode enabled */
p[64] = RT_H2LE_U16(ATA_PIO_MODE_MAX > 2 ? (1 << (ATA_PIO_MODE_MAX - 2)) - 1 : 0); /* PIO modes beyond PIO2 supported */
p[88] = RT_H2LE_U16(ATA_TRANSFER_ID(ATA_MODE_UDMA, ATA_UDMA_MODE_MAX, s->uATATransferMode)); /* UDMA modes supported / mode enabled */
if (s->fATAPI)
else if (s->pDrvBlock)
s->uATARegLCyl = 0;
s->uATARegHCyl = 0;
if (s->fLBA48)
s->uATARegSector;
iLBA = ((s->uATARegHCyl << 8) | s->uATARegLCyl) * s->PCHSGeometry.cHeads * s->PCHSGeometry.cSectors +
return iLBA;
if (s->fLBA48)
int rc;
return rc;
static int ataWriteSectors(AHCIATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
int rc;
return rc;
ataCmdOK(s, 0);
int rc;
N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
int rc;
N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
int rc;
N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
int rc;
int rc;
if (!s->cbTotalTransfer)
s->uATARegError = 0;
Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f),
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferCur = 0;
s->iIOBufferEnd = 0;
s->fATAPITransfer = true;
atapiCmdOK(s);
int rc;
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aModeSenseCmd, PDMBLOCKTXDIR_FROM_DEVICE, aModeSenseResult, &cbTransfer, &uDummySense, 500);
s->cbATAPISector = 0;
if (s->cbTotalTransfer == 0)
atapiCmdBT(s);
switch (s->cbATAPISector)
rc = s->pDrvBlock->pfnRead(s->pDrvBlock, (uint64_t)s->iATAPILBA * s->cbATAPISector, s->CTXALLSUFF(pbIOBuffer), s->cbATAPISector * cSectors);
atapiCmdOK(s);
LogRel(("AHCI ATA: LUN#%d: CD-ROM read error, %d sectors at LBA %d\n", s->iLUN, cSectors, s->iATAPILBA));
switch (s->aATAPICmd[0])
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
cReqSectors = 0;
cReqSectors = i;
switch (s->aATAPICmd[0])
case SCSI_READ_10:
case SCSI_WRITE_10:
case SCSI_WRITE_AND_VERIFY_10:
case SCSI_READ_12:
case SCSI_WRITE_12:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, pbBuf, &cbCurrTX, abATAPISense, sizeof(abATAPISense), 30000 /**< @todo timeout */);
rc = s->pDrvBlock->pfnSendCmd(s->pDrvBlock, s->aATAPICmd, (PDMBLOCKTXDIR)s->uTxDir, s->CTXALLSUFF(pbIOBuffer), &cbTransfer, abATAPISense, sizeof(abATAPISense), 30000 /**< @todo timeout */);
Log3(("ATAPI PT inquiry data before (%d): %.*Rhxs\n", cbTransfer, cbTransfer, s->CTXALLSUFF(pbIOBuffer)));
if (cbTransfer)
atapiCmdOK(s);
LogRel(("AHCI ATA: LUN#%d: CD-ROM passthrough command (%#04x) error %d %Rrc\n", s->iLUN, u8Cmd, abATAPISense[0] & 0x0f, rc));
static bool atapiReadSectors(AHCIATADevState *s, uint32_t iATAPILBA, uint32_t cSectors, uint32_t cbSector)
ataStartTransfer(s, cSectors * cbSector, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ, true);
atapiCmdOK(s);
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 */
atapiCmdOK(s);
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 */
pbBuf[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */
atapiCmdOK(s);
atapiCmdOK(s);
switch (OldStatus)
atapiCmdOK(s);
atapiCmdOK(s);
atapiCmdOK(s);
pbBuf[14] = (1 << 0) | (1 << 3) | (1 << 5); /* lock supported, eject supported, tray type loading mechanism */
pbBuf[15] = 0; /* no subchannel reads supported, no separate audio volume control, no changer etc. */
atapiCmdOK(s);
atapiCmdOK(s);
atapiCmdOK(s);
bool fMSF;
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
if (fMSF)
atapiCmdOK(s);
bool fMSF;
/** @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. */
if (fMSF)
atapiCmdOK(s);
bool fMSF;
if (fMSF)
if (fMSF)
ataLBA2MSF(q, 0);
ataH2BE_U32(q, 0);
atapiCmdOK(s);
switch (pbPacket[0])
case SCSI_TEST_UNIT_READY:
if (s->cNotifiedMediaChange > 0)
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
atapiCmdOK(s);
ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION, true);
case SCSI_MODE_SENSE_10:
switch (uPageControl)
case SCSI_PAGECONTROL_CURRENT:
switch (uPageCode)
ataStartTransfer(s, RT_MIN(cbMax, 16), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_ERROR_RECOVERY, true);
case SCSI_MODEPAGE_CD_STATUS:
ataStartTransfer(s, RT_MIN(cbMax, 40), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MODE_SENSE_CD_STATUS, true);
goto error_cmd;
goto error_cmd;
case SCSI_PAGECONTROL_DEFAULT:
goto error_cmd;
case SCSI_PAGECONTROL_SAVED:
case SCSI_REQUEST_SENSE:
ataStartTransfer(s, RT_MIN(cbMax, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
atapiCmdOK(s);
case SCSI_READ_10:
case SCSI_READ_12:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
if (cSectors == 0)
atapiCmdOK(s);
LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
case SCSI_READ_CD:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
if (cSectors == 0)
atapiCmdOK(s);
LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (READ CD)\n", s->iLUN, (uint64_t)iATAPILBA + cSectors));
atapiCmdOK(s);
case SCSI_SEEK_10:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
LogRel(("AHCI ATA: LUN#%d: CD-ROM block number %Ld invalid (SEEK)\n", s->iLUN, (uint64_t)iATAPILBA));
atapiCmdOK(s);
case SCSI_START_STOP_UNIT:
atapiCmdOK(s);
case SCSI_MECHANISM_STATUS:
ataStartTransfer(s, RT_MIN(cbMax, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_MECHANISM_STATUS, true);
case SCSI_READ_TOC_PMA_ATIP:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
switch (format)
ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_NORMAL, true);
ataStartTransfer(s, RT_MIN(cbMax, 12), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_MULTI, true);
ataStartTransfer(s, cbMax, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TOC_RAW, true);
case SCSI_READ_CAPACITY:
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
ataStartTransfer(s, 8, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_CAPACITY, true);
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
ataStartTransfer(s, RT_MIN(cbMax, 34), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_DISC_INFORMATION, true);
if (s->cNotifiedMediaChange > 0)
s->cNotifiedMediaChange-- ;
atapiCmdErrorSimple(s, SCSI_SENSE_UNIT_ATTENTION, SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED); /* media changed */
ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_READ_TRACK_INFORMATION, true);
case SCSI_GET_CONFIGURATION:
ataStartTransfer(s, RT_MIN(cbMax, 32), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_CONFIGURATION, true);
case SCSI_INQUIRY:
ataStartTransfer(s, RT_MIN(cbMax, 36), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_INQUIRY, true);
switch (pbPacket[0])
case SCSI_BLANK:
goto sendcmd;
case SCSI_CLOSE_TRACK_SESSION:
goto sendcmd;
case SCSI_ERASE_10:
goto sendcmd;
case SCSI_FORMAT_UNIT:
goto sendcmd;
case SCSI_GET_CONFIGURATION:
goto sendcmd;
ataStartTransfer(s, RT_MIN(cbTransfer, 8), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_GET_EVENT_STATUS_NOTIFICATION, true);
goto sendcmd;
case SCSI_GET_PERFORMANCE:
goto sendcmd;
case SCSI_INQUIRY:
goto sendcmd;
case SCSI_LOAD_UNLOAD_MEDIUM:
goto sendcmd;
case SCSI_MECHANISM_STATUS:
goto sendcmd;
case SCSI_MODE_SELECT_10:
goto sendcmd;
case SCSI_MODE_SENSE_10:
goto sendcmd;
case SCSI_PAUSE_RESUME:
goto sendcmd;
case SCSI_PLAY_AUDIO_10:
goto sendcmd;
case SCSI_PLAY_AUDIO_12:
goto sendcmd;
case SCSI_PLAY_AUDIO_MSF:
goto sendcmd;
goto sendcmd;
case SCSI_READ_10:
goto sendcmd;
case SCSI_READ_12:
goto sendcmd;
case SCSI_READ_BUFFER:
goto sendcmd;
goto sendcmd;
case SCSI_READ_CAPACITY:
goto sendcmd;
case SCSI_READ_CD:
goto sendcmd;
case SCSI_READ_CD_MSF:
cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
goto sendcmd;
goto sendcmd;
case SCSI_READ_DVD_STRUCTURE:
goto sendcmd;
goto sendcmd;
case SCSI_READ_SUBCHANNEL:
goto sendcmd;
case SCSI_READ_TOC_PMA_ATIP:
goto sendcmd;
goto sendcmd;
case SCSI_REPAIR_TRACK:
goto sendcmd;
case SCSI_REPORT_KEY:
goto sendcmd;
case SCSI_REQUEST_SENSE:
ataStartTransfer(s, RT_MIN(cbTransfer, 18), PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_ATAPI_CMD, ATAFN_SS_ATAPI_REQUEST_SENSE, true);
goto sendcmd;
case SCSI_RESERVE_TRACK:
goto sendcmd;
case SCSI_SCAN:
goto sendcmd;
case SCSI_SEEK_10:
goto sendcmd;
case SCSI_SEND_CUE_SHEET:
goto sendcmd;
case SCSI_SEND_DVD_STRUCTURE:
goto sendcmd;
case SCSI_SEND_EVENT:
goto sendcmd;
case SCSI_SEND_KEY:
goto sendcmd;
goto sendcmd;
case SCSI_SET_CD_SPEED:
goto sendcmd;
case SCSI_SET_READ_AHEAD:
goto sendcmd;
case SCSI_SET_STREAMING:
goto sendcmd;
case SCSI_START_STOP_UNIT:
goto sendcmd;
case SCSI_STOP_PLAY_SCAN:
goto sendcmd;
case SCSI_SYNCHRONIZE_CACHE:
goto sendcmd;
case SCSI_TEST_UNIT_READY:
goto sendcmd;
case SCSI_VERIFY_10:
goto sendcmd;
case SCSI_WRITE_10:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_12:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_AND_VERIFY_10:
s->cbATAPISector = 0;
goto sendcmd;
case SCSI_WRITE_BUFFER:
LogRel(("AHCI ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", s->iLUN));
goto sendcmd;
goto sendcmd;
case SCSI_REZERO_UNIT:
if (cbTransfer == 0)
ataStartTransfer(s, cbTransfer, uTxDir, ATAFN_BT_ATAPI_PASSTHROUGH_CMD, ATAFN_SS_ATAPI_PASSTHROUGH, true);
#ifdef DEBUG
Log(("%s: LUN#%d DMA=%d CMD=%#04x \"%s\"\n", __FUNCTION__, s->iLUN, s->fDMA, pbPacket[0], SCSICmdText(pbPacket[0])));
Log2(("%s: limit=%#x packet: %.*Rhxs\n", __FUNCTION__, s->uATARegLCyl | (s->uATARegHCyl << 8), ATAPI_PACKET_SIZE, pbPacket));
if (s->fATAPIPassthrough)
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
atapiParseCmd(s);
switch (OldStatus)
LogRel(("ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pIf->iLUN, pIf->cTotalSectors));
s->cNotifiedMediaChange = 0;
ataUnsetIRQ(s);
ataSetSignature(s);
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
s->iIOBufferPIODataStart = 0;
s->iIOBufferPIODataEnd = 0;
s->fATAPITransfer = false;
s->uATARegFeature = 0;
ataSetSignature(s);
if (s->fATAPI)
#ifdef DEBUG
s->fLBA48 = false;
s->fDMA = false;
if (s->u64CmdTS)
switch (cmd)
case ATA_IDENTIFY_DEVICE:
if (s->fATAPI)
ataSetSignature(s);
case ATA_RECALIBRATE:
case ATA_SET_MULTIPLE_MODE:
if ( s->uATARegNSector != 0
ataCmdOK(s, 0);
s->fLBA48 = true;
case ATA_READ_VERIFY_SECTORS:
ataCmdOK(s, 0);
case ATA_READ_SECTORS_EXT:
s->fLBA48 = true;
case ATA_READ_SECTORS:
if (!s->pDrvBlock)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_SECTORS_EXT:
s->fLBA48 = true;
case ATA_WRITE_SECTORS:
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
case ATA_READ_MULTIPLE_EXT:
s->fLBA48 = true;
case ATA_READ_MULTIPLE:
if (!s->cMultSectors)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_MULTIPLE_EXT:
s->fLBA48 = true;
case ATA_WRITE_MULTIPLE:
if (!s->cMultSectors)
goto abort_cmd;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
case ATA_READ_DMA_EXT:
s->fLBA48 = true;
case ATA_READ_DMA:
if (!s->pDrvBlock)
goto abort_cmd;
s->fDMA = true;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_FROM_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_READ_SECTORS, false);
case ATA_WRITE_DMA_EXT:
s->fLBA48 = true;
case ATA_WRITE_DMA:
if (!s->pDrvBlock)
goto abort_cmd;
s->fDMA = true;
ataStartTransfer(s, ataGetNSectors(s) * 512, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_READ_WRITE_SECTORS, ATAFN_SS_WRITE_SECTORS, false);
s->fLBA48 = true;
ataCmdOK(s, 0);
ataCmdOK(s, 0);
case ATA_CHECK_POWER_MODE:
ataCmdOK(s, 0);
case ATA_SET_FEATURES:
if (!s->pDrvBlock)
goto abort_cmd;
switch (s->uATARegFeature)
s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_MDMA_MODE_MAX);
s->uATATransferMode = (s->uATARegNSector & 0xf8) | RT_MIN(s->uATARegNSector & 0x07, ATA_UDMA_MODE_MAX);
goto abort_cmd;
goto abort_cmd;
s->uATARegFeature = 0;
case ATA_FLUSH_CACHE_EXT:
case ATA_FLUSH_CACHE:
goto abort_cmd;
case ATA_STANDBY_IMMEDIATE:
ataCmdOK(s, 0);
case ATA_IDLE_IMMEDIATE:
ataAbortCurrentCommand(s, false);
if (s->fATAPI)
ataStartTransfer(s, 0, PDMBLOCKTXDIR_NONE, ATAFN_BT_NULL, ATAFN_SS_EXECUTE_DEVICE_DIAGNOSTIC, false);
case ATA_DEVICE_RESET:
if (!s->fATAPI)
goto abort_cmd;
ataAbortCurrentCommand(s, true);
case ATA_PACKET:
if (!s->fATAPI)
goto abort_cmd;
goto abort_cmd;
ataStartTransfer(s, ATAPI_PACKET_SIZE, PDMBLOCKTXDIR_TO_DEVICE, ATAFN_BT_PACKET, ATAFN_SS_PACKET, false);
bool fRc;
if (fRc)
return fRc;
switch (addr)
Log2(("%s: LUN#%d asserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
Log2(("%s: LUN#%d deasserting IRQ (drive select change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return VINF_SUCCESS;
bool fHOB;
if (!s->pDrvBlock)
val = 0;
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
if (!s->pDrvBlock)
val = 0;
else if (fHOB)
val = 0;
static unsigned cBusy = 0;
if (!s->pDrvBlock)
val = 0;
#ifdef IN_RING3
cBusy = 0;
cBusy = 0;
return VINF_IOM_HC_IOPORT_READ;
cBusy = 0;
ataUnsetIRQ(s);
return VINF_SUCCESS;
val = 0;
return val;
#ifndef IN_RING3
#ifdef IN_RING3
LogRel(("ATA: Ctl: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
#ifdef IN_RING3
Log2(("%s: LUN#%d asserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
Log2(("%s: LUN#%d deasserting IRQ (interrupt disable change)\n", __FUNCTION__, pCtl->aIfs[pCtl->iSelectedIf].iLUN));
return VINF_SUCCESS;
#ifdef IN_RING3
AHCIATADevState *s;
LogRel(("AHCI ATA: LUN#%d: %s data in the middle of a PIO transfer - VERY SLOW\n", s->iLUN, s->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE ? "loading" : "storing"));
bool fRedo;
s->iIOBufferCur = 0;
if (s->cbTotalTransfer)
if (s->fATAPITransfer)
if (s->cbTotalTransfer)
ataSetIRQ(s);
static int ataDataWrite(PAHCIATACONTROLLER pCtl, uint32_t addr, uint32_t cbSize, const uint8_t *pbBuf)
uint8_t *p;
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return VINF_SUCCESS;
uint8_t *p;
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_READ;
return VINF_SUCCESS;
#ifdef IN_RING3
s->cbTotalTransfer = 0;
s->cbElementaryTransfer = 0;
bool fRedo;
bool fLastDesc = false;
if (cbBuffer == 0)
iIOBufferCur = 0;
if (fLastDesc)
int rc;
AHCIATADevState *s;
AssertReleaseMsg(ReqType == AHCIATA_AIO_RESET_ASSERTED || ReqType == AHCIATA_AIO_RESET_CLEARED || ReqType == AHCIATA_AIO_ABORT || pCtl->uAsyncIOState == ReqType, ("I/O state inconsistent: state=%d request=%d\n", pCtl->uAsyncIOState, ReqType));
switch (ReqType)
case AHCIATA_AIO_NEW:
s->iIOBufferEnd = 0;
if (s->fATAPI)
if (s->fDMA)
if (s->fDMA)
s->iIOBufferCur = 0;
bool fRedo;
ataCmdOK(s, 0);
if (s->fDMA)
if (s->cbTotalTransfer)
Log2(("%s: Ctl: message to async I/O thread, continuing DMA transfer immediately\n", __FUNCTION__));
Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
ataSetIRQ(s);
if (s->cbTotalTransfer)
ataSetIRQ(s);
Assert(s->uTxDir == PDMBLOCKTXDIR_NONE); /* Any transfer which has an initial transfer size of 0 must be marked as such. */
if (!s->fATAPITransfer)
ataSetIRQ(s);
case AHCIATA_AIO_DMA:
s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
ATAFNSS iOriginalSourceSink = (ATAFNSS)s->iSourceSink; /* Used by the hack below, but gets reset by then. */
&& s->cbTotalTransfer == 0
if (s->fATAPITransfer)
s->fATAPITransfer = false;
ataSetIRQ(s);
case AHCIATA_AIO_PIO:
s = &pCtl->aIfs[pCtl->iAIOIf]; /* Do not remove or there's an instant crash after loading the saved state */
bool fRedo;
s->iIOBufferCur = 0;
if (s->cbTotalTransfer)
ataSetIRQ(s);
&& !s->fATAPITransfer
ataSetIRQ(s);
case AHCIATA_AIO_ABORT:
ataResetDevice(s);
ataSetIRQ(s);
Log(("%s: Ctl: LUN#%d finished I/O transaction in %d microseconds\n", __FUNCTION__, pCtl->aIfs[pCtl->iAIOIf].iLUN, (uint32_t)(uWait)));
LogRel(("AHCI ATA: execution time for ATA command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].uATARegCommand, uWait / (1000 * 1000)));
LogRel(("AHCI ATA: execution time for ATAPI command %#04x was %d seconds\n", pCtl->aIfs[pCtl->iAIOIf].aATAPICmd[0], uWait / (1000 * 1000)));
return rc;
return val;
#ifdef IN_RING3
return val;
return val;
int ataControllerBMDMAIOPortRead(PAHCIATACONTROLLER pCtl, RTIOPORT Port, uint32_t *pu32, unsigned cb)
int rc;
return rc;
return VERR_IOM_IOPORT_UNUSED;
return rc;
int ataControllerBMDMAIOPortWrite(PAHCIATACONTROLLER pCtl, RTIOPORT Port, uint32_t u32, unsigned cb)
int rc;
return rc;
#ifndef IN_RING3
default: AssertMsgFailed(("%s: Unsupported write to port %x size=%d val=%x\n", __FUNCTION__, Port, cb, u32)); break;
return rc;
#ifdef IN_RING3
static DECLCALLBACK(int) ataBMDMAIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
return rc;
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_BLOCK_PORT:
return NULL;
return rc;
return rc;
return rc;
return rc;
int ataControllerIOPortReadStr1(PAHCIATACONTROLLER pCtl, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
return rc;
#ifndef IN_RING3
rc = PGMPhysSimpleDirtyWriteGCPtr(PDMDevHlpGetVMCPU(pDevIns), GCDst, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
#ifdef IN_RING3
return rc;
int ataControllerIOPortWriteStr1(PAHCIATACONTROLLER pCtl, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
return rc;
#ifndef IN_RING3
rc = PGMPhysSimpleReadGCPtr(PDMDevHlpGetVMCPU(pDevIns), s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart, GCSrc, cbTransfer);
if (cbTransfer)
Log3(("%s: addr=%#x val=%.*Rhxs\n", __FUNCTION__, Port, cbTransfer, s->CTX_SUFF(pbIOBuffer) + s->iIOBufferPIODataStart));
#ifdef IN_RING3
return rc;
int rc;
return VINF_SUCCESS;
return rc;
return rc;
int rc;
return VERR_IOM_IOPORT_UNUSED;
return rc;
return VINF_SUCCESS;
#ifdef IN_RING3
bool fAllIdle = false;
fAllIdle = true;
if (!fAllIdle)
if ( fAllIdle
if (!fAllIdle)
return fAllIdle;
if (s->pbIOBufferR3)
int rc;
LogRel(("PIIX3 ATA Dtor: Ctl/irq=%u is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x rc=%Rrc\n",
return VINF_SUCCESS;
unsigned iController;
unsigned iInterface;
AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
int rc;
return VERR_PDM_MISSING_INTERFACE;
pIf->pDrvBlockBios = (PDMIBLOCKBIOS *)pIf->pDrvBase->pfnQueryInterface(pIf->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
return VERR_PDM_MISSING_INTERFACE;
AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd-rom. enmType=%d\n", pIf->iLUN, enmType));
return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
return VERR_INTERNAL_ERROR;
rc = MMR3HyperAllocOnceNoRel(pVM, pIf->cbIOBuffer, 0, MM_TAG_PDM_DEVICE_USER, (void **)&pIf->pbIOBufferR3);
return VERR_NO_MEMORY;
LogRel(("ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
LogRel(("AHCI ATA: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n", pIf->iLUN, pIf->PCHSGeometry.cCylinders, pIf->PCHSGeometry.cHeads, pIf->PCHSGeometry.cSectors, pIf->cTotalSectors));
return VINF_SUCCESS;
int rc;
unsigned iController;
unsigned iInterface;
AssertReleaseMsg(iController < RT_ELEMENTS(pThis->aCts), ("iController=%d iLUN=%d\n", iController, iLUN));
return rc;
int rc;
return VERR_SSM_IDE_ASYNC_TIMEOUT;
return VINF_SUCCESS;
int rc;
return VERR_SSM_LOAD_CONFIG_MISMATCH;
while (cbLeft-- > 0)
return rc;
if (u32 != ~0U)
return rc;
return VINF_SUCCESS;
DECLCALLBACK(int) ataControllerInit(PPDMDEVINS pDevIns, PAHCIATACONTROLLER pCtl, PPDMIBASE pDrvBaseMaster, PPDMIBASE pDrvBaseSlave,
int rc;
Assert(pCtl->AsyncIOThread != NIL_RTTHREAD && pCtl->AsyncIOSem != NIL_RTSEMEVENT && pCtl->SuspendIOSem != NIL_RTSEMEVENT && pCtl->AsyncIORequestMutex != NIL_RTSEMMUTEX);
Log(("%s: controller AIO thread id %#x; sem %p susp_sem %p mutex %p\n", __FUNCTION__, pCtl->AsyncIOThread, pCtl->AsyncIOSem, pCtl->SuspendIOSem, pCtl->AsyncIORequestMutex));
return VINF_SUCCESS;