14
14
* Foundation, in version 2 as it comes in the "COPYING" file of the
15
15
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16
16
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19
* Clara, CA 95054 USA or visit http://www.sun.com if you need
20
* additional information or have any questions.
23
19
/** @page pg_dev_ahci AHCI - Advanced Host Controller Interface Emulation.
2373
* Queries an interface to the driver.
2375
* @returns Pointer to interface.
2376
* @returns NULL if the interface was not supported by the device.
2377
* @param pInterface Pointer to ATADevState::IBase.
2378
* @param enmInterface The requested interface identification.
2407
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
2380
static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2409
static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
2382
PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
2383
switch (enmInterface)
2385
case PDMINTERFACE_BASE:
2386
return &pAhci->IBase;
2387
case PDMINTERFACE_LED_PORTS:
2388
return &pAhci->ILeds;
2411
PAHCI pThis = PDMIBASE_2_PAHCI(pInterface);
2412
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2413
PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
2395
* Query interface method for the AHCI port.
2418
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
2397
static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2420
static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2399
2422
PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
2400
switch (enmInterface)
2402
case PDMINTERFACE_BASE:
2403
return &pAhciPort->IBase;
2404
case PDMINTERFACE_BLOCK_PORT:
2405
return &pAhciPort->IPort;
2406
case PDMINTERFACE_BLOCK_ASYNC_PORT:
2407
return &pAhciPort->IPortAsync;
2408
case PDMINTERFACE_MOUNT_NOTIFY:
2409
return &pAhciPort->IMountNotify;
2423
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pAhciPort->IBase);
2424
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKPORT, &pAhciPort->IPort);
2425
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNCPORT, &pAhciPort->IPortAsync);
2426
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pAhciPort->IMountNotify);
3871
3884
* @returns Nothing
3872
3885
* @param pAhciPort The port for which the SDB Fis is send.
3873
3886
* @param uFinishedTasks Bitmask of finished tasks.
3874
* @param pAhciPortTaskState The state of the last task.
3875
3887
* @param fInterrupt If an interrupt should be asserted.
3877
static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, PAHCIPORTTASKSTATE pAhciPortTaskState, bool fInterrupt)
3889
static void ahciSendSDBFis(PAHCIPort pAhciPort, uint32_t uFinishedTasks, bool fInterrupt)
3879
3891
uint32_t sdbFis[2];
3880
3892
bool fAssertIntr = false;
3881
3893
PAHCI pAhci = pAhciPort->CTX_SUFF(pAhci);
3894
PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr);
3883
3896
ahciLog(("%s: Building SDB FIS\n", __FUNCTION__));
3887
3900
memset(&sdbFis[0], 0, sizeof(sdbFis));
3888
3901
sdbFis[0] = AHCI_CMDFIS_TYPE_SETDEVBITS;
3889
3902
sdbFis[0] |= (fInterrupt ? (1 << 14) : 0);
3890
sdbFis[0] |= pAhciPortTaskState->uATARegError << 24;
3891
sdbFis[0] |= (pAhciPortTaskState->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3892
sdbFis[1] = uFinishedTasks;
3894
ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3896
if (pAhciPortTaskState->uATARegStatus & ATA_STAT_ERR)
3903
if (RT_UNLIKELY(pTaskErr))
3905
sdbFis[0] = pTaskErr->uATARegError;
3906
sdbFis[0] |= (pTaskErr->uATARegStatus & 0x77) << 16; /* Some bits are marked as reserved and thus are masked out. */
3908
/* Update registers. */
3909
pAhciPort->regTFD = (pTaskErr->uATARegError << 8) | pTaskErr->uATARegStatus;
3914
sdbFis[0] |= (ATA_STAT_READY | ATA_STAT_SEEK) << 16;
3915
pAhciPort->regTFD = ATA_STAT_READY | ATA_STAT_SEEK;
3918
sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
3920
ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
3922
if (RT_UNLIKELY(pTaskErr))
3898
3924
/* Error bit is set. */
3899
3925
ASMAtomicOrU32(&pAhciPort->regIS, AHCI_PORT_IS_TFES);
4083
4106
if (pAhciPortTaskState->cbBufferUnaligned < cbUnaligned)
4085
4108
if (pAhciPortTaskState->pvBufferUnaligned)
4086
RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4109
RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4088
4111
Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
4090
pAhciPortTaskState->pvBufferUnaligned = RTMemAllocZ(cbUnaligned);
4113
pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(cbUnaligned);
4091
4114
if (!pAhciPortTaskState->pvBufferUnaligned)
4092
4115
return VERR_NO_MEMORY;
4097
4120
/* Make debugging easier. */
4099
memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(PDMDATASEG));
4122
memset(pAhciPortTaskState->pSGListHead, 0, pAhciPortTaskState->cSGListSize * sizeof(RTSGSEG));
4100
4123
memset(pAhciPortTaskState->paSGEntries, 0, pAhciPortTaskState->cSGListSize * sizeof(AHCIPORTTASKSTATESGENTRY));
4101
4124
if (pAhciPortTaskState->pvBufferUnaligned)
4102
4125
memset(pAhciPortTaskState->pvBufferUnaligned, 0, pAhciPortTaskState->cbBufferUnaligned);
4164
4187
pAhciPortTaskState->cbBufferUnaligned = pAhciPortTaskState->cbSGBuffers;
4166
4189
/* Allocate new buffers and SG lists. */
4167
pAhciPortTaskState->pvBufferUnaligned = RTMemAlloc(pAhciPortTaskState->cbSGBuffers);
4190
pAhciPortTaskState->pvBufferUnaligned = RTMemPageAlloc(pAhciPortTaskState->cbSGBuffers);
4168
4191
if (!pAhciPortTaskState->pvBufferUnaligned)
4169
4192
return VERR_NO_MEMORY;
4171
pAhciPortTaskState->pSGListHead = (PPDMDATASEG)RTMemAllocZ(1 * sizeof(PDMDATASEG));
4194
pAhciPortTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(1 * sizeof(RTSGSEG));
4172
4195
if (!pAhciPortTaskState->pSGListHead)
4174
RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4197
RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4175
4198
return VERR_NO_MEMORY;
4178
4201
pAhciPortTaskState->paSGEntries = (PAHCIPORTTASKSTATESGENTRY)RTMemAllocZ(1 * sizeof(AHCIPORTTASKSTATESGENTRY));
4179
4202
if (!pAhciPortTaskState->paSGEntries)
4181
RTMemFree(pAhciPortTaskState->pvBufferUnaligned);
4204
RTMemPageFree(pAhciPortTaskState->pvBufferUnaligned, pAhciPortTaskState->cbBufferUnaligned);
4182
4205
RTMemFree(pAhciPortTaskState->pSGListHead);
4183
4206
return VERR_NO_MEMORY;
4250
4273
RTGCPHYS GCPhysAddrPRDTLUnalignedStart = NIL_RTGCPHYS;
4251
4274
PAHCIPORTTASKSTATESGENTRY pSGInfoCurr = NULL;
4252
4275
PAHCIPORTTASKSTATESGENTRY pSGInfoPrev = NULL;
4253
PPDMDATASEG pSGEntryCurr = NULL;
4254
PPDMDATASEG pSGEntryPrev = NULL;
4276
PRTSGSEG pSGEntryCurr = NULL;
4277
PRTSGSEG pSGEntryPrev = NULL;
4255
4278
RTGCPHYS GCPhysBufferPageAlignedPrev = NIL_RTGCPHYS;
4256
4279
uint8_t *pu8BufferUnalignedPos = NULL;
4257
4280
uint32_t cbUnalignedComplete = 0;
4264
4287
* Create a safe mapping when doing post processing because the size of the
4265
* data to transfer and the amount of guest memory reserved can differ
4288
* data to transfer and the amount of guest memory reserved can differ.
4290
* @fixme: Read performance is really bad on OS X hosts because there is no
4291
* S/G support and the I/O manager has to create a newrequest
4292
* for every segment. The default limit of active requests is 16 on OS X
4293
* which causes a the bad read performance (writes are not affected
4294
* because of the writeback cache).
4295
* For now we will always use an intermediate buffer until
4296
* there is support for host S/G operations.
4267
if (pAhciPortTaskState->pfnPostProcess)
4298
if (pAhciPortTaskState->pfnPostProcess || true)
4269
ahciLog(("%s: Request with post processing.\n"));
4300
ahciLog(("%s: Request with post processing.\n", __FUNCTION__));
4271
4302
ahciScatterGatherListGetTotalBufferSize(pAhciPort, pAhciPortTaskState);
4840
4871
* @param pAhciPort Pointer to the port where to request completed.
4841
4872
* @param pAhciPortTaskState Pointer to the task which finished.
4873
* @param rcReq IPRT status code of the completed request.
4843
static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState)
4875
static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
4845
4877
/* Free system resources occupied by the scatter gather list. */
4846
ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4848
pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4850
pAhciPortTaskState->uATARegError = 0;
4851
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4852
/* Write updated command header into memory of the guest. */
4853
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4854
&pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4856
if (pAhciPortTaskState->uTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
4878
if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
4879
ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4881
if (RT_FAILURE(rcReq))
4883
pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
4884
pAhciPortTaskState->uATARegError = ID_ERR;
4885
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
4887
/* Log the error. */
4888
if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
4890
if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
4891
LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
4892
pAhciPort->iLUN, rcReq));
4894
LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
4896
pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
4899
pAhciPortTaskState->uOffset,
4900
pAhciPortTaskState->cbTransfer, rcReq));
4902
ASMAtomicCmpXchgPtr((void * volatile *)&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
4906
pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
4908
pAhciPortTaskState->uATARegError = 0;
4909
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
4911
/* Write updated command header into memory of the guest. */
4912
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
4913
&pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
4916
if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
4858
4918
STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
4859
4919
pAhciPort->Led.Actual.s.fReading = 0;
4921
else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
4863
4923
STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
4864
4924
pAhciPort->Led.Actual.s.fWriting = 0;
4871
4931
ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
4872
4932
cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
4873
4933
ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
4874
ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
4934
if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtr((void * volatile *)&pAhciPort->pTaskErr))
4935
ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
4938
bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
4939
AssertMsg(fXchg, ("Task is not active\n"));
4876
4942
if (!cOutstandingTasks)
4877
ahciSendSDBFis(pAhciPort, pAhciPort->u32QueuedTasksFinished, pAhciPortTaskState, true);
4943
ahciSendSDBFis(pAhciPort, 0, true);
4948
bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
4949
AssertMsg(fXchg, ("Task is not active\n"));
4880
4952
ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
4882
4955
/* Add the task to the cache. */
4883
4956
pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
4891
4964
* @returns VBox status code.
4892
4965
* @param pInterface Pointer to the interface.
4893
4966
* @param pvUser User data.
4967
* @param rcReq IPRT Status code of the completed request.
4895
static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser)
4969
static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
4897
4971
PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
4898
4972
PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
4900
4974
ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
4901
4975
__FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
4903
int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
4977
int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
4905
4979
if (pAhciPort->uActTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
4906
4980
PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
4930
5004
if (pAhciPort->pDrvBlock && !pAhciPort->fATAPI)
4932
5007
uint16_t u16Temp[256];
4934
5009
/* Fill the buffer. */
4935
5010
ahciIdentifySS(pAhciPort, u16Temp);
4937
5012
/* Create scatter gather list. */
4938
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
4940
AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc));
5013
rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
5014
if (RT_FAILURE(rc2))
5015
AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
4942
5017
/* Copy the buffer. */
4943
5018
pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &u16Temp[0], sizeof(u16Temp));
4945
5020
/* Destroy list. */
4946
rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
4948
AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc));
5021
rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5022
if (RT_FAILURE(rc2))
5023
AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
4950
5025
pAhciPortTaskState->uATARegError = 0;
4951
5026
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5081
5153
pAhciPortTaskState->cbTransfer = ahciGetNSectors(pCmdFis, fLBA48) * 512;
5082
5154
pAhciPortTaskState->uOffset = ahciGetSector(pAhciPort, pCmdFis, fLBA48) * 512;
5083
rc = PDMBLOCKTXDIR_TO_DEVICE;
5155
rc = AHCITXDIR_WRITE;
5086
5158
case ATA_READ_FPDMA_QUEUED:
5088
5160
pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5089
5161
pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5090
rc = PDMBLOCKTXDIR_FROM_DEVICE;
5162
rc = AHCITXDIR_READ;
5093
5165
case ATA_WRITE_FPDMA_QUEUED:
5095
5167
pAhciPortTaskState->cbTransfer = ahciGetNSectorsQueued(pCmdFis) * 512;
5096
5168
pAhciPortTaskState->uOffset = ahciGetSectorQueued(pCmdFis) * 512;
5097
rc = PDMBLOCKTXDIR_TO_DEVICE;
5169
rc = AHCITXDIR_WRITE;
5172
case ATA_READ_LOG_EXT:
5174
size_t cbLogRead = ((pCmdFis[AHCI_CMDFIS_SECTCEXP] << 8) | pCmdFis[AHCI_CMDFIS_SECTC]) * 512;
5175
unsigned offLogRead = ((pCmdFis[AHCI_CMDFIS_CYLLEXP] << 8) | pCmdFis[AHCI_CMDFIS_CYLL]) * 512;
5176
unsigned iPage = pCmdFis[AHCI_CMDFIS_SECTN];
5178
LogFlow(("Trying to read %zu bytes starting at offset %u from page %u\n", cbLogRead, offLogRead, iPage));
5182
memset(aBuf, 0, sizeof(aBuf));
5184
if (offLogRead + cbLogRead <= sizeof(aBuf))
5190
LogFlow(("Reading error page\n"));
5191
PAHCIPORTTASKSTATE pTaskErr = (PAHCIPORTTASKSTATE)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->pTaskErr, NULL);
5194
aBuf[0] = pTaskErr->fQueued ? pTaskErr->uTag : (1 << 7);
5195
aBuf[2] = pTaskErr->uATARegStatus;
5196
aBuf[3] = pTaskErr->uATARegError;
5197
aBuf[4] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTN];
5198
aBuf[5] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLL];
5199
aBuf[6] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLH];
5200
aBuf[7] = pTaskErr->cmdFis[AHCI_CMDFIS_HEAD];
5201
aBuf[8] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTNEXP];
5202
aBuf[9] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLLEXP];
5203
aBuf[10] = pTaskErr->cmdFis[AHCI_CMDFIS_CYLHEXP];
5204
aBuf[12] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTC];
5205
aBuf[13] = pTaskErr->cmdFis[AHCI_CMDFIS_SECTCEXP];
5207
/* Calculate checksum */
5208
uint8_t uChkSum = 0;
5209
for (unsigned i = 0; i < RT_ELEMENTS(aBuf)-1; i++)
5212
aBuf[511] = (uint8_t)-(int8_t)uChkSum;
5215
* Reading this log page results in an abort of all outstanding commands
5216
* and clearing the SActive register and TaskFile register.
5218
ahciSendSDBFis(pAhciPort, 0xffffffff, true);
5224
/* Create scatter gather list. */
5225
int rc2 = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, false);
5226
if (RT_FAILURE(rc2))
5227
AssertMsgFailed(("Creating list failed rc=%Rrc\n", rc2));
5229
/* Copy the buffer. */
5230
pCmdHdr->u32PRDBC = ahciScatterGatherListCopyFromBuffer(pAhciPortTaskState, &aBuf[offLogRead], cbLogRead);
5233
rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5234
if (RT_FAILURE(rc2))
5235
AssertMsgFailed(("Freeing list failed rc=%Rrc\n", rc2));
5237
pAhciPortTaskState->uATARegError = 0;
5238
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5240
/* Write updated command header into memory of the guest. */
5241
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, pCmdHdr, sizeof(CmdHdr));
5100
5246
/* All not implemented commands go below. */
5101
5247
case ATA_SECURITY_FREEZE_LOCK:
5102
5248
case ATA_SMART:
5103
5249
case ATA_NV_CACHE:
5104
case ATA_SLEEP: /* Powermanagement not supported. */
5105
5250
pAhciPortTaskState->uATARegError = ABRT_ERR;
5106
5251
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5262
5413
pAhciPort->fResetDevice = true;
5263
5414
ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
5264
5415
pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5417
fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
5418
AssertMsg(fXchg, ("Task is not active\n"));
5267
5422
else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
5269
5424
ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
5270
5425
pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
5427
fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
5428
AssertMsg(fXchg, ("Task is not active\n"));
5273
5432
else /* We are not in a reset state update the control registers. */
5279
iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5438
enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
5281
if (iTxDir != PDMBLOCKTXDIR_NONE)
5440
if (enmTxDir != AHCITXDIR_NONE)
5442
pAhciPortTaskState->enmTxDir = enmTxDir;
5283
5444
if (pAhciPortTaskState->fQueued)
5285
5446
ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5287
5448
ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
5290
STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5292
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5294
AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5296
if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5451
if (enmTxDir != AHCITXDIR_FLUSH)
5453
STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
5455
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
5457
AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
5460
if (enmTxDir == AHCITXDIR_FLUSH)
5462
rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
5463
pAhciPortTaskState);
5465
else if (enmTxDir == AHCITXDIR_READ)
5298
5467
pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5299
5468
rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
5310
5479
pAhciPortTaskState);
5312
5481
if (rc == VINF_VD_ASYNC_IO_FINISHED)
5313
rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState);
5482
rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, VINF_SUCCESS);
5316
AssertMsgFailed(("%s: Failed to enqueue command %Rrc\n", __FUNCTION__, rc));
5484
if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
5485
rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rc);
5490
fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
5491
AssertMsg(fXchg, ("Task is not active\n"));
5320
5494
/* There is nothing left to do. Notify the guest. */
5321
5495
ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5322
5496
/* Add the task to the cache. */
5494
iTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5496
if (iTxDir != PDMBLOCKTXDIR_NONE)
5668
enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0]);
5670
if (enmTxDir == AHCITXDIR_FLUSH)
5672
rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);
5674
/* Log the error. */
5676
&& pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5678
LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
5679
pAhciPort->iLUN, rc));
5684
pAhciPortTaskState->uATARegError = ID_ERR;
5685
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5689
pAhciPortTaskState->uATARegError = 0;
5690
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5693
if (pAhciPortTaskState->fQueued)
5694
uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
5697
/* Task is not queued send D2H FIS */
5698
ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
5701
else if (enmTxDir != AHCITXDIR_NONE)
5498
5703
uint64_t uOffset;
5499
5704
size_t cbTransfer;
5500
PPDMDATASEG pSegCurr;
5501
5706
PAHCIPORTTASKSTATESGENTRY pSGInfoCurr;
5503
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE) ? false : true);
5708
rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
5504
5709
if (RT_FAILURE(rc))
5505
5710
AssertMsgFailed(("%s: Failed to get number of list elments %Rrc\n", __FUNCTION__, rc));
5522
5727
AssertMsg(!(uOffset % 512), ("Offset is not sector aligned %llu\n", uOffset));
5523
5728
AssertMsg(!(cbProcess % 512), ("Number of bytes to process is not sector aligned %lu\n", cbProcess));
5525
if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
5730
if (enmTxDir == AHCITXDIR_READ)
5527
5732
pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
5528
5733
rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, uOffset,
5529
5734
pSegCurr->pvSeg, cbProcess);
5530
5735
pAhciPort->Led.Actual.s.fReading = 0;
5531
5736
if (RT_FAILURE(rc))
5532
AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
5534
5739
STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, cbProcess);
5555
STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, a);
5760
STAM_PROFILE_STOP(&pAhciPort->StatProfileReadWrite, b);
5762
/* Log the error. */
5764
&& pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
5766
LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
5768
enmTxDir == AHCITXDIR_READ
5771
uOffset, cbTransfer, rc));
5558
rc = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5775
int rc2 = ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
5776
if (RT_FAILURE(rc2))
5560
5777
AssertMsgFailed(("Destroying task list failed rc=%Rrc\n", rc));
5562
5779
if (RT_LIKELY(!pAhciPort->fPortReset))
5564
pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
5565
pAhciPortTaskState->uATARegError = 0;
5566
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5781
pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer - cbTransfer;
5784
pAhciPortTaskState->uATARegError = ID_ERR;
5785
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
5789
pAhciPortTaskState->uATARegError = 0;
5790
pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
5567
5792
/* Write updated command header into memory of the guest. */
5568
5793
PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
5569
5794
&pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
5603
5828
pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
5604
5829
ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
5605
5830
cTasksToProcess--;
5606
if (!cTasksToProcess)
5832
/* If we encountered an error notify the guest and continue with the next task. */
5835
if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5836
ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
5838
uQueuedTasksFinished = 0;
5840
else if (!cTasksToProcess)
5607
5841
cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
5610
5844
if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
5611
ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, pAhciPortTaskState, true);
5845
ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
5613
5847
uQueuedTasksFinished = 0;
6136
6370
* Query the block and blockbios interfaces.
6138
pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
6372
pAhciPort->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCK);
6139
6373
if (!pAhciPort->pDrvBlock)
6141
6375
AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
6142
6376
return VERR_PDM_MISSING_INTERFACE;
6144
pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
6378
pAhciPort->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKBIOS);
6145
6379
if (!pAhciPort->pDrvBlockBios)
6147
6381
AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
6148
6382
return VERR_PDM_MISSING_INTERFACE;
6151
pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
6385
pAhciPort->pDrvMount = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIMOUNT);
6153
6387
/* Try to get the optional async block interface. */
6154
pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
6388
pAhciPort->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pAhciPort->pDrvBase, PDMIBLOCKASYNC);
6157
6391
* Validate type.
6384
6620
/* Create the async IO thread. */
6385
rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6386
RTTHREADTYPE_IO, szName);
6621
rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6622
RTTHREADTYPE_IO, szName);
6387
6623
if (RT_FAILURE(rc))
6389
6625
AssertMsgFailed(("%s: Async IO Thread creation for %s failed rc=%d\n", __FUNCTION__, szName, rc));
6467
* Construct a device instance for a VM.
6469
* @returns VBox status.
6470
* @param pDevIns The device instance data.
6471
* If the registration structure is needed, pDevIns->pDevReg points to it.
6472
* @param iInstance Instance number. Use this to figure out which registers and such to use.
6473
* The device number is also found in pDevIns->iInstance, but since it's
6474
* likely to be freqently used PDM passes it as parameter.
6475
* @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
6476
* of the device instance. It's also found in pDevIns->pCfgHandle, but like
6477
* iInstance it's expected to be used a bit in this function.
6703
* @interface_method_impl{PDMDEVREG,pfnConstruct}
6479
static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
6705
static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
6481
6707
PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
6482
6708
PPDMIBASE pBase;
6502
6729
return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
6503
6730
N_("AHCI configuration error: unknown option specified"));
6505
rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
6732
rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
6506
6733
if (RT_FAILURE(rc))
6507
6734
return PDMDEV_SET_ERROR(pDevIns, rc,
6508
6735
N_("AHCI configuration error: failed to read GCEnabled as boolean"));
6509
6736
Log(("%s: fGCEnabled=%d\n", __FUNCTION__, fGCEnabled));
6511
rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
6738
rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
6512
6739
if (RT_FAILURE(rc))
6513
6740
return PDMDEV_SET_ERROR(pDevIns, rc,
6514
6741
N_("AHCI configuration error: failed to read R0Enabled as boolean"));
6515
6742
Log(("%s: fR0Enabled=%d\n", __FUNCTION__, fR0Enabled));
6517
rc = CFGMR3QueryU32Def(pCfgHandle, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6744
rc = CFGMR3QueryU32Def(pCfg, "PortCount", &pThis->cPortsImpl, AHCI_MAX_NR_PORTS_IMPL);
6518
6745
if (RT_FAILURE(rc))
6519
6746
return PDMDEV_SET_ERROR(pDevIns, rc,
6520
6747
N_("AHCI configuration error: failed to read PortCount as integer"));
6528
6755
N_("AHCI configuration error: PortCount=%u should be at least 1"),
6529
6756
pThis->cPortsImpl);
6531
rc = CFGMR3QueryBoolDef(pCfgHandle, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6758
rc = CFGMR3QueryBoolDef(pCfg, "UseAsyncInterfaceIfAvailable", &pThis->fUseAsyncInterfaceIfAvailable, true);
6532
6759
if (RT_FAILURE(rc))
6533
6760
return PDMDEV_SET_ERROR(pDevIns, rc,
6534
6761
N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
6535
rc = CFGMR3QueryU32Def(pCfgHandle, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6762
rc = CFGMR3QueryU32Def(pCfg, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
6536
6763
if (RT_FAILURE(rc))
6537
6764
return PDMDEV_SET_ERROR(pDevIns, rc,
6538
6765
N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
6539
rc = CFGMR3QueryU32Def(pCfgHandle, "MillisToSleep", &pThis->cMillisToSleep, 0);
6766
rc = CFGMR3QueryU32Def(pCfg, "MillisToSleep", &pThis->cMillisToSleep, 0);
6540
6767
if (RT_FAILURE(rc))
6541
6768
return PDMDEV_SET_ERROR(pDevIns, rc,
6542
6769
N_("AHCI configuration error: failed to read MillisToSleep as integer"));
6646
6873
* Create the transmit queue.
6648
rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6649
ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6875
rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
6876
ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
6650
6877
if (RT_FAILURE(rc))
6652
6879
pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
6746
6973
RTStrPrintf(szSerial, sizeof(szSerial), "VB%08x-%08x", Uuid.au32[0], Uuid.au32[3]);
6748
6975
/* Get user config if present using defaults otherwise. */
6749
PCFGMNODE pCfgNode = CFGMR3GetChild(pCfgHandle, szName);
6976
PCFGMNODE pCfgNode = CFGMR3GetChild(pCfg, szName);
6750
6977
rc = CFGMR3QueryStringDef(pCfgNode, "SerialNumber", pAhciPort->szSerialNumber, sizeof(pAhciPort->szSerialNumber),
6752
6979
if (RT_FAILURE(rc))
6836
7063
AssertMsgRC(rc, ("Failed to create event semaphore for %s rc=%Rrc.\n", szName, rc));
6839
rc = PDMDevHlpPDMThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
6840
RTTHREADTYPE_IO, szName);
7066
rc = PDMDevHlpThreadCreate(pDevIns, &pAhciPort->pAsyncIOThread, pAhciPort, ahciAsyncIOLoop, ahciAsyncIOLoopWakeUp, 0,
7067
RTTHREADTYPE_IO, szName);
6841
7068
AssertMsgRC(rc, ("%s: Async IO Thread creation for %s failed rc=%Rrc\n", szName, rc));
6900
7127
{ "SecondaryMaster", "SecondarySlave" }
6903
rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][0], &iPortMaster, 2 * i);
7130
rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][0], &iPortMaster, 2 * i);
6904
7131
if (RT_FAILURE(rc))
6905
7132
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6906
7133
N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][0]);
6908
rc = CFGMR3QueryU32Def(pCfgHandle, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
7135
rc = CFGMR3QueryU32Def(pCfg, s_apszDescs[i][1], &iPortSlave, 2 * i + 1);
6909
7136
if (RT_FAILURE(rc))
6910
7137
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
6911
7138
N_("AHCI configuration error: failed to read %s as U32"), s_apszDescs[i][1]);