Changeset 33175 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Oct 16, 2010 6:32:23 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 66711
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevAHCI.cpp
r33125 r33175 5584 5584 #define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface) ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) ) 5585 5585 5586 static void ahciWarningDiskFull(PPDMDEVINS pDevIns) 5587 { 5588 int rc; 5589 LogRel(("AHCI: Host disk full\n")); 5590 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL", 5591 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space")); 5592 AssertRC(rc); 5593 } 5594 5595 static void ahciWarningFileTooBig(PPDMDEVINS pDevIns) 5596 { 5597 int rc; 5598 LogRel(("AHCI: File too big\n")); 5599 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG", 5600 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")); 5601 AssertRC(rc); 5602 } 5603 5604 static void ahciWarningISCSI(PPDMDEVINS pDevIns) 5605 { 5606 int rc; 5607 LogRel(("AHCI: iSCSI target unavailable\n")); 5608 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN", 5609 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again")); 5610 AssertRC(rc); 5611 } 5612 5613 bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc) 5614 { 5615 if (rc == VERR_DISK_FULL) 5616 { 5617 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false)) 5618 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns)); 5619 return true; 5620 } 5621 if (rc == VERR_FILE_TOO_BIG) 5622 { 5623 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false)) 5624 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns)); 5625 return true; 5626 } 5627 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED) 5628 { 5629 /* iSCSI connection abort (first error) or failure to reestablish 5630 * connection (second error). Pause VM. On resume we'll retry. */ 5631 if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false)) 5632 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns)); 5633 return true; 5634 } 5635 return false; 5636 } 5637 5586 5638 /** 5587 5639 * Complete a data transfer task by freeing all occupied ressources … … 5596 5648 static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq) 5597 5649 { 5650 bool fRedo = false; 5651 5598 5652 /* Free system resources occupied by the scatter gather list. */ 5599 5653 if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH) 5600 5654 ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState); 5601 5655 5656 if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ) 5657 { 5658 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer); 5659 pAhciPort->Led.Actual.s.fReading = 0; 5660 } 5661 else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE) 5662 { 5663 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer); 5664 pAhciPort->Led.Actual.s.fWriting = 0; 5665 } 5666 5602 5667 if (RT_FAILURE(rcReq)) 5603 5668 { 5604 pAhciPortTaskState->cmdHdr.u32PRDBC = 0;5605 pAhciPortTaskState->uATARegError = ID_ERR;5606 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;5607 5608 5669 /* Log the error. */ 5609 5670 if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS) … … 5621 5682 pAhciPortTaskState->cbTransfer, rcReq)); 5622 5683 } 5623 ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL); 5684 5685 fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq); 5686 if (!fRedo) 5687 { 5688 pAhciPortTaskState->cmdHdr.u32PRDBC = 0; 5689 pAhciPortTaskState->uATARegError = ID_ERR; 5690 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR; 5691 ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL); 5692 } 5624 5693 } 5625 5694 else … … 5635 5704 } 5636 5705 5637 if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)5638 {5639 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);5640 pAhciPort->Led.Actual.s.fReading = 0;5641 }5642 else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)5643 {5644 STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);5645 pAhciPort->Led.Actual.s.fWriting = 0;5646 }5647 5648 if (pAhciPortTaskState->fQueued)5649 {5650 uint32_t cOutstandingTasks;5651 5652 ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));5653 cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);5654 ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));5655 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))5656 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));5657 5658 5706 #ifdef RT_STRICT 5659 5660 5707 bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true); 5708 AssertMsg(fXchg, ("Task is not active\n")); 5661 5709 #endif 5662 5710 5663 /* Always raise an interrupt after task completion; delaying5664 * this (interrupt coalescing) increases latency and has a significant5665 * impact on performance (see #5071)5666 */5667 ahciSendSDBFis(pAhciPort, 0, true);5668 }5669 else5670 {5671 #ifdef RT_STRICT5672 bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);5673 AssertMsg(fXchg, ("Task is not active\n"));5674 #endif5675 5676 ASMAtomicDecU32(&pAhciPort->uActTasksActive);5677 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);5678 }5679 5680 5711 /* Add the task to the cache. */ 5681 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState; 5712 ASMAtomicWritePtr(&pAhciPort->aCachedTasks[pAhciPortTaskState->uTag], pAhciPortTaskState); 5713 ASMAtomicDecU32(&pAhciPort->uActTasksActive); 5714 5715 if (!fRedo) 5716 { 5717 if (pAhciPortTaskState->fQueued) 5718 { 5719 if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE)) 5720 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag)); 5721 5722 /* 5723 * Always raise an interrupt after task completion; delaying 5724 * this (interrupt coalescing) increases latency and has a significant 5725 * impact on performance (see #5071) 5726 */ 5727 ahciSendSDBFis(pAhciPort, 0, true); 5728 } 5729 else 5730 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true); 5731 } 5682 5732 5683 5733 return VINF_SUCCESS; … … 5705 5755 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3); 5706 5756 return rc; 5707 }5708 5709 static void ahciWarningDiskFull(PPDMDEVINS pDevIns)5710 {5711 int rc;5712 LogRel(("AHCI: Host disk full\n"));5713 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",5714 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));5715 AssertRC(rc);5716 }5717 5718 static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)5719 {5720 int rc;5721 LogRel(("AHCI: File too big\n"));5722 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",5723 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"));5724 AssertRC(rc);5725 }5726 5727 static void ahciWarningISCSI(PPDMDEVINS pDevIns)5728 {5729 int rc;5730 LogRel(("AHCI: iSCSI target unavailable\n"));5731 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",5732 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));5733 AssertRC(rc);5734 }5735 5736 bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)5737 {5738 if (rc == VERR_DISK_FULL)5739 {5740 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));5741 return true;5742 }5743 if (rc == VERR_FILE_TOO_BIG)5744 {5745 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));5746 return true;5747 }5748 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)5749 {5750 /* iSCSI connection abort (first error) or failure to reestablish5751 * connection (second error). Pause VM. On resume we'll retry. */5752 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));5753 return true;5754 }5755 return false;5756 5757 } 5757 5758 … … 6508 6509 } 6509 6510 else 6510 {6511 pAhciPort->fRedo = true;6512 6511 pAhciPort->cTasksToProcess = cTasksToProcess; 6513 }6514 6512 } 6515 6513 else … … 7094 7092 for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++) 7095 7093 { 7094 PAHCIPort pAhciPort = &pThis->ahciPort[i]; 7095 7096 7096 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB); 7097 7097 SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU); … … 7138 7138 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true")); 7139 7139 7140 if ( pThis->ahciPort[i].uActWritePos != pThis->ahciPort[i].uActReadPos 7141 && !pThis->ahciPort[i].fAsyncInterface) 7140 /* Check if we have tasks pending. */ 7141 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished; 7142 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished; 7143 7144 if (fTasksOutstanding || fQueuedTasksOutstanding) 7142 7145 { 7143 7146 /* … … 7147 7150 * of the FIFO counters. 7148 7151 */ 7149 PAHCIPort pAhciPort = &pThis->ahciPort[i]; 7150 7151 pAhciPort->fRedo = true; 7152 /* 7153 * Because we don't save the task FIFO we have to reconstruct it by using the 7154 * SACT and CI registers along with the shadowed variables containing the 7155 * completed tasks and placing them in the FIFO again. 7156 */ 7157 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished; 7158 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished; 7159 7160 pAhciPort->uActWritePos = 0; 7161 pAhciPort->uActReadPos = 0; 7162 7163 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++) 7152 7153 if (!pAhciPort->fAsyncInterface) 7164 7154 { 7165 if ( fTasksOutstanding & (1 << uTag) 7166 || fQueuedTasksOutstanding & (1 << uTag)) 7155 /* 7156 * Because we don't save the task FIFO we have to reconstruct it by using the 7157 * SACT and CI registers along with the shadowed variables containing the 7158 * completed tasks and placing them in the FIFO again. 7159 */ 7160 pAhciPort->fRedo = true; 7161 7162 pAhciPort->uActWritePos = 0; 7163 pAhciPort->uActReadPos = 0; 7164 7165 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++) 7167 7166 { 7168 pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0); 7169 pAhciPort->uActWritePos++; 7170 pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks); 7171 pAhciPort->cTasksToProcess++; 7167 if ( fTasksOutstanding & (1 << uTag) 7168 || fQueuedTasksOutstanding & (1 << uTag)) 7169 { 7170 pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0); 7171 pAhciPort->uActWritePos++; 7172 pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks); 7173 pAhciPort->cTasksToProcess++; 7174 } 7175 } 7176 } 7177 else 7178 { 7179 /* Use the PDM queue. */ 7180 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++) 7181 { 7182 if ( fTasksOutstanding & (1 << uTag) 7183 || fQueuedTasksOutstanding & (1 << uTag)) 7184 { 7185 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pThis->CTX_SUFF(pNotifierQueue)); 7186 AssertMsg(pItem, ("Allocating item for queue failed\n")); 7187 7188 pItem->iPort = pThis->ahciPort[i].iLUN; 7189 pItem->iTask = uTag; 7190 pItem->fQueued = !!(fQueuedTasksOutstanding & (1 << uTag)); /* Mark if the task is queued. */ 7191 PDMQueueInsert(pThis->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem); 7192 } 7172 7193 } 7173 7194 } … … 7546 7567 { 7547 7568 PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI); 7569 7570 /* 7571 * Check if one of the ports has the redo flag set 7572 * and queue all pending tasks again. 7573 */ 7574 for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++) 7575 { 7576 PAHCIPort pAhciPort = &pAhci->ahciPort[i]; 7577 7578 if ( pAhciPort->fRedo 7579 && pAhciPort->fAsyncInterface) 7580 { 7581 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished; 7582 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished; 7583 7584 pAhciPort->fRedo = false; 7585 7586 /* Use the PDM queue. */ 7587 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++) 7588 { 7589 if ( fTasksOutstanding & (1 << uTag) 7590 || fQueuedTasksOutstanding & (1 << uTag)) 7591 { 7592 PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue)); 7593 AssertMsg(pItem, ("Allocating item for queue failed\n")); 7594 7595 pItem->iPort = pAhci->ahciPort[i].iLUN; 7596 pItem->iTask = uTag; 7597 pItem->fQueued = !!(fQueuedTasksOutstanding & (1 << uTag)); /* Mark if the task is queued. */ 7598 PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem); 7599 } 7600 } 7601 } 7602 } 7548 7603 7549 7604 Log(("%s:\n", __FUNCTION__));
Note:
See TracChangeset
for help on using the changeset viewer.