Changeset 55847 in vbox
- Timestamp:
- May 13, 2015 1:46:42 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 100298
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevAHCI.cpp
r55775 r55847 47 47 #include <iprt/asm.h> 48 48 #include <iprt/string.h> 49 #include <iprt/list.h> 49 50 #ifdef IN_RING3 50 51 # include <iprt/param.h> … … 279 280 280 281 /** Task encountered a buffer overflow. */ 281 #define AHCI_REQ_OVERFLOW RT_BIT_32(0)282 #define AHCI_REQ_OVERFLOW RT_BIT_32(0) 282 283 /** Request is a PIO data command, if this flag is not set it either is 283 284 * a command which does not transfer data or a DMA command based on the transfer size. */ 284 #define AHCI_REQ_PIO_DATA RT_BIT_32(1)285 #define AHCI_REQ_PIO_DATA RT_BIT_32(1) 285 286 /** The request has the SACT register set. */ 286 #define AHCI_REQ_CLEAR_SACT RT_BIT_32(2) 287 /** FLag whether the request is queued. */ 288 #define AHCI_REQ_IS_QUEUED RT_BIT_32(3) 287 #define AHCI_REQ_CLEAR_SACT RT_BIT_32(2) 288 /** Flag whether the request is queued. */ 289 #define AHCI_REQ_IS_QUEUED RT_BIT_32(3) 290 /** Flag whether the request is stored on the stack. */ 291 #define AHCI_REQ_IS_ON_STACK RT_BIT_32(4) 289 292 290 293 /** … … 293 296 typedef struct AHCIREQ 294 297 { 298 /** List node for the free list if the request is not in use. */ 299 RTLISTNODE NodeList; 295 300 /** Task state. */ 296 301 volatile AHCITXSTATE enmTxState; … … 523 528 /** Async IO Thread. */ 524 529 R3PTRTYPE(PPDMTHREAD) pAsyncIOThread; 525 /** 526 * Array of cached tasks. The tag number is the index value. 527 * Only used with the async interface. 528 */ 529 R3PTRTYPE(PAHCIREQ) aCachedTasks[AHCI_NR_COMMAND_SLOTS]; 530 /** Array of active tasks indexed by the tag. */ 531 R3PTRTYPE(volatile PAHCIREQ) aActiveTasks[AHCI_NR_COMMAND_SLOTS]; 530 532 /** First task throwing an error. */ 531 533 R3PTRTYPE(volatile PAHCIREQ) pTaskErr; … … 567 569 568 570 uint32_t u32Alignment5; 571 572 /** Critical section protecting the global free list. */ 573 RTCRITSECT CritSectReqsFree; 574 /** Head of the global free request list. */ 575 R3PTRTYPE(PRTLISTANCHOR) pListReqsFree; 576 569 577 } AHCIPort; 570 578 /** Pointer to the state of an AHCI port. */ … … 944 952 static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept); 945 953 static void ahciReqMemFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, bool fForceFree); 954 static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort); 946 955 #endif 947 956 RT_C_DECLS_END … … 4643 4652 * is about to be destroyed. 4644 4653 */ 4645 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++) 4646 { 4647 if (pAhciPort->aCachedTasks[i]) 4648 ahciReqMemFree(pAhciPort, pAhciPort->aCachedTasks[i], true /* fForceFree */); 4649 } 4654 ahciR3PortCachedReqsFree(pAhciPort); 4650 4655 4651 4656 rc = VMR3ReqPriorityCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY, … … 5677 5682 static void ahciR3PortCachedReqsFree(PAHCIPort pAhciPort) 5678 5683 { 5679 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++) 5680 { 5681 if (pAhciPort->aCachedTasks[i]) 5682 { 5683 ahciReqMemFree(pAhciPort, pAhciPort->aCachedTasks[i], true /* fForceFree */); 5684 RTMemFree(pAhciPort->aCachedTasks[i]); 5685 pAhciPort->aCachedTasks[i] = NULL; 5686 } 5684 if (pAhciPort->pListReqsFree) 5685 { 5686 PAHCIREQ pReq = NULL; 5687 PAHCIREQ pReqNext = NULL; 5688 5689 RTCritSectEnter(&pAhciPort->CritSectReqsFree); 5690 RTListForEachSafe(pAhciPort->pListReqsFree, pReq, pReqNext, AHCIREQ, NodeList) 5691 { 5692 RTListNodeRemove(&pReq->NodeList); 5693 ahciReqMemFree(pAhciPort, pReq, true /* fForceFree */); 5694 RTMemFree(pReq); 5695 } 5696 RTCritSectLeave(&pAhciPort->CritSectReqsFree); 5687 5697 } 5688 5698 } … … 5698 5708 static bool ahciCancelActiveTasks(PAHCIPort pAhciPort, PAHCIREQ pAhciReqExcept) 5699 5709 { 5700 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->a CachedTasks); i++)5701 { 5702 PAHCIREQ pAhciReq = pAhciPort->aCachedTasks[i];5710 for (unsigned i = 0; i < RT_ELEMENTS(pAhciPort->aActiveTasks); i++) 5711 { 5712 PAHCIREQ pAhciReq = (PAHCIREQ)ASMAtomicXchgPtr((void * volatile *)&pAhciPort->aActiveTasks[i], NULL); 5703 5713 5704 5714 if ( VALID_PTR(pAhciReq) … … 5706 5716 { 5707 5717 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_CANCELED, AHCITXSTATE_ACTIVE); 5708 5709 5718 if (fXchg) 5710 5719 { … … 5718 5727 * a new task structure for this tag. 5719 5728 */ 5720 ASMAtomicWriteNullPtr(&pAhciPort->a CachedTasks[i]);5729 ASMAtomicWriteNullPtr(&pAhciPort->aActiveTasks[i]); 5721 5730 LogRel(("AHCI#%uP%u: Cancelled task %u\n", pAhciPort->CTX_SUFF(pDevIns)->iInstance, 5722 5731 pAhciPort->iLUN, pAhciReq->uTag)); … … 5932 5941 5933 5942 /** 5943 * Allocates a new AHCI request. 5944 * 5945 * @returns A new AHCI request structure or NULL if out of memory. 5946 * @param pAhciPort The AHCI port. 5947 */ 5948 static PAHCIREQ ahciR3ReqAlloc(PAHCIPort pAhciPort) 5949 { 5950 PAHCIREQ pAhciReq = NULL; 5951 5952 /* Check the global free list first. */ 5953 RTCritSectEnter(&pAhciPort->CritSectReqsFree); 5954 pAhciReq = RTListGetFirst(pAhciPort->pListReqsFree, AHCIREQ, NodeList); 5955 if (pAhciReq) 5956 RTListNodeRemove(&pAhciReq->NodeList); 5957 RTCritSectLeave(&pAhciPort->CritSectReqsFree); 5958 5959 if (!pAhciReq) 5960 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ)); 5961 5962 pAhciReq->enmTxState = AHCITXSTATE_ACTIVE; 5963 return pAhciReq; 5964 } 5965 5966 /** 5967 * Frees a given AHCI request structure. 5968 * 5969 * @returns nothing. 5970 * @param pAhciPort The AHCI port. 5971 */ 5972 static void ahciR3ReqFree(PAHCIPort pAhciPort, PAHCIREQ pAhciReq) 5973 { 5974 pAhciReq->enmTxState = AHCITXSTATE_FREE; 5975 5976 RTCritSectEnter(&pAhciPort->CritSectReqsFree); 5977 RTListAppend(pAhciPort->pListReqsFree, &pAhciReq->NodeList); 5978 RTCritSectLeave(&pAhciPort->CritSectReqsFree); 5979 } 5980 5981 /** 5934 5982 * Complete a data transfer task by freeing all occupied resources 5935 5983 * and notifying the guest. … … 5940 5988 * @param pAhciReq Pointer to the task which finished. 5941 5989 * @param rcReq IPRT status code of the completed request. 5942 * @param fFreeReq Flag whether to free the request if it was canceled. 5943 */ 5944 static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq, bool fFreeReq) 5945 { 5946 bool fXchg = false; 5990 */ 5991 static bool ahciTransferComplete(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, int rcReq) 5992 { 5947 5993 bool fRedo = false; 5948 5994 bool fCanceled = false; … … 5950 5996 AHCITXSTATE enmTxState = AHCITXSTATE_INVALID; 5951 5997 5952 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d fFreeReq=%RTbool\n",5953 pAhciPort, pAhciReq, rcReq , fFreeReq));5998 LogFlowFunc(("pAhciPort=%p pAhciReq=%p rcReq=%d\n", 5999 pAhciPort, pAhciReq, rcReq)); 5954 6000 5955 6001 enmTxState = (AHCITXSTATE)ASMAtomicReadU32((volatile uint32_t *)&pAhciReq->enmTxState); 5956 6002 VBOXDD_AHCI_REQ_COMPLETED(pAhciReq, rcReq, enmTxState, pAhciReq->uOffset, pAhciReq->cbTransfer); 5957 6003 VBOXDD_AHCI_REQ_COMPLETED_TIMESTAMP(pAhciReq, tsNow); 6004 6005 /* 6006 * Clear the request structure from the active request list first so it doesn't get cancelled 6007 * while we complete it. If the request is not in the active list anymore it was already canceled 6008 * and we have to make sure to not copy anything to guest memory because the guest might use it 6009 * for other things already. 6010 */ 6011 bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset); 6012 bool fXchg = ASMAtomicCmpXchgPtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL, pAhciReq); 6013 6014 if (fXchg) 6015 { 6016 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0, 6017 ("Inconsistent request counter\n")); 6018 ASMAtomicDecU32(&pAhciPort->cTasksActive); 6019 } 5958 6020 5959 6021 /* … … 5986 6048 pAhciPort->CTX_SUFF(pDevIns)->iInstance, pAhciPort->iLUN, pcszReq, (tsNow - pAhciReq->tsStart) / 1000)); 5987 6049 } 5988 5989 bool fPortReset = ASMAtomicReadBool(&pAhciPort->fPortReset);5990 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);5991 6050 5992 6051 if (fXchg && !fPortReset) … … 6046 6105 pAhciReq->cmdHdr.u32PRDBC = pAhciReq->cbTransfer; 6047 6106 6048 /* Status will be set byalready for non I/O requests. */6107 /* Status will be set already for non I/O requests. */ 6049 6108 if (pAhciReq->enmTxDir != AHCITXDIR_NONE) 6050 6109 { … … 6069 6128 } 6070 6129 6071 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,6072 ("Inconsistent request counter\n"));6073 ASMAtomicDecU32(&pAhciPort->cTasksActive);6074 6075 6130 if (!fRedo) 6076 6131 { … … 6108 6163 ("Task is not active but wasn't canceled and no port reset is active!\n")); 6109 6164 6110 /*6111 * If this handler switched the request state from active to free the request counter6112 * must be decremented.6113 */6114 if (fXchg)6115 {6116 Assert(fPortReset);6117 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) > 0 ,6118 ("Inconsistent request counter\n"));6119 ASMAtomicDecU32(&pAhciPort->cTasksActive);6120 }6121 6122 6165 fCanceled = true; 6123 ASMAtomicXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE);6124 6166 6125 6167 if (pAhciReq->enmTxDir == AHCITXDIR_TRIM) … … 6146 6188 pAhciReq->cbTransfer, rcReq)); 6147 6189 } 6148 6149 /* Finally free the task state structure because it is completely unused now. */6150 if (fFreeReq)6151 RTMemFree(pAhciReq);6152 6190 } 6153 6191 … … 6155 6193 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3); 6156 6194 6195 if (pAhciReq && !(pAhciReq->fFlags & AHCI_REQ_IS_ON_STACK)) 6196 ahciR3ReqFree(pAhciPort, pAhciReq); 6157 6197 return fCanceled; 6158 6198 } … … 6174 6214 __FUNCTION__, pInterface, pvUser, pAhciReq->uTag)); 6175 6215 6176 ahciTransferComplete(pAhciPort, pAhciReq, rcReq , true);6216 ahciTransferComplete(pAhciPort, pAhciReq, rcReq); 6177 6217 6178 6218 return VINF_SUCCESS; … … 6577 6617 6578 6618 /** 6619 * Submits a given request for execution. 6620 * 6621 * @returns Flag whether the request was canceled inbetween. 6622 * @param pAhciPort The port the request is for. 6623 * @param pAhciReq The request to submit. 6624 * @param enmTxDir The request type. 6625 */ 6626 static bool ahciR3ReqSubmit(PAHCIPort pAhciPort, PAHCIREQ pAhciReq, AHCITXDIR enmTxDir) 6627 { 6628 int rc = VINF_SUCCESS; 6629 bool fReqCanceled = false; 6630 6631 if (pAhciPort->fAsyncInterface) 6632 { 6633 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, pAhciReq->enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer); 6634 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart); 6635 if (enmTxDir == AHCITXDIR_FLUSH) 6636 { 6637 rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync, 6638 pAhciReq); 6639 } 6640 else if (enmTxDir == AHCITXDIR_TRIM) 6641 { 6642 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq); 6643 if (RT_SUCCESS(rc)) 6644 { 6645 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1; 6646 rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges, 6647 pAhciReq->u.Trim.cRanges, pAhciReq); 6648 } 6649 } 6650 else if (enmTxDir == AHCITXDIR_READ) 6651 { 6652 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1; 6653 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset, 6654 &pAhciReq->u.Io.DataSeg, 1, 6655 pAhciReq->cbTransfer, 6656 pAhciReq); 6657 } 6658 else 6659 { 6660 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1; 6661 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset, 6662 &pAhciReq->u.Io.DataSeg, 1, 6663 pAhciReq->cbTransfer, 6664 pAhciReq); 6665 } 6666 if (rc == VINF_VD_ASYNC_IO_FINISHED) 6667 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS); 6668 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS) 6669 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc); 6670 } 6671 else 6672 { 6673 if (enmTxDir == AHCITXDIR_FLUSH) 6674 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock); 6675 else if (enmTxDir == AHCITXDIR_TRIM) 6676 { 6677 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq); 6678 if (RT_SUCCESS(rc)) 6679 { 6680 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1; 6681 rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock, pAhciReq->u.Trim.paRanges, 6682 pAhciReq->u.Trim.cRanges); 6683 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0; 6684 } 6685 } 6686 else if (enmTxDir == AHCITXDIR_READ) 6687 { 6688 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1; 6689 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, pAhciReq->uOffset, 6690 pAhciReq->u.Io.DataSeg.pvSeg, 6691 pAhciReq->cbTransfer); 6692 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0; 6693 } 6694 else 6695 { 6696 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1; 6697 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, pAhciReq->uOffset, 6698 pAhciReq->u.Io.DataSeg.pvSeg, 6699 pAhciReq->cbTransfer); 6700 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0; 6701 } 6702 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc); 6703 } 6704 6705 return fReqCanceled; 6706 } 6707 6708 /** 6709 * Prepares the command for execution coping it from guest memory and doing a few 6710 * validation checks on it. 6711 * 6712 * @returns Whether the command was successfully fetched from guest memory and 6713 * can be continued. 6714 * @param pAhciPort The AHCI port the request is for. 6715 * @param pAhciReq Request structure to copy the command to. 6716 */ 6717 static bool ahciR3CmdPrepare(PAHCIPort pAhciPort, PAHCIREQ pAhciReq) 6718 { 6719 pAhciReq->tsStart = RTTimeMilliTS(); 6720 pAhciReq->uATARegStatus = 0; 6721 pAhciReq->uATARegError = 0; 6722 6723 /* Set current command slot */ 6724 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag); 6725 ASMAtomicWritePtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], pAhciReq); 6726 6727 bool fContinue = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq); 6728 if (fContinue) 6729 { 6730 /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */ 6731 if (pAhciPort->regSACT & RT_BIT_32(pAhciReq->uTag)) 6732 { 6733 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT; 6734 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, RT_BIT_32(pAhciReq->uTag)); 6735 } 6736 6737 if (pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C) 6738 { 6739 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS, 6740 ("There are more than 32 requests active")); 6741 ASMAtomicIncU32(&pAhciPort->cTasksActive); 6742 } 6743 else 6744 { 6745 /* If the reset bit is set put the device into reset state. */ 6746 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST) 6747 { 6748 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__)); 6749 pAhciPort->fResetDevice = true; 6750 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true); 6751 } 6752 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */ 6753 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq); 6754 else /* We are not in a reset state update the control registers. */ 6755 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__)); 6756 6757 fContinue = false; 6758 } 6759 } 6760 else 6761 { 6762 /* 6763 * Couldn't find anything in either the AHCI or SATA spec which 6764 * indicates what should be done if the FIS is not read successfully. 6765 * The closest thing is in the state machine, stating that the device 6766 * should go into idle state again (SATA spec 1.0 chapter 8.7.1). 6767 * Do the same here and ignore any corrupt FIS types, after all 6768 * the guest messed up everything and this behavior is undefined. 6769 */ 6770 fContinue = false; 6771 } 6772 6773 return fContinue; 6774 } 6775 6776 /** 6579 6777 * Transmit queue consumer 6580 6778 * Queue a new async task. … … 6673 6871 ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx)); 6674 6872 6675 /* 6676 * Check if there is already an allocated task struct in the cache. 6677 * Allocate a new task otherwise. 6678 */ 6679 if (!pAhciPort->aCachedTasks[idx]) 6873 /* Check whether the request is already active and ignore. */ 6874 if (ASMAtomicReadPtr((void * volatile *)&pAhciPort->aActiveTasks[idx])) 6680 6875 { 6681 pAhciReq = (PAHCIREQ)RTMemAllocZ(sizeof(AHCIREQ)); 6682 AssertMsg(pAhciReq, ("%s: Cannot allocate task state memory!\n")); 6683 pAhciReq->enmTxState = AHCITXSTATE_FREE; 6684 pAhciPort->aCachedTasks[idx] = pAhciReq; 6685 } 6686 else 6687 pAhciReq = pAhciPort->aCachedTasks[idx]; 6688 6689 bool fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_ACTIVE, AHCITXSTATE_FREE); 6690 AssertMsg(fXchg, ("Task is already active\n")); 6691 6692 pAhciReq->tsStart = RTTimeMilliTS(); 6693 pAhciReq->uATARegStatus = 0; 6694 pAhciReq->uATARegError = 0; 6695 pAhciReq->fFlags = 0; 6696 6697 /* Set current command slot */ 6698 pAhciReq->uTag = idx; 6699 ASMAtomicWriteU32(&pAhciPort->u32CurrentCommandSlot, pAhciReq->uTag); 6700 6701 bool fFisRead = ahciPortTaskGetCommandFis(pAhciPort, pAhciReq); 6702 if (RT_UNLIKELY(!fFisRead)) 6703 { 6704 /* 6705 * Couldn't find anything in either the AHCI or SATA spec which 6706 * indicates what should be done if the FIS is not read successfully. 6707 * The closest thing is in the state machine, stating that the device 6708 * should go into idle state again (SATA spec 1.0 chapter 8.7.1). 6709 * Do the same here and ignore any corrupt FIS types, after all 6710 * the guest messed up everything and this behavior is undefined. 6711 */ 6712 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE); 6713 Assert(fXchg); 6714 u32Tasks &= ~RT_BIT_32(idx); /* Clear task bit. */ 6715 idx = ASMBitFirstSetU32(u32Tasks); 6876 ahciLog(("%s: Ignoring command at slot %d because it is already active\n", __FUNCTION__, idx)); 6716 6877 continue; 6717 6878 } 6718 6879 6719 /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */6720 if ( pAhciPort->regSACT & (1 << idx))6880 pAhciReq = ahciR3ReqAlloc(pAhciPort); 6881 if (RT_LIKELY(pAhciReq)) 6721 6882 { 6722 pAhciReq->fFlags |= AHCI_REQ_CLEAR_SACT; 6723 ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciReq->uTag)); 6883 pAhciReq->uTag = idx; 6884 pAhciReq->fFlags = 0; 6885 6886 bool fContinue = ahciR3CmdPrepare(pAhciPort, pAhciReq); 6887 if (fContinue) 6888 { 6889 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis); 6890 pAhciReq->enmTxDir = enmTxDir; 6891 6892 if (enmTxDir != AHCITXDIR_NONE) 6893 { 6894 if ( enmTxDir != AHCITXDIR_FLUSH 6895 && enmTxDir != AHCITXDIR_TRIM) 6896 { 6897 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA); 6898 6899 rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer); 6900 if (RT_FAILURE(rc)) 6901 { 6902 /* In case we can't allocate enough memory fail the request with an overflow error. */ 6903 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc)); 6904 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW; 6905 } 6906 } 6907 6908 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW)) 6909 fReqCanceled = ahciR3ReqSubmit(pAhciPort, pAhciReq, enmTxDir); 6910 else /* Overflow is handled in completion routine. */ 6911 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS); 6912 } 6913 else 6914 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS); 6915 } /* Command */ 6916 else 6917 { 6918 ASMAtomicWritePtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL); 6919 ahciR3ReqFree(pAhciPort, pAhciReq); 6920 } 6724 6921 } 6725 6726 if (!(pAhciReq->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C)) 6922 else /* !Request allocated, use on stack variant to signal the error. */ 6727 6923 { 6728 /* If the reset bit is set put the device into reset state. */ 6729 if (pAhciReq->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST) 6924 AHCIREQ Req; 6925 Req.uTag = idx; 6926 Req.fFlags = AHCI_REQ_IS_ON_STACK; 6927 6928 bool fContinue = ahciR3CmdPrepare(pAhciPort, &Req); 6929 if (fContinue) 6930 fReqCanceled = ahciTransferComplete(pAhciPort, &Req, VERR_NO_MEMORY); 6931 else 6730 6932 { 6731 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__)); 6732 pAhciPort->fResetDevice = true; 6733 ahciSendD2HFis(pAhciPort, pAhciReq, pAhciReq->cmdFis, true); 6933 ASMAtomicWritePtr(&pAhciPort->aActiveTasks[pAhciReq->uTag], NULL); 6934 ahciR3ReqFree(pAhciPort, pAhciReq); 6734 6935 } 6735 else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */6736 ahciFinishStorageDeviceReset(pAhciPort, pAhciReq);6737 else /* We are not in a reset state update the control registers. */6738 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));6739 6740 fXchg = ASMAtomicCmpXchgU32((volatile uint32_t *)&pAhciReq->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE);6741 AssertMsg(fXchg, ("Task is not active\n"));6742 break;6743 6936 } 6744 else6745 {6746 AssertReleaseMsg(ASMAtomicReadU32(&pAhciPort->cTasksActive) < AHCI_NR_COMMAND_SLOTS,6747 ("There are more than 32 requests active"));6748 ASMAtomicIncU32(&pAhciPort->cTasksActive);6749 6750 enmTxDir = ahciProcessCmd(pAhciPort, pAhciReq, pAhciReq->cmdFis);6751 pAhciReq->enmTxDir = enmTxDir;6752 6753 if (enmTxDir != AHCITXDIR_NONE)6754 {6755 if ( enmTxDir != AHCITXDIR_FLUSH6756 && enmTxDir != AHCITXDIR_TRIM)6757 {6758 STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);6759 6760 rc = ahciIoBufAllocate(pAhciPort, pAhciReq, pAhciReq->cbTransfer);6761 if (RT_FAILURE(rc))6762 {6763 /* In case we can't allocate enough memory fail the request with an overflow error. */6764 AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));6765 pAhciReq->fFlags |= AHCI_REQ_OVERFLOW;6766 }6767 }6768 6769 if (!(pAhciReq->fFlags & AHCI_REQ_OVERFLOW))6770 {6771 if (pAhciPort->fAsyncInterface)6772 {6773 VBOXDD_AHCI_REQ_SUBMIT(pAhciReq, enmTxDir, pAhciReq->uOffset, pAhciReq->cbTransfer);6774 VBOXDD_AHCI_REQ_SUBMIT_TIMESTAMP(pAhciReq, pAhciReq->tsStart);6775 if (enmTxDir == AHCITXDIR_FLUSH)6776 {6777 rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,6778 pAhciReq);6779 }6780 else if (enmTxDir == AHCITXDIR_TRIM)6781 {6782 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);6783 if (RT_SUCCESS(rc))6784 {6785 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;6786 rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciReq->u.Trim.paRanges,6787 pAhciReq->u.Trim.cRanges, pAhciReq);6788 }6789 }6790 else if (enmTxDir == AHCITXDIR_READ)6791 {6792 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;6793 rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,6794 &pAhciReq->u.Io.DataSeg, 1,6795 pAhciReq->cbTransfer,6796 pAhciReq);6797 }6798 else6799 {6800 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;6801 rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciReq->uOffset,6802 &pAhciReq->u.Io.DataSeg, 1,6803 pAhciReq->cbTransfer,6804 pAhciReq);6805 }6806 if (rc == VINF_VD_ASYNC_IO_FINISHED)6807 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);6808 else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)6809 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);6810 }6811 else6812 {6813 if (enmTxDir == AHCITXDIR_FLUSH)6814 rc = pAhciPort->pDrvBlock->pfnFlush(pAhciPort->pDrvBlock);6815 else if (enmTxDir == AHCITXDIR_TRIM)6816 {6817 rc = ahciTrimRangesCreate(pAhciPort, pAhciReq);6818 if (RT_SUCCESS(rc))6819 {6820 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;6821 rc = pAhciPort->pDrvBlock->pfnDiscard(pAhciPort->pDrvBlock, pAhciReq->u.Trim.paRanges,6822 pAhciReq->u.Trim.cRanges);6823 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;6824 }6825 }6826 else if (enmTxDir == AHCITXDIR_READ)6827 {6828 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;6829 rc = pAhciPort->pDrvBlock->pfnRead(pAhciPort->pDrvBlock, pAhciReq->uOffset,6830 pAhciReq->u.Io.DataSeg.pvSeg,6831 pAhciReq->cbTransfer);6832 pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 0;6833 }6834 else6835 {6836 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;6837 rc = pAhciPort->pDrvBlock->pfnWrite(pAhciPort->pDrvBlock, pAhciReq->uOffset,6838 pAhciReq->u.Io.DataSeg.pvSeg,6839 pAhciReq->cbTransfer);6840 pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 0;6841 }6842 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, rc, true);6843 }6844 }6845 }6846 else6847 fReqCanceled = ahciTransferComplete(pAhciPort, pAhciReq, VINF_SUCCESS, true);6848 } /* Command */6849 6937 6850 6938 /* … … 7581 7669 pAhciPort->fATAPIPassthrough = pAhciPort->fATAPI ? (pAhciPort->pDrvBlock->pfnSendCmd != NULL) : false; 7582 7670 7671 rc = RTCritSectInit(&pAhciPort->CritSectReqsFree); 7672 if (RT_FAILURE(rc)) 7673 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 7674 N_("AHCI initialisation error: Failed to create critical section for free request list")); 7675 7676 pAhciPort->pListReqsFree = (PRTLISTANCHOR)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(RTLISTANCHOR)); 7677 if (!pAhciPort->pListReqsFree) 7678 return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS, 7679 N_("AHCI initialisation error: Failed to allocate memory for free request list")); 7680 7681 RTListInit(pAhciPort->pListReqsFree); 7682 7583 7683 if (pAhciPort->fATAPI) 7584 7684 { … … 7884 7984 /* Free all cached I/O tasks. */ 7885 7985 ahciR3PortCachedReqsFree(pAhciPort); 7986 7987 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree)) 7988 RTCritSectDelete(&pAhciPort->CritSectReqsFree); 7989 7990 if (pAhciPort->pListReqsFree) 7991 MMR3HeapFree(pAhciPort->pListReqsFree); 7992 7993 pAhciPort->pListReqsFree = NULL; 7886 7994 7887 7995 if (!(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG)) … … 8130 8238 } 8131 8239 8240 if (RTCritSectIsInitialized(&pAhciPort->CritSectReqsFree)) 8241 RTCritSectDelete(&pAhciPort->CritSectReqsFree); 8242 8132 8243 #ifdef VBOX_STRICT 8133 8244 for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++) 8134 Assert(!pAhciPort->a CachedTasks[i]);8245 Assert(!pAhciPort->aActiveTasks[i]); 8135 8246 #endif 8136 8247 }
Note:
See TracChangeset
for help on using the changeset viewer.