Changeset 32957 in vbox for trunk/src/VBox/Devices/Storage
- Timestamp:
- Oct 6, 2010 4:10:48 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 66456
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevAHCI.cpp
r32939 r32957 531 531 /** Error counter */ 532 532 uint32_t cErrors; 533 534 /** Tasks to process */ 535 uint32_t cTasksToProcess; 536 /** Flag whether we need to redo a task. */ 537 bool fRedo; 533 538 534 539 } AHCIPort; … … 4597 4602 sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks; 4598 4603 4599 4604 ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis); 4600 4605 4601 4606 if (RT_UNLIKELY(pTaskErr)) … … 5665 5670 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3); 5666 5671 return rc; 5672 } 5673 5674 static void ahciWarningDiskFull(PPDMDEVINS pDevIns) 5675 { 5676 int rc; 5677 LogRel(("AHCI: Host disk full\n")); 5678 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL", 5679 N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space")); 5680 AssertRC(rc); 5681 } 5682 5683 static void ahciWarningFileTooBig(PPDMDEVINS pDevIns) 5684 { 5685 int rc; 5686 LogRel(("AHCI: File too big\n")); 5687 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG", 5688 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")); 5689 AssertRC(rc); 5690 } 5691 5692 static void ahciWarningISCSI(PPDMDEVINS pDevIns) 5693 { 5694 int rc; 5695 LogRel(("AHCI: iSCSI target unavailable\n")); 5696 rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN", 5697 N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again")); 5698 AssertRC(rc); 5699 } 5700 5701 bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc) 5702 { 5703 if (rc == VERR_DISK_FULL) 5704 { 5705 ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns)); 5706 return true; 5707 } 5708 if (rc == VERR_FILE_TOO_BIG) 5709 { 5710 ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns)); 5711 return true; 5712 } 5713 if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED) 5714 { 5715 /* iSCSI connection abort (first error) or failure to reestablish 5716 * connection (second error). Pause VM. On resume we'll retry. */ 5717 ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns)); 5718 return true; 5719 } 5720 return false; 5667 5721 } 5668 5722 … … 6199 6253 uint32_t uIORequestsProcessed = 0; 6200 6254 uint32_t uIOsPerSec = 0; 6255 uint32_t cTasksToProcess = 0; 6256 bool fRedoDontWait = false; 6201 6257 6202 6258 ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN)); … … 6204 6260 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 6205 6261 return VINF_SUCCESS; 6262 6263 if (pAhciPort->fRedo) 6264 { 6265 /* 6266 * We entered again after the VM was suspended due to a task failing. 6267 * Use that task and try to process it again. 6268 */ 6269 ahciLog(("%s: Port %d redo task\n", __FUNCTION__, pAhciPort->iLUN)); 6270 cTasksToProcess = pAhciPort->cTasksToProcess; 6271 pAhciPort->cTasksToProcess = 0; 6272 fRedoDontWait = true; 6273 } 6206 6274 6207 6275 /* We use only one task structure. */ … … 6213 6281 } 6214 6282 6215 while(pThread->enmState == PDMTHREADSTATE_RUNNING) 6216 { 6217 uint32_t uQueuedTasksFinished = 0; 6218 6219 /* New run to get number of I/O requests per second?. */ 6220 if (!u64StartTime) 6221 u64StartTime = RTTimeMilliTS(); 6222 6223 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true); 6224 if (pAhci->fSignalIdle) 6225 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3); 6226 6227 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000); 6228 if (rc == VERR_TIMEOUT) 6229 { 6230 /* No I/O requests inbetween. Reset statistics and wait again. */ 6231 pAhciPort->StatIORequestsPerSecond.c = 0; 6232 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT); 6283 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 6284 { 6285 6286 if (!fRedoDontWait) 6287 { 6288 /* New run to get number of I/O requests per second?. */ 6289 if (!u64StartTime) 6290 u64StartTime = RTTimeMilliTS(); 6291 6292 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true); 6293 if (pAhci->fSignalIdle) 6294 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3); 6295 6296 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000); 6297 if (rc == VERR_TIMEOUT) 6298 { 6299 /* No I/O requests inbetween. Reset statistics and wait again. */ 6300 pAhciPort->StatIORequestsPerSecond.c = 0; 6301 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT); 6302 } 6303 6304 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING)) 6305 break; 6306 6307 /* 6308 * Don't process further tasks if the redo flag is set but wait again 6309 * until we got suspended. 6310 */ 6311 if (pAhciPort->fRedo) 6312 continue; 6313 6314 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n")); 6233 6315 } 6234 6235 if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING)) 6236 break; 6237 6238 AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n")); 6316 else 6317 fRedoDontWait = false; 6239 6318 6240 6319 ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false); 6241 6320 6242 /* 6243 * To maximize the throughput of the controller we try to minimize the 6244 * number of world switches during interrupts by grouping as many 6245 * I/O requests together as possible. 6246 * On the other side we want to get minimal latency if the I/O load is low. 6247 * Thatswhy the number of I/O requests per second is measured and if it is over 6248 * a threshold the thread waits for other requests from the guest. 6249 */ 6250 if (uIOsPerSec >= pAhci->cHighIOThreshold) 6251 { 6252 uint8_t uActWritePosPrev = pAhciPort->uActWritePos; 6253 6254 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__)); 6255 6256 do 6321 if (!pAhciPort->fRedo) 6322 { 6323 /* 6324 * To maximize the throughput of the controller we try to minimize the 6325 * number of world switches during interrupts by grouping as many 6326 * I/O requests together as possible. 6327 * On the other side we want to get minimal latency if the I/O load is low. 6328 * Thatswhy the number of I/O requests per second is measured and if it is over 6329 * a threshold the thread waits for other requests from the guest. 6330 */ 6331 if (uIOsPerSec >= pAhci->cHighIOThreshold) 6257 6332 { 6258 /* Sleep some time. */ 6259 RTThreadSleep(pAhci->cMillisToSleep); 6260 /* Check if we got some new requests inbetween. */ 6261 if (uActWritePosPrev != pAhciPort->uActWritePos) 6333 uint8_t uActWritePosPrev = pAhciPort->uActWritePos; 6334 6335 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__)); 6336 6337 do 6262 6338 { 6263 uActWritePosPrev = pAhciPort->uActWritePos; 6264 /* 6265 * Check if the queue is full. If that is the case 6266 * there is no point waiting another round. 6267 */ 6268 if ( ( (pAhciPort->uActReadPos < uActWritePosPrev) 6269 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS) 6270 || ( (pAhciPort->uActReadPos > uActWritePosPrev) 6271 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) ) 6339 /* Sleep some time. */ 6340 RTThreadSleep(pAhci->cMillisToSleep); 6341 /* Check if we got some new requests inbetween. */ 6342 if (uActWritePosPrev != pAhciPort->uActWritePos) 6272 6343 { 6273 Log(("%s: Queue full -> leaving\n", __FUNCTION__)); 6344 uActWritePosPrev = pAhciPort->uActWritePos; 6345 /* 6346 * Check if the queue is full. If that is the case 6347 * there is no point waiting another round. 6348 */ 6349 if ( ( (pAhciPort->uActReadPos < uActWritePosPrev) 6350 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS) 6351 || ( (pAhciPort->uActReadPos > uActWritePosPrev) 6352 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS) ) 6353 { 6354 Log(("%s: Queue full -> leaving\n", __FUNCTION__)); 6355 break; 6356 } 6357 Log(("%s: Another round\n", __FUNCTION__)); 6358 } 6359 else /* No change break out of the loop. */ 6360 { 6361 #ifdef DEBUG 6362 uint8_t uQueuedTasks; 6363 if (pAhciPort->uActReadPos < uActWritePosPrev) 6364 uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos; 6365 else 6366 uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev; 6367 6368 Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks)); 6369 #endif 6274 6370 break; 6275 6371 } 6276 Log(("%s: Another round\n", __FUNCTION__)); 6277 } 6278 else /* No change break out of the loop. */ 6279 { 6280 #ifdef DEBUG 6281 uint8_t uQueuedTasks; 6282 if (pAhciPort->uActReadPos < uActWritePosPrev) 6283 uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos; 6284 else 6285 uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev; 6286 6287 Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks)); 6288 #endif 6289 break; 6290 } 6291 } while (true); 6292 } 6372 } while (true); 6373 } 6374 6375 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0); 6376 6377 ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess)); 6378 } /* fRedo */ 6379 else 6380 pAhciPort->fRedo = false; 6293 6381 6294 6382 ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false); 6295 6296 uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);6297 6298 ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));6299 6383 6300 6384 /* Process commands. */ 6301 6385 while ( (cTasksToProcess > 0) 6386 && RT_LIKELY(!pAhciPort->fRedo) 6302 6387 && RT_LIKELY(!pAhciPort->fPortReset)) 6303 6388 { … … 6368 6453 if (RT_FAILURE(rc)) 6369 6454 { 6370 pAhciPortTaskState->uATARegError = ID_ERR; 6371 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR; 6455 if (!ahciIsRedoSetWarning(pAhciPort, rc)) 6456 { 6457 pAhciPortTaskState->uATARegError = ID_ERR; 6458 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR; 6459 } 6460 else 6461 { 6462 pAhciPort->fRedo = true; 6463 pAhciPort->cTasksToProcess = cTasksToProcess; 6464 } 6372 6465 } 6373 6466 else … … 6377 6470 } 6378 6471 6379 if (pAhciPortTaskState->fQueued) 6380 uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag); 6381 else 6472 if (!pAhciPort->fRedo) 6382 6473 { 6383 /* Task is not queued send D2H FIS */ 6384 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true); 6474 if (pAhciPortTaskState->fQueued) 6475 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag)); 6476 else 6477 { 6478 /* Task is not queued send D2H FIS */ 6479 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true); 6480 } 6385 6481 } 6386 6482 } … … 6468 6564 if (RT_FAILURE(rc)) 6469 6565 { 6470 pAhciPortTaskState->uATARegError = ID_ERR; 6471 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR; 6566 if (!ahciIsRedoSetWarning(pAhciPort, rc)) 6567 { 6568 pAhciPortTaskState->uATARegError = ID_ERR; 6569 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR; 6570 } 6571 else 6572 { 6573 pAhciPort->cTasksToProcess = cTasksToProcess; 6574 pAhciPort->fRedo = true; 6575 } 6472 6576 } 6473 6577 else … … 6476 6580 pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK; 6477 6581 } 6478 /* Write updated command header into memory of the guest. */ 6479 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, 6480 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr)); 6481 6482 if (pAhciPortTaskState->fQueued) 6483 uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag); 6484 else 6582 6583 if (!pAhciPort->fRedo) 6485 6584 { 6486 /* Task is not queued send D2H FIS */ 6487 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true); 6585 /* Write updated command header into memory of the guest. */ 6586 PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr, 6587 &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr)); 6588 6589 if (pAhciPortTaskState->fQueued) 6590 ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag)); 6591 else 6592 { 6593 /* Task is not queued send D2H FIS */ 6594 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true); 6595 } 6596 6597 uIORequestsProcessed++; 6488 6598 } 6489 6490 uIORequestsProcessed++;6491 6599 } 6492 6600 } … … 6500 6608 } 6501 6609 6610 if (!pAhciPort->fRedo) 6611 { 6502 6612 #ifdef DEBUG 6503 /* Be paranoid. */6504 memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));6505 memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);6506 pAhciPortTaskState->GCPhysCmdHdrAddr = 0;6507 pAhciPortTaskState->uOffset = 0;6508 pAhciPortTaskState->cbTransfer = 0;6509 /* Make the port number invalid making it easier to track down bugs. */6510 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;6613 /* Be paranoid. */ 6614 memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr)); 6615 memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE); 6616 pAhciPortTaskState->GCPhysCmdHdrAddr = 0; 6617 pAhciPortTaskState->uOffset = 0; 6618 pAhciPortTaskState->cbTransfer = 0; 6619 /* Make the port number invalid making it easier to track down bugs. */ 6620 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff; 6511 6621 #endif 6512 6622 6513 pAhciPort->uActReadPos++; 6514 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks); 6515 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos)); 6516 cTasksToProcess--; 6517 6518 /* If we encountered an error notify the guest and continue with the next task. */ 6519 if (RT_FAILURE(rc)) 6520 { 6521 if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset)) 6522 ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true); 6523 6524 uQueuedTasksFinished = 0; 6623 pAhciPort->uActReadPos++; 6624 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks); 6625 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos)); 6626 cTasksToProcess--; 6627 6628 /* If we encountered an error notify the guest and continue with the next task. */ 6629 if (RT_FAILURE(rc)) 6630 { 6631 if ( ASMAtomicReadU32(&pAhciPort->u32QueuedTasksFinished) != 0 6632 && RT_LIKELY(!pAhciPort->fPortReset)) 6633 ahciSendSDBFis(pAhciPort, 0, true); 6634 } 6635 else if (!cTasksToProcess) 6636 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0); 6525 6637 } 6526 else if (!cTasksToProcess)6527 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);6528 6638 } 6529 6639 6530 if ( uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))6531 ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);6532 6533 uQueuedTasksFinished = 0;6640 if ( ASMAtomicReadU32(&pAhciPort->u32QueuedTasksFinished) != 0 6641 && RT_LIKELY(!pAhciPort->fPortReset) 6642 && RT_LIKELY(!pAhciPort->fRedo)) 6643 ahciSendSDBFis(pAhciPort, 0, true); 6534 6644 6535 6645 u64StopTime = RTTimeMilliTS(); … … 6559 6669 RTMemFree(pAhciPortTaskState); 6560 6670 6561 ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));6562 return rc;6671 ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN)); 6672 return VINF_SUCCESS; 6563 6673 } 6564 6674 … … 6677 6787 fFinished = (pThisPort->uActTasksActive == 0); 6678 6788 else 6679 fFinished = ((pThisPort->uActTasksActive == 0 ) && (pThisPort->fAsyncIOThreadIdle));6789 fFinished = ((pThisPort->uActTasksActive == 0 || pThisPort->fRedo) && (pThisPort->fAsyncIOThreadIdle)); 6680 6790 if (!fFinished) 6681 6791 return false; … … 6978 7088 else if (pThis->ahciPort[i].fATAPI) 6979 7089 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true")); 7090 7091 if ( pThis->ahciPort[i].uActWritePos != pThis->ahciPort[i].uActReadPos 7092 && !pThis->ahciPort[i].fAsyncInterface) 7093 { 7094 /* 7095 * There are tasks pending. The VM was saved after a task failed 7096 * because of non-fatal error. Set the redo flag 7097 * and the correct cTasksToProcess number based on the difference 7098 * of the FIFO counters. 7099 */ 7100 PAHCIPort pAhciPort = &pThis->ahciPort[i]; 7101 7102 pAhciPort->fRedo = true; 7103 /* 7104 * Because we don't save the task FIFO we have to reconstruct it by using the 7105 * SACT and CI registers along with the shadowed variables containing the 7106 * completed tasks and placing them in the FIFO again. 7107 */ 7108 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished; 7109 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished; 7110 7111 pAhciPort->uActWritePos = 0; 7112 pAhciPort->uActReadPos = 0; 7113 7114 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++) 7115 { 7116 if ( fTasksOutstanding & (1 << uTag) 7117 || fQueuedTasksOutstanding & (1 << uTag)) 7118 { 7119 pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0); 7120 pAhciPort->uActWritePos++; 7121 pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks); 7122 pAhciPort->cTasksToProcess++; 7123 } 7124 } 7125 } 6980 7126 } 6981 7127
Note:
See TracChangeset
for help on using the changeset viewer.