Changeset 80383 in vbox for trunk/src/VBox
- Timestamp:
- Aug 22, 2019 7:25:38 AM (5 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r80340 r80383 27 27 #include <VBox/vmm/pdmcritsect.h> 28 28 #include <VBox/version.h> 29 #include <VBox/log.h> 29 30 #include <iprt/errcore.h> 30 #include <VBox/log.h>31 31 #include <iprt/assert.h> 32 32 #include <iprt/string.h> … … 36 36 # include <iprt/alloc.h> 37 37 # include <iprt/memcache.h> 38 # include <iprt/semaphore.h> 39 # include <iprt/sg.h> 38 40 # include <iprt/param.h> 39 41 # include <iprt/uuid.h> … … 66 68 #define VIRTIOSCSI_MAX_TARGETS 1 /**< Can probably determined from higher layers */ 67 69 #define VIRTIOSCSI_MAX_LUN 16383 /* < VirtIO specification, section 5.6.4 */ 68 #define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 64/* < T.B.D. What is a good value for this? */70 #define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 1 /* < T.B.D. What is a good value for this? */ 69 71 #define VIRTIOSCSI_MAX_SEG_COUNT 1024 /* < T.B.D. What is a good value for this? */ 70 72 #define VIRTIOSCSI_MAX_SECTORS_HINT 0x10000 /* < VirtIO specification, section 5.6.4 */ … … 89 91 #define EVENTQ_IDX 1 /**< Spec-defined Index of event queue */ 90 92 #define VIRTQ_REQ_BASE 2 /**< Spec-defined base index of request queues */ 91 #define QUEUENAME(qIdx) (pVirtioScsi->szQueueNames[qIdx]) /**< Macro to get queue name from its index */ 92 93 #define IS_REQ_QUEUE(qIdx) ( qIdx >= VIRTQ_REQ_BASE \ 94 && qIdx < VIRTIOSCSI_QUEUE_CNT) 95 /** 96 * The following struct is the VirtIO SCSI Host Device device-specific configuration described in section 5.6.4 93 #define QUEUENAME(qIdx) (pThis->szQueueNames[qIdx]) /**< Macro to get queue name from its index */ 94 95 #define IS_REQ_QUEUE(qIdx) (qIdx >= VIRTQ_REQ_BASE && qIdx < VIRTIOSCSI_QUEUE_CNT) 96 /** 97 * The following struct is the VirtIO SCSI Host Device device-specific configuration described in section 5.6.4 97 98 * of the VirtIO 1.0 specification. This layout maps an MMIO area shared VirtIO guest driver. The VBox VirtIO 98 99 * this virtual controller device implementation is a client of. The frame work calls back whenever the guest driver … … 111 112 uint16_t uMaxTarget; /**< max_target Hint to guest driver */ 112 113 uint32_t uMaxLun; /**< max_lun Hint to guest driver */ 113 } VIRTIO_SCSI_CONFIG_T, PVIRTIO_SCSI_CONFIG_T; 114 115 /** 116 * Device operation: controlq 117 */ 118 typedef struct virtio_scsi_ctrl 119 { 120 uint32_t type; /**< type */ 121 uint8_t response; /**< response */ 122 } VIRTIO_SCSI_CTRL_T, *PVIRTIO_SCSI_CTRL_T; 114 } VIRTIOSCSI_CONFIG_T, PVIRTIOSCSI_CONFIG_T; 115 123 116 124 117 /** … … 140 133 uint8_t uLUN[8]; /**< lun */ 141 134 uint32_t uReason; /**< reason */ 142 } VIRTIO _SCSI_EVENT_T, *PVIRTIO_SCSI_EVENT_T;135 } VIRTIOSCSI_EVENT_T, *PVIRTIOSCSI_EVENT_T; 143 136 144 137 /** … … 161 154 #define VIRTIOSCSI_DATA_OUT 512 /**< Value TBD (see section 5.6.6.1) */ 162 155 156 #pragma pack(1) 163 157 typedef struct virtio_scsi_req_cmd 164 158 { 165 159 /* Device-readable part */ 166 uint8_t uLUN[8]; /**< lun */ 167 uint64_t uId; /**< id */ 168 uint8_t uTaskAttr; /**< task_attr */ 169 uint8_t uPrio; /**< prio */ 170 uint8_t uCrn; /**< crn */ 171 uint8_t uCdb[VIRTIOSCSI_CDB_SIZE_DEFAULT]; /**< cdb VirtIO 1.0 mandates 32-bytes */ 172 173 /** Following three fields only present if VIRTIOSCSI_F_T10_PI negotiated */ 174 175 uint32_t uPiBytesOut; /**< pi_bytesout */ 176 uint32_t uPiBytesIn; /**< pi_bytesin */ 177 uint8_t uPiOut[VIRTIOSCSI_PI_BYTES_OUT]; /**< pi_out[] TBD */ 178 179 uint8_t uDataOut[VIRTIOSCSI_DATA_OUT]; /**< dataout */ 180 181 /* Device-writable part */ 182 uint32_t uSenseLen; /**< sense_len */ 183 uint32_t uResidual; /**< residual */ 184 uint16_t uStatusQualifier; /**< status_qualifier */ 185 uint8_t uStatus; /**< status */ 186 uint8_t uResponse; /**< response */ 187 uint8_t uSense[VIRTIOSCSI_SENSE_SIZE_DEFAULT]; /**< sense */ 188 189 /** Following two fields only present if VIRTIOSCSI_F_T10_PI negotiated */ 190 uint8_t uPiIn[VIRTIOSCSI_PI_BYTES_IN]; /**< pi_in[] */ 191 uint8_t uDataIn[]; /**< detain; */ 192 } VIRTIO_SCSI_REQ_CMD_T, *PVIRTIO_SCSI_REQ_CMD_T; 160 struct VIRTIOSCSI_REQ_CMD_HDR 161 { 162 uint8_t uLUN[8]; /**< lun */ 163 uint64_t uId; /**< id */ 164 uint8_t uTaskAttr; /**< task_attr */ 165 uint8_t uPrio; /**< prio */ 166 uint8_t uCrn; /**< crn */ 167 } cmdHdr; 168 uint8_t uCdb[1]; /**< cdb */ 169 170 /** T10 Pi (protection) fields only present if negotiated at VirtIO init */ 171 struct VIRTIOSCSI_REQ_CMD_PI 172 { 173 uint32_t uPiBytesOut; /**< pi_bytesout */ 174 uint32_t uPiBytesIn; /**< pi_bytesin */ 175 uint8_t uPiOut[1]; /**< pi_out[] TBD */ 176 } cmdPi; 177 178 uint8_t uDataOut[1]; /**< dataout */ 179 180 struct VIRTIOSCSI_REQ_RESP_HDR 181 { 182 uint32_t uSenseLen; /**< sense_len */ 183 uint32_t uResidual; /**< residual */ 184 uint16_t uStatusQualifier; /**< status_qualifier */ 185 uint8_t uStatus; /**< status */ 186 uint8_t uResponse; /**< response */ 187 uint8_t uSense[1]; /**< sense */ 188 } respHdr; 189 /** T10 Pi (protection) field only present if negotiated at VirtIO init */ 190 uint8_t uPiIn[1]; /**< pi_in[] */ 191 uint8_t uDataIn[1]; /**< detain; */ 192 } VIRTIOSCSI_REQ_CMD_T, *PVIRTIOSCSI_REQ_CMD_T; 193 #pragma pack() 193 194 194 195 /** … … 218 219 219 220 /** 221 * @name VirtIO 1.0 SCSI Host Device Control command before we know type (5.6.6.2) 222 * @{ */ 223 typedef struct virtio_scsi_ctrl 224 { 225 uint32_t uType; 226 } VIRTIOSCSI_CTRL, *PVIRTIOSCSI_CTRL_T; 227 228 /** 220 229 * @name VirtIO 1.0 SCSI Host Device command-specific TMF values 221 230 * @{ */ … … 231 240 /*** @} */ 232 241 242 #pragma pack(1) 233 243 typedef struct virtio_scsi_ctrl_tmf 234 244 { … … 240 250 // Device-writable part 241 251 uint8_t uResponse; /** response */ 242 } VIRTIO_SCSI_CTRL_BUF_T, *PVIRTIO_SCSI_CTRL_BUF_T; 252 } VIRTIOSCSI_CTRL_TMF_T, *PVIRTIOSCSI_CTRL_TMF_T; 253 #pragma pack(0) 243 254 244 255 /** … … 253 264 #define VIRTIOSCSI_T_AN_SUBSCRIBE 2 /** Asynchronous notification subscription */ 254 265 266 #pragma pack(1) 255 267 typedef struct virtio_scsi_ctrl_an 256 268 { … … 262 274 uint32_t uEventActual; /** event_actual */ 263 275 uint8_t uResponse; /** response */ 264 } VIRTIO_SCSI_CTRL_AN, *PVIRTIO_SCSI_CTRL_AN_T; 276 } VIRTIOSCSI_CTRL_AN, *PVIRTIOSCSI_CTRL_AN_T; 277 #pragma pack() 265 278 266 279 /** … … 275 288 /** @} */ 276 289 290 291 /** 292 * Worker thread context 293 */ 294 typedef struct WORKER 295 { 296 R3PTRTYPE(PPDMTHREAD) pThread; 297 SUPSEMEVENT hEvtProcess; 298 bool fSleeping; 299 bool fNotified; 300 } WORKER, *PWORKER; 301 277 302 /** 278 303 * State of a target attached to the VirtIO SCSI Host … … 281 306 { 282 307 /** Pointer to PCI device that owns this target instance. - R3 pointer */ 283 R3PTRTYPE(struct VIRTIOSCSI *) p VirtioScsiR3;308 R3PTRTYPE(struct VIRTIOSCSI *) pThisR3; 284 309 285 310 /** Pointer to attached driver's base interface. */ … … 320 345 } VIRTIOSCSITARGET, *PVIRTIOSCSITARGET; 321 346 322 323 347 /** 324 348 * PDM instance data (state) for VirtIO Host SCSI device … … 328 352 typedef struct VIRTIOSCSI 329 353 { 330 /* Opaque handle to VirtIO common framework (must be first item331 * in this struct so PDMINS_2_DATA macro's casting works) */354 /** Opaque handle to VirtIO common framework (must be first item 355 * in this struct so PDMINS_2_DATA macro's casting works) */ 332 356 VIRTIOHANDLE hVirtio; 333 357 334 /* SCSI target instances data */358 /** SCSI target instances data */ 335 359 VIRTIOSCSITARGET aTargetInstances[VIRTIOSCSI_MAX_TARGETS]; 336 360 361 /** Per device-bound virtq worker-thread contexts (eventq slot unused) */ 362 WORKER aWorker[VIRTIOSCSI_QUEUE_CNT]; 363 364 bool fBootable; 365 bool fRCEnabled; 366 bool fR0Enabled; 337 367 /** Instance name */ 338 368 const char szInstance[16]; … … 372 402 R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession; 373 403 374 /** Worker thread. */375 R3PTRTYPE(PPDMTHREAD) pThreadWrk;376 377 404 /** The event semaphore the processing thread waits on. */ 378 SUPSEMEVENT hEvtProcess;379 405 380 406 /** Number of ports detected */ … … 384 410 bool volatile fSignalIdle; 385 411 386 VIRTIO_SCSI_CONFIG_T virtioScsiConfig; 412 VIRTIOSCSI_CONFIG_T virtioScsiConfig; 413 bool fVirtioReady; 414 bool fHasT10pi; 415 bool fHasHotplug; 416 bool fHasInOutBufs; 417 bool fHasLunChange; 387 418 388 419 … … 422 453 */ 423 454 #define MATCH_SCSI_CONFIG(member) \ 424 (RT_SIZEOFMEMB(VIRTIO _SCSI_CONFIG_T, member) == 8 \425 && ( uOffset == RT_UOFFSETOF(VIRTIO _SCSI_CONFIG_T, member) \426 || uOffset == RT_UOFFSETOF(VIRTIO _SCSI_CONFIG_T, member) + sizeof(uint32_t)) \455 (RT_SIZEOFMEMB(VIRTIOSCSI_CONFIG_T, member) == 8 \ 456 && ( uOffset == RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member) \ 457 || uOffset == RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member) + sizeof(uint32_t)) \ 427 458 && cb == sizeof(uint32_t)) \ 428 || (uOffset == RT_UOFFSETOF(VIRTIO _SCSI_CONFIG_T, member) \429 && cb == RT_SIZEOFMEMB(VIRTIO _SCSI_CONFIG_T, member))459 || (uOffset == RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member) \ 460 && cb == RT_SIZEOFMEMB(VIRTIOSCSI_CONFIG_T, member)) 430 461 431 462 #define LOG_ACCESSOR(member) \ 432 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO _SCSI_CONFIG_T, member), \463 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIOSCSI_CONFIG_T, member), \ 433 464 pv, cb, uIntraOffset, fWrite, false, 0); 434 465 435 466 #define SCSI_CONFIG_ACCESSOR(member) \ 436 467 { \ 437 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO _SCSI_CONFIG_T, member); \468 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member); \ 438 469 if (fWrite) \ 439 memcpy(((char *)&p VirtioScsi->virtioScsiConfig.member) + uIntraOffset, (const char *)pv, cb); \470 memcpy(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset, (const char *)pv, cb); \ 440 471 else \ 441 memcpy((char *)pv, (const char *)(((char *)&p VirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \472 memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset), cb); \ 442 473 LOG_ACCESSOR(member); \ 443 474 } … … 445 476 #define SCSI_CONFIG_ACCESSOR_READONLY(member) \ 446 477 { \ 447 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO _SCSI_CONFIG_T, member); \478 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member); \ 448 479 if (fWrite) \ 449 480 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \ 450 481 else \ 451 482 { \ 452 memcpy((char *)pv, (const char *)(((char *)&p VirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \483 memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset), cb); \ 453 484 LOG_ACCESSOR(member); \ 454 485 } \ … … 479 510 #endif 480 511 481 482 483 static void virtioScsiHandleRequestq(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pszQueueName) 484 { 485 LogFunc(("\n")); 486 487 PVIRTQ_BUF_VECTOR_T pBufVec = virtioQueueGetBuffer(hVirtio, qIdx); 488 if (pBufVec == NULL) 489 { 490 Log(("\"%s\" not initialized\n", pszQueueName)); 491 return; 492 } 493 494 int rc = virtioQueueGet(hVirtio, qIdx, true); 495 if (rc == VERR_NOT_AVAILABLE) 496 { 497 Log2Func(("Request queue %s is empty\n", pszQueueName)); 498 return; 499 } 500 501 AssertReturnVoid(rc == VINF_SUCCESS); 502 503 Log2Func(("Read request queue, %d segs in, %d segs out\n", 504 pBufVec->cSegsIn, pBufVec->cSegsOut)); 505 } 506 507 static void virtioScsiHandleControlq(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pszQueueName) 508 { 509 510 LogFunc( ("\n")); 511 512 PVIRTQ_BUF_VECTOR_T pBufVec = virtioQueueGetBuffer(hVirtio, qIdx); 513 if (pBufVec == NULL) 514 { 515 Log(("\"%s\" not initialized\n", pszQueueName)); 516 return; 517 } 518 519 int rc = virtioQueueGet(hVirtio, qIdx, true); 520 if (rc == VERR_NOT_AVAILABLE) 521 { 522 Log2Func(("Control queue %s is empty\n", pszQueueName)); 523 return; 524 } 525 526 AssertReturnVoid(rc == VINF_SUCCESS); 527 528 Log2Func(("Read control queue, %d segs in, %d segs out\n", 529 pBufVec->cSegsIn, pBufVec->cSegsOut)); 530 } 531 532 static void virtioScsiHandleEventq(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pszQueueName) 533 { 534 LogFunc(("\n")); 535 536 PVIRTQ_BUF_VECTOR_T pBufVec = virtioQueueGetBuffer(hVirtio, qIdx); 537 if (pBufVec == NULL) 538 { 539 Log(("\"%s\" not initialized\n", pszQueueName)); 540 return; 541 } 542 543 int rc = virtioQueueGet(hVirtio, qIdx, true); 544 if (rc == VERR_NOT_AVAILABLE) 545 { 546 Log2Func(("Event queue %s is empty\n", pszQueueName)); 547 return; 548 } 549 550 AssertReturnVoid(rc == VINF_SUCCESS); 551 552 Log2Func(("Read event queue, %d segs in, %d segs out\n", 553 pBufVec->cSegsIn, pBufVec->cSegsOut)); 512 #if 0 513 */ 514 typedef struct virtio_scsi_config 515 { 516 uint32_t uNumQueues; /**< num_queues # of req q's exposed by dev */ 517 uint32_t uSegMax; /**< seg_max Max # of segs allowed in cmd */ 518 uint32_t uMaxSectors; /**< max_sectors Hint to guest max xfer to use */ 519 uint32_t uCmdPerLun; /**< cmd_per_lun Max # of link cmd sent per lun */ 520 uint32_t uEventInfoSize; /**< event_info_size Fill max, evtq bufs */ 521 uint32_t uSenseSize; /**< sense_size Max sense data size dev writes */ 522 uint32_t uCdbSize; /**< cdb_size Max CDB size driver writes */ 523 uint16_t uMaxChannel; /**< max_channel Hint to guest driver */ 524 uint16_t uMaxTarget; /**< max_target Hint to guest driver */ 525 uint32_t uMaxLun; /**< max_lun Hint to guest driver */ 526 } VIRTIOSCSI_CONFIG_T, PVIRTIOSCSI_CONFIG_T; 527 528 typedef struct virtio_scsi_req_cmd 529 { 530 /* Device-readable part */ 531 struct VIRTIOSCSI_REQ_CMD_HDR 532 { 533 uint8_t uLUN[8]; /**< lun */ 534 uint64_t uId; /**< id */ 535 uint8_t uTaskAttr; /**< task_attr */ 536 uint8_t uPrio; /**< prio */ 537 uint8_t uCrn; /**< crn */ 538 } cmdHdr; 539 uint8_t uCdb[1]; /**< cdb */ 540 541 /** T10 Pi (protection) fields only present if negotiated at VirtIO init */ 542 struct VIRTIOSCSI_REQ_CMD_PI 543 { 544 uint32_t uPiBytesOut; /**< pi_bytesout */ 545 uint32_t uPiBytesIn; /**< pi_bytesin */ 546 uint8_t uPiOut[1]; /**< pi_out[] TBD */ 547 } cmdPi; 548 549 uint8_t uDataOut[1]; /**< dataout */ 550 551 struct VIRTIOSCSI_REQ_RESP_HDR 552 { 553 uint32_t uSenseLen; /**< sense_len */ 554 uint32_t uResidual; /**< residual */ 555 uint16_t uStatusQualifier; /**< status_qualifier */ 556 uint8_t uStatus; /**< status */ 557 uint8_t uResponse; /**< response */ 558 } respHdr; 559 uint8_t uSense[1]; /**< sense */ 560 /** T10 Pi (protection) field only present if negotiated at VirtIO init */ 561 uint8_t uPiIn[1]; /**< pi_in[] */ 562 uint8_t uDataIn[1]; /**< detain; */ 563 } VIRTIOSCSI_REQ_CMD_T, *PVIRTIOSCSI_REQ_CMD_T; 564 pThis->fHasT10pi = features & VIRTIOSCSI_F_T10_PI; 565 pThis->fHasHotplug = features & VIRTIOSCSI_F_HOTPLUG; 566 pThis->fHasInOutBufs = features & VIRTIOSCSI_F_INOUT; 567 pThis->fHasLunChange = features & VIRTIOSCSI_F_CHANGE; 568 569 #endif 570 static int virtioScsiHandleReq(PVIRTIOSCSI pThis, uint16_t qIdx, PRTSGBUF pInSgBuf, PRTSGBUF pOutSgBuf) 571 { 572 RT_NOREF(pInSgBuf); 573 RT_NOREF(qIdx); 574 AssertMsgReturn(pOutSgBuf->cSegs, ("Req. has no OUT data, unexpected/TBD\n"), VERR_NOT_IMPLEMENTED); 575 576 size_t cbOut = RTSgBufCalcTotalLength(pOutSgBuf); 577 size_t cbCdb = pThis->virtioScsiConfig.uCdbSize; 578 size_t cbSense = pThis->virtioScsiConfig.uSenseSize; 579 size_t cbCmdHdr = RT_SIZEOFMEMB(VIRTIOSCSI_REQ_CMD_T, cmdHdr) + cbCdb; 580 size_t cbDataOut = cbOut - cbCmdHdr; 581 582 RT_NOREF(cbSense); 583 584 AssertMsgReturn(cbOut >= RT_SIZEOFMEMB(VIRTIOSCSI_REQ_CMD_T, cmdHdr), ("Req to short"), VERR_BUFFER_UNDERFLOW); 585 586 /** Actual CDB bytes didn't fill negotiated space allocated for it, adjust size */ 587 if (cbOut <= cbCmdHdr) 588 cbCdb -= (cbCmdHdr - cbOut); 589 590 /** 591 * For the time being, assume one descriptor chain has the complete req data to write to device, 592 * and that it's not too much to shove into virtual memory at once 593 */ 594 PVIRTIOSCSI_REQ_CMD_T pVirtqReq = (PVIRTIOSCSI_REQ_CMD_T)RTMemAllocZ(cbOut); 595 off_t cbOff = 0; 596 size_t cbSeg = 0; 597 size_t cbLeft = cbOut; 598 while (cbLeft) 599 { 600 RTGCPHYS pvSeg = (RTGCPHYS)RTSgBufGetNextSegment(pOutSgBuf, &cbSeg); 601 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pvSeg, pVirtqReq + cbOff, cbSeg); 602 cbLeft -= cbSeg; 603 cbOff += cbSeg; 604 } 605 606 LogFunc(("LUN: %.8Rhxs, id: %RX64, attr: %x, prio: %d, crn: %x\n", 607 pVirtqReq->cmdHdr.uLUN, pVirtqReq->cmdHdr.uId, pVirtqReq->cmdHdr.uTaskAttr, 608 pVirtqReq->cmdHdr.uPrio, pVirtqReq->cmdHdr.uCrn)); 609 LogFunc(("CDB: %.*Rhxs\n", cbCdb, &(pVirtqReq->uCdb))); 610 611 if (cbDataOut) 612 LogFunc(("dataout[]: %.*Rhxs\n", cbDataOut, pVirtqReq->uDataOut)); 613 else 614 LogFunc(("dataout[]: empty\n")); 615 616 PDMMEDIAEXIOREQ hIoReq = NULL; 617 RT_NOREF(hIoReq); 618 uint8_t uTarget = pVirtqReq->cmdHdr.uLUN[1]; 619 620 Assert(uTarget <= pThis->cTargets); 621 PPDMIMEDIAEX pMediaEx = pThis->aTargetInstances[uTarget].pDrvMediaEx; 622 RT_NOREF(pMediaEx); 623 // pMediaEx->pfnIoReqAlloc(pMediaX, &hIoReq, (void **) 624 // pThis->Lun0.pIMediaEx, &hIoReq, (void **)&pReq, 0 /* uTag */, PDMIMEDIAEX_F_DEFAULT); 625 626 // size_t cbRespHdr = RT_SIZEOFMEMB(VIRTIOSCSI_REQ_CMD_T, respHdr) + cbSense; 627 // size_t cbOut = RTSgBufCalcTotalLength(pOutSgBuf); 628 629 return VINF_SUCCESS; 630 } 631 632 633 static int virtioScsiHandleControlCmd(PVIRTIOSCSI pThis, uint16_t qIdx, PRTSGBUF pInSgBuf, PRTSGBUF pOutSgBuf) 634 { 635 RT_NOREF(pThis); 636 RT_NOREF(qIdx); 637 RT_NOREF(pInSgBuf); 638 639 Log2Func(("qidx=%d, %s\n", qIdx, QUEUENAME(qIdx))); 640 /** 641 * According to the VirtIO 1.0 SCSI Host device, spec, section 5.6.6.2, control packets are 642 * extremely small, so more than one segment is highly unlikely but not a bug. Get the 643 * the controlq sg buffer into virtual memory. */ 644 645 size_t cbOut = RTSgBufCalcTotalLength(pOutSgBuf); 646 647 PVIRTIOSCSI_CTRL_T pScsiCtrl = (PVIRTIOSCSI_CTRL_T)RTMemAllocZ(cbOut); 648 AssertMsgReturn(pScsiCtrl, ("Out of memory"), VERR_NO_MEMORY); 649 650 off_t cbOff = 0; 651 size_t cbSeg = 0; 652 while (cbOut) 653 { 654 RTGCPHYS pvSeg = (RTGCPHYS)RTSgBufGetNextSegment(pOutSgBuf, &cbSeg); 655 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pvSeg, pScsiCtrl + cbOff, cbSeg); 656 cbOut -= cbSeg; 657 cbOff += cbSeg; 658 } 659 660 switch(pScsiCtrl->uType) 661 { 662 case VIRTIOSCSI_T_TMF: 663 { 664 PVIRTIOSCSI_CTRL_TMF_T pScsiCtrlTmf = (PVIRTIOSCSI_CTRL_TMF_T)pScsiCtrl; 665 Log(("Task Mgt Function, LUN: %.8Rhxs ", pScsiCtrlTmf->uLUN)); 666 667 switch(pScsiCtrlTmf->uSubtype) 668 { 669 case VIRTIOSCSI_T_TMF_ABORT_TASK: 670 Log(("ABORT TASK\n")); 671 break; 672 case VIRTIOSCSI_T_TMF_ABORT_TASK_SET: 673 Log(("ABORT TASK SET\n")); 674 break; 675 case VIRTIOSCSI_T_TMF_CLEAR_ACA: 676 Log(("CLEAR ACA\n")); 677 break; 678 case VIRTIOSCSI_T_TMF_CLEAR_TASK_SET: 679 Log(("CLEAR TASK SET\n")); 680 break; 681 case VIRTIOSCSI_T_TMF_I_T_NEXUS_RESET: 682 Log(("I T NEXUS RESET\n")); 683 break; 684 case VIRTIOSCSI_T_TMF_LOGICAL_UNIT_RESET: 685 Log(("LOGICAL UNIT RESET\n")); 686 break; 687 case VIRTIOSCSI_T_TMF_QUERY_TASK: 688 Log(("QUERY TASK\n")); 689 break; 690 case VIRTIOSCSI_T_TMF_QUERY_TASK_SET: 691 Log(("QUERY TASK SET\n")); 692 break; 693 default: 694 Log(("<unknown>\n")); 695 break; 696 } 697 break; 698 } 699 case VIRTIOSCSI_T_AN_QUERY: 700 { 701 PVIRTIOSCSI_CTRL_AN_T pScsiCtrlAnQuery = (PVIRTIOSCSI_CTRL_AN_T)pScsiCtrl; 702 Log(("Async Query, LUN: %.8Rhxs ", pScsiCtrlAnQuery->uLUN)); 703 switch(pScsiCtrlAnQuery->uEventRequested) 704 { 705 case VIRTIOSCSI_EVT_ASYNC_OPERATIONAL_CHANGE: 706 Log(("OPERATIONAL CHANGE\n")); 707 break; 708 case VIRTIOSCSI_EVT_ASYNC_POWER_MGMT: 709 Log(("POWER MGMT\n")); 710 break; 711 case VIRTIOSCSI_EVT_ASYNC_EXTERNAL_REQUEST: 712 Log(("EXTERNAL REQUEST\n")); 713 break; 714 case VIRTIOSCSI_EVT_ASYNC_MEDIA_CHANGE: 715 Log(("MEDIA CHANGE\n")); 716 break; 717 case VIRTIOSCSI_EVT_ASYNC_MULTI_HOST: 718 Log(("MULTI HOST\n")); 719 break; 720 case VIRTIOSCSI_EVT_ASYNC_DEVICE_BUSY: 721 Log(("DEVICE BUSY\n")); 722 break; 723 default: 724 Log(("<unknown>\n")); 725 break; 726 } 727 break; 728 } 729 case VIRTIOSCSI_T_AN_SUBSCRIBE: 730 { 731 PVIRTIOSCSI_CTRL_AN_T pScsiCtrlAnSubscribe = (PVIRTIOSCSI_CTRL_AN_T)pScsiCtrl; 732 Log(("Async Subscribe, LUN %.8Rxhs ", pScsiCtrlAnSubscribe->uLUN)); 733 switch(pScsiCtrlAnSubscribe->uEventRequested) 734 { 735 case VIRTIOSCSI_EVT_ASYNC_OPERATIONAL_CHANGE: 736 Log(("OPERATIONAL CHANGE\n")); 737 break; 738 case VIRTIOSCSI_EVT_ASYNC_POWER_MGMT: 739 Log(("POWER MGMT\n")); 740 break; 741 case VIRTIOSCSI_EVT_ASYNC_EXTERNAL_REQUEST: 742 Log(("EXTERNAL REQUEST\n")); 743 break; 744 case VIRTIOSCSI_EVT_ASYNC_MEDIA_CHANGE: 745 Log(("MEDIA CHANGE\n")); 746 break; 747 case VIRTIOSCSI_EVT_ASYNC_MULTI_HOST: 748 Log(("MULTI HOST\n")); 749 break; 750 case VIRTIOSCSI_EVT_ASYNC_DEVICE_BUSY: 751 Log(("DEVICE BUSY\n")); 752 break; 753 default: 754 Log(("<unknown>\n")); 755 break; 756 } 757 break; 758 } 759 default: 760 Log(("Unknown control type extracted from %s: %d\n", QUEUENAME(qIdx), pScsiCtrl->uType)); 761 } 762 763 return VINF_SUCCESS; 764 } 765 766 /* 767 * Unblock the worker thread so it can respond to a state change. 768 * 769 * @returns VBox status code. 770 * @param pDevIns The pcnet device instance. 771 * @param pThread The send thread. 772 */ 773 static DECLCALLBACK(int) virtioScsiR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 774 { 775 RT_NOREF(pThread); 776 uint16_t qIdx = ((uint64_t)pThread->pvUser) & 0xffff; 777 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 778 return SUPSemEventSignal(pThis->pSupDrvSession, pThis->aWorker[qIdx].hEvtProcess); 779 } 780 781 static int virtioScsiWorkIncoming(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 782 { 783 int rc; 784 uint16_t qIdx = ((uint64_t)pThread->pvUser) & 0xffff; 785 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 786 PWORKER pWorker = &pThis->aWorker[qIdx]; 787 PRTSGBUF pInSgBuf; 788 PRTSGBUF pOutSgBuf; 789 790 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 791 return VINF_SUCCESS; 792 793 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 794 { 795 /** Interlocks avoid missing alarm while going to sleep & notifier doesn't wake the awoken */ 796 ASMAtomicWriteBool(&pWorker->fSleeping, true); 797 bool fNotificationSent = ASMAtomicXchgBool(&pWorker->fNotified, false); 798 if (!fNotificationSent) 799 { 800 Assert(ASMAtomicReadBool(&pWorker->fSleeping)); 801 rc = SUPSemEventWaitNoResume(pThis->pSupDrvSession, pWorker->hEvtProcess, RT_INDEFINITE_WAIT); 802 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc); 803 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 804 break; 805 Log3Func(("Woken-up\n")); 806 ASMAtomicWriteBool(&pWorker->fNotified, false); 807 } 808 ASMAtomicWriteBool(&pWorker->fSleeping, false); 809 810 Log2Func(("Fetching next descriptor chain\n")); 811 rc = virtioQueueGet(pThis->hVirtio, qIdx, true, &pInSgBuf, &pOutSgBuf); 812 if (rc == VERR_NOT_AVAILABLE) 813 { 814 Log2Func(("Nothing found in %s\n", QUEUENAME(qIdx))); 815 continue; 816 } 817 818 AssertRC(rc); 819 if (qIdx == CONTROLQ_IDX) 820 virtioScsiHandleControlCmd(pThis, qIdx, pInSgBuf, pOutSgBuf); 821 else 822 virtioScsiHandleReq(pThis, qIdx, pInSgBuf, pOutSgBuf); 823 } 824 return VINF_SUCCESS; 554 825 } 555 826 556 827 static DECLCALLBACK(void) virtioScsiQueueNotified(VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx) 557 828 { 829 RT_NOREF(hVirtio); 830 558 831 AssertReturnVoid(qIdx < VIRTIOSCSI_QUEUE_CNT); 559 PVIRTIOSCSI pVirtioScsi = (PVIRTIOSCSI)pClient; 560 561 if (!pVirtioScsi->fQueueAttached[qIdx]) 562 { 563 int rc = virtioQueueAttach(hVirtio, qIdx, QUEUENAME(qIdx)); 564 pVirtioScsi->fQueueAttached[qIdx] = (rc == VINF_SUCCESS); 565 AssertReturnVoid(pVirtioScsi->fQueueAttached); 566 } 832 PVIRTIOSCSI pThis = (PVIRTIOSCSI)pClient; 833 PWORKER pWorker = &pThis->aWorker[qIdx]; 567 834 568 835 Log2Func(("%s has available data\n", QUEUENAME(qIdx))); 569 570 if (qIdx == CONTROLQ_IDX) 571 virtioScsiHandleControlq(hVirtio, qIdx, QUEUENAME(qIdx)); 836 if (qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx)) 837 { 838 /** Wake queue's worker thread up if sleeping */ 839 if (!ASMAtomicXchgBool(&pWorker->fNotified, true)) 840 { 841 if (ASMAtomicReadBool(&pWorker->fSleeping)) 842 { 843 Log2Func(("Waking %s worker.\n", QUEUENAME(qIdx))); 844 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pWorker->hEvtProcess); 845 AssertRC(rc); 846 } 847 } 848 } 572 849 else 573 if (qIdx == EVENTQ_IDX) 574 virtioScsiHandleEventq(hVirtio, qIdx, QUEUENAME(qIdx)); 575 else 576 if (IS_REQ_QUEUE(qIdx)) 577 virtioScsiHandleRequestq(hVirtio, qIdx, QUEUENAME(qIdx)); 850 Log2Func(("%s has available data\n", QUEUENAME(qIdx))); 578 851 } 579 852 … … 582 855 Log2Func(("\n")); 583 856 RT_NOREF(hVirtio); 584 PVIRTIOSCSI pVirtioScsi = (PVIRTIOSCSI)pClient; 857 PVIRTIOSCSI pThis = (PVIRTIOSCSI)pClient; 858 pThis->fVirtioReady = fVirtioReady; 585 859 if (fVirtioReady) 860 { 586 861 Log2Func(("VirtIO ready\n")); 862 uint64_t features = virtioGetNegotiatedFeatures(hVirtio); 863 pThis->fHasT10pi = features & VIRTIOSCSI_F_T10_PI; 864 pThis->fHasHotplug = features & VIRTIOSCSI_F_HOTPLUG; 865 pThis->fHasInOutBufs = features & VIRTIOSCSI_F_INOUT; 866 pThis->fHasLunChange = features & VIRTIOSCSI_F_CHANGE; 867 } 587 868 else 588 869 { 589 870 Log2Func(("VirtIO is resetting\n")); 590 871 for (int i = 0; i < VIRTIOSCSI_QUEUE_CNT; i++) 591 pVirtioScsi->fQueueAttached[i] = false; 592 } 593 } 872 pThis->fQueueAttached[i] = false; 873 } 874 } 875 876 /*static void virtioScsiEventToClient(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 877 { } */ 878 594 879 595 880 /** 596 881 * Implementation invokes this to reset the VirtIO device 597 882 */ 598 static void virtioScsiDeviceReset(PVIRTIOSCSI p VirtioScsi)599 { 600 p VirtioScsi->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT;601 p VirtioScsi->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT;602 virtioResetAll(p VirtioScsi->hVirtio);603 } 604 605 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI p VirtioScsi, uint32_t uOffset,883 static void virtioScsiDeviceReset(PVIRTIOSCSI pThis) 884 { 885 pThis->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT; 886 pThis->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT; 887 virtioResetAll(pThis->hVirtio); 888 } 889 890 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pThis, uint32_t uOffset, 606 891 const void *pv, size_t cb, uint8_t fWrite) 607 892 { … … 676 961 { 677 962 int rc = VINF_SUCCESS; 678 PVIRTIOSCSI p VirtioScsi= PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);963 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 679 964 680 965 // LogFunc(("Read from Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n", 681 966 // uOffset, cb)); 682 967 683 rc = virtioScsiR3CfgAccessed(p VirtioScsi, uOffset, pv, cb, false);968 rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, false); 684 969 685 970 return rc; … … 698 983 { 699 984 int rc = VINF_SUCCESS; 700 PVIRTIOSCSI p VirtioScsi= PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);985 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 701 986 702 987 // LogFunc(("Write to Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n", 703 988 // uOffset, cb)); 704 989 705 rc = virtioScsiR3CfgAccessed(p VirtioScsi, uOffset, pv, cb, true);990 rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, true); 706 991 707 992 return rc; … … 810 1095 static DECLCALLBACK(void) virtioScsiR3PDMReset(PPDMDEVINS pDevIns) 811 1096 { 812 PVIRTIOSCSI p VirtioScsi= PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);813 virtioScsiDeviceReset(p VirtioScsi);1097 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1098 virtioScsiDeviceReset(pThis); 814 1099 815 1100 // ASMAtomicWriteBool(&pThis->fSignalIdle, true); … … 850 1135 { 851 1136 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[i]; 852 pTarget->p VirtioScsiR3 = pThis;;1137 pTarget->pThisR3 = pThis;; 853 1138 } 854 1139 … … 863 1148 uint32_t *piInstance, uint32_t *piLUN) 864 1149 { 865 PVIRTIOSCSITARGET p VirtioScsiTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaPort);866 PPDMDEVINS pDevIns = p VirtioScsiTarget->CTX_SUFF(pVirtioScsi)->CTX_SUFF(pDevIns);1150 PVIRTIOSCSITARGET pThisTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaPort); 1151 PPDMDEVINS pDevIns = pThisTarget->CTX_SUFF(pThis)->CTX_SUFF(pDevIns); 867 1152 868 1153 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER); … … 872 1157 *ppcszController = pDevIns->pReg->szName; 873 1158 *piInstance = pDevIns->iInstance; 874 *piLUN = p VirtioScsiTarget->iLUN;1159 *piLUN = pThisTarget->iLUN; 875 1160 876 1161 return VINF_SUCCESS; … … 899 1184 /* 900 1185 if (RT_UNLIKELY(pReq->fBIOS)) 901 cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(p VirtioScsi)->VBoxSCSI, pSgBuf, offDst, cbCopy);1186 cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(pThis)->VBoxSCSI, pSgBuf, offDst, cbCopy); 902 1187 else 903 cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(p VirtioScsi), pReq, pSgBuf, offDst, cbCopy);1188 cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(pThis), pReq, pSgBuf, offDst, cbCopy); 904 1189 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW; 905 1190 */ … … 929 1214 /* 930 1215 if (RT_UNLIKELY(pReq->fBIOS)) 931 cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(p VirtioScsi)->VBoxSCSI, pSgBuf, offSrc, cbCopy);1216 cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(pThis)->VBoxSCSI, pSgBuf, offSrc, cbCopy); 932 1217 else 933 cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(p VirtioScsi), pReq, pSgBuf, offSrc, cbCopy);1218 cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(pThis), pReq, pSgBuf, offSrc, cbCopy); 934 1219 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN; 935 1220 */ … … 950 1235 RT_NOREF(rcReq); 951 1236 RT_NOREF(hIoReq); 952 // virtioScsiR3ReqComplete(pTarget->CTX_SUFF(p VirtioScsi), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq);1237 // virtioScsiR3ReqComplete(pTarget->CTX_SUFF(pThis), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq); 953 1238 return VINF_SUCCESS; 954 1239 } … … 970 1255 /* Make sure the request is not accounted for so the VM can suspend successfully. */ 971 1256 uint32_t cTasksActive = ASMAtomicDecU32(&pTarget->cOutstandingRequests); 972 if (!cTasksActive && pTarget->CTX_SUFF(p VirtioScsi)->fSignalIdle)973 PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(p VirtioScsi)->pDevInsR3);1257 if (!cTasksActive && pTarget->CTX_SUFF(pThis)->fSignalIdle) 1258 PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(pThis)->pDevInsR3); 974 1259 break; 975 1260 } … … 989 1274 { 990 1275 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort); 991 PVIRTIOSCSI pThis = pTarget->CTX_SUFF(p VirtioScsi);1276 PVIRTIOSCSI pThis = pTarget->CTX_SUFF(pThis); 992 1277 993 1278 if (pThis->pMediaNotify) … … 995 1280 } 996 1281 997 /**998 * Transmit queue consumer999 * Queue a new async task.1000 *1001 * @returns Success indicator.1002 * If false the item will not be removed and the flushing will stop.1003 * @param pDevIns The device instance.1004 * @param pItem The item to consume. Upon return this item will be freed.1005 */1006 static DECLCALLBACK(bool) virtioScsiR3NotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)1007 {1008 RT_NOREF(pItem);1009 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);1010 1011 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess);1012 AssertRC(rc);1013 1014 return true;1015 }1016 1282 1017 1283 … … 1145 1411 static DECLCALLBACK(void *) virtioScsiR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID) 1146 1412 { 1147 PVIRTIOSCSI p VirtioScsi= RT_FROM_MEMBER(pInterface, VIRTIOSCSI, IBase);1148 1149 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &p VirtioScsi->IBase);1150 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &p VirtioScsi->ILeds);1413 PVIRTIOSCSI pThis = RT_FROM_MEMBER(pInterface, VIRTIOSCSI, IBase); 1414 1415 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase); 1416 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds); 1151 1417 1152 1418 return NULL; … … 1233 1499 * Check the versions here as well since the destructor is *always* called. 1234 1500 */ 1501 1235 1502 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 1236 return VINF_SUCCESS; 1503 1504 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1505 1506 for (int qIdx = 0; qIdx < VIRTQ_MAX_CNT; qIdx++) 1507 { 1508 PWORKER pWorker = &pThis->aWorker[qIdx]; 1509 if (pWorker->hEvtProcess != NIL_SUPSEMEVENT) 1510 { 1511 SUPSemEventClose(pThis->pSupDrvSession, pWorker->hEvtProcess); 1512 pWorker->hEvtProcess = NIL_SUPSEMEVENT; 1513 } 1514 } 1515 return VINF_SUCCESS; 1237 1516 } 1238 1517 … … 1243 1522 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1244 1523 int rc = VINF_SUCCESS; 1245 bool fBootable = false;1246 1524 1247 1525 pThis->pDevInsR3 = pDevIns; 1248 1526 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 1249 1527 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1528 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns); 1250 1529 1251 1530 LogFunc(("PDM device instance: %d\n", iInstance)); … … 1269 1548 LogFunc(("NumTargets=%d\n", pThis->cTargets)); 1270 1549 1271 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", & fBootable, true);1550 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true); 1272 1551 if (RT_FAILURE(rc)) 1273 1552 return PDMDEV_SET_ERROR(pDevIns, rc, 1274 1553 N_("virtio-scsi configuration error: failed to read Bootable as boolean")); 1275 LogFunc(("Bootable=%RTbool (unimplemented)\n", fBootable)); 1554 LogFunc(("Bootable=%RTbool (unimplemented)\n", pThis->fBootable)); 1555 1556 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false); 1557 if (RT_FAILURE(rc)) 1558 return PDMDEV_SET_ERROR(pDevIns, rc, 1559 N_("virtio-scsi configuration error: failed to read R0Enabled as boolean")); 1560 1561 rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &pThis->fRCEnabled, false); 1562 if (RT_FAILURE(rc)) 1563 return PDMDEV_SET_ERROR(pDevIns, rc, 1564 N_("virtio-scsi configuration error: failed to read RCEnabled as boolean")); 1276 1565 1277 1566 VIRTIOPCIPARAMS virtioPciParams, *pVirtioPciParams = &virtioPciParams; … … 1291 1580 pThis->virtioScsiConfig.uMaxSectors = VIRTIOSCSI_MAX_SECTORS_HINT; 1292 1581 pThis->virtioScsiConfig.uCmdPerLun = VIRTIOSCSI_MAX_COMMANDS_PER_LUN; 1293 pThis->virtioScsiConfig.uEventInfoSize = sizeof(VIRTIO _SCSI_EVENT_T); /* Spec says at least this size! */1582 pThis->virtioScsiConfig.uEventInfoSize = sizeof(VIRTIOSCSI_EVENT_T); /* Spec says at least this size! */ 1294 1583 pThis->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT; 1295 1584 pThis->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT; … … 1308 1597 virtioScsiR3LoadExec, 1309 1598 virtioScsiR3LoadDone, 1310 sizeof(VIRTIO _SCSI_CONFIG_T) /* cbDevSpecificCap */,1599 sizeof(VIRTIOSCSI_CONFIG_T) /* cbDevSpecificCap */, 1311 1600 (void *)&pThis->virtioScsiConfig /* pDevSpecificCap */); 1312 1601 … … 1314 1603 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO")); 1315 1604 1605 1316 1606 RTStrCopy((char *)pThis->szQueueNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq"); 1317 1607 RTStrCopy((char *)pThis->szQueueNames[EVENTQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "eventq"); 1318 for (uint32_t qIdx = VIRTQ_REQ_BASE; qIdx < VIRTQ_REQ_BASE + VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++) 1319 RTStrPrintf((char *)pThis->szQueueNames[qIdx], VIRTIO_MAX_QUEUE_NAME_SIZE, "requestq_%d", qIdx); 1608 for (uint16_t qIdx = VIRTQ_REQ_BASE; qIdx < VIRTQ_REQ_BASE + VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++) 1609 RTStrPrintf((char *)pThis->szQueueNames[qIdx], VIRTIO_MAX_QUEUE_NAME_SIZE, 1610 "requestq_%d", qIdx - VIRTQ_REQ_BASE); 1611 1612 /** 1613 * Create one worker per incoming-work-related queue (eventq is outgoing status to guest, 1614 * wherein guest is supposed to keep the queue loaded-up with buffer vectors the host 1615 * can quickly fill-in send back. Should be light-duty and fast enough to be handled on 1616 * requestq or controlq thread. The Linux virtio_scsi driver limits the number of request 1617 * queues to MIN(<# Guest CPUs>, <Device's req queue max>), so queue count is ultimately 1618 * constrained from host side at negotiation time and initialization and later through 1619 * bounds-checking. 1620 */ 1621 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++) 1622 { 1623 rc = virtioQueueAttach(pThis->hVirtio, qIdx, QUEUENAME(qIdx)); 1624 AssertMsgReturn(rc == VINF_SUCCESS, ("Failed to attach queue %s\n", QUEUENAME(qIdx)), rc); 1625 pThis->fQueueAttached[qIdx] = (rc == VINF_SUCCESS); 1626 1627 if (qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx)) 1628 { 1629 rc = PDMDevHlpThreadCreate(pDevIns, &pThis->aWorker[qIdx].pThread, 1630 (void *)(uint64_t)qIdx, virtioScsiWorkIncoming, 1631 virtioScsiR3WorkerWakeUp, 0, RTTHREADTYPE_IO, QUEUENAME(qIdx)); 1632 if (rc != VINF_SUCCESS) 1633 { 1634 LogRel(("Error creating thread for Virtual Queue %s\n", QUEUENAME(qIdx))); 1635 return rc; 1636 } 1637 1638 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->aWorker[qIdx].hEvtProcess); 1639 if (RT_FAILURE(rc)) 1640 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 1641 N_("LsiLogic: Failed to create SUP event semaphore")); 1642 } 1643 } 1320 1644 1321 1645 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_MEM_IO, 32, … … 1337 1661 #endif 1338 1662 1339 /* Initialize task queue. */1340 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 5, 0,1341 virtioScsiR3NotifyQueueConsumer, true, "VirtioTask", &pThis->pNotifierQueueR3);1342 if (RT_FAILURE(rc))1343 return rc;1344 1345 1663 /* Initialize per device instance. */ 1346 1664 for (RTUINT iLUN = 0; iLUN < VIRTIOSCSI_MAX_TARGETS; iLUN++) … … 1353 1671 /* Initialize static parts of the device. */ 1354 1672 pTarget->iLUN = iLUN; 1355 pTarget->p VirtioScsiR3 = pThis;1673 pTarget->pThisR3 = pThis; 1356 1674 1357 1675 pTarget->IBase.pfnQueryInterface = virtioScsiR3TargetQueryInterface; … … 1412 1730 } 1413 1731 } 1414 1415 /* rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIOSCSI_SAVED_STATE_MINOR_VERSION, sizeof(*pThis), NULL,1416 NULL, virtioScsiR3LiveExec, NULL,1417 NULL, virtioScsiR3SaveExec, NULL,1418 NULL, virtioScsiR3LoadExec, virtioScsiR3LoadDone);1419 if (RT_FAILURE(rc))1420 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi cannot register save state handlers"));1421 */1422 1732 1423 1733 /* Status driver */ -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r80340 r80383 28 28 #include <iprt/mem.h> 29 29 #include <iprt/assert.h> 30 #include <iprt/sg.h> 30 31 #include <VBox/vmm/pdmdev.h> 31 32 #include "Virtio_1_0_impl.h" … … 35 36 36 37 #ifdef LOG_ENABLED 37 # define QUEUENAME(s, q) (q->sz Name)38 # define QUEUENAME(s, q) (q->szVirtqName) 38 39 #endif 39 40 … … 93 94 } 94 95 96 /** 97 * See API comments in header file for description 98 */ 95 99 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName) 96 100 { … … 98 102 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 99 103 PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]); 100 if (pVirtio->uQueueEnable[qIdx]) 101 { 102 pVirtqProxy->pBufVec = (PVIRTQ_BUF_VECTOR_T)RTMemAllocZ(sizeof(PVIRTQ_BUF_VECTOR_T)); 103 if (!pVirtqProxy->pBufVec) 104 { 105 Log(("Out of memory!")); 106 return VERR_NO_MEMORY; 107 } 108 pVirtqProxy->uAvailIdx = 0; 109 pVirtqProxy->uUsedIdx = 0; 110 pVirtqProxy->fEventThresholdReached = false; 111 RTStrCopy((char *)pVirtqProxy->szName, sizeof(pVirtqProxy->szName), pcszName); 112 return VINF_SUCCESS; 113 } 114 LogFunc(("Couldn't attach to %s: Not enabled\n", pcszName)); 115 return VERR_INVALID_STATE; 116 } 117 118 PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx) 119 { 120 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 121 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 122 { 123 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 124 return pVirtqProxy->pBufVec; 125 } 126 LogFunc(("Can't get buffer, driver not ready\n")); 127 return NULL; 128 } 129 104 pVirtqProxy->pDescChain = (PVIRTQ_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTQ_DESC_CHAIN_T)); 105 if (!pVirtqProxy->pDescChain) 106 { 107 Log(("Out of memory!")); 108 return VERR_NO_MEMORY; 109 } 110 pVirtqProxy->uAvailIdx = 0; 111 pVirtqProxy->uUsedIdx = 0; 112 pVirtqProxy->fEventThresholdReached = false; 113 RTStrCopy((char *)pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName), pcszName); 114 return VINF_SUCCESS; 115 116 } 117 118 /** 119 * See API comments in header file for description 120 */ 130 121 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx) 131 122 { … … 134 125 ("Guest driver not in ready state.\n"), "<null>"); 135 126 136 return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szName; 137 } 138 127 return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szVirtqName; 128 } 129 130 /** 131 * See API comments in header file for description 132 */ 139 133 int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx) 140 134 { … … 150 144 return VERR_NOT_AVAILABLE; 151 145 152 Log2Func(("%s: %s avail_idx=%u\n", INSTANCE(pVirtio), 153 pVirtqProxy->szName, pVirtqProxy->uAvailIdx)); 146 Log2Func(("%s avail_idx=%u\n", pVirtqProxy->szVirtqName, pVirtqProxy->uAvailIdx)); 154 147 pVirtqProxy->uAvailIdx++; 155 148 … … 157 150 } 158 151 152 153 /** 154 * See API comments in header file for description 155 */ 156 uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio) 157 { 158 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 159 return pVirtio->uDriverFeatures; 160 } 161 162 163 /** 164 * See API comments in header file for description 165 */ 159 166 bool virtioQueueIsEmpty(VIRTIOHANDLE hVirtio, uint16_t qIdx) 160 167 { … … 163 170 } 164 171 165 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx) 166 { 167 return virtioQueueGet(hVirtio, qIdx, false /* fRemove */); 168 } 169 170 /** See API comments in header file prototype for description */ 171 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove) 172 /** 173 * See API comments in header file for description 174 */ 175 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs) 176 { 177 return virtioQueueGet(hVirtio, qIdx, false /* fRemove */, ppInSegs, ppOutSegs); 178 } 179 180 /*/** 181 * See API comments in header file for description 182 */ 183 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, 184 PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs) 172 185 { 173 186 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 174 187 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 175 PVIRTQ_ BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;188 PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain; 176 189 177 190 AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], … … 181 194 return VERR_NOT_AVAILABLE; 182 195 183 pBufVec->cSegsIn = pBufVec->cSegsOut = 0; 184 185 Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtqProxy->szName, pVirtqProxy->uAvailIdx)); 186 187 uint16_t uDescIdx; 188 // pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx); 196 pDescChain->cSegsIn = pDescChain->cSegsOut = 0; 197 198 199 pDescChain->uHeadIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx); 200 uint16_t uDescIdx = pDescChain->uHeadIdx; 201 202 Log2Func(("%s DESC CHAIN: (head) desc_idx=%u [avail_idx=%u]\n", 203 pVirtqProxy->szVirtqName, pDescChain->uHeadIdx, pVirtqProxy->uAvailIdx)); 189 204 190 205 if (fRemove) … … 194 209 do 195 210 { 196 VIRTQ_SEG_T*pSeg;211 RTSGSEG *pSeg; 197 212 198 213 /** … … 202 217 * the following aborts I/O if breach and employs a simple log throttling algorithm to notify. 203 218 */ 204 if (p BufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE)219 if (pDescChain->cSegsIn + pDescChain->cSegsOut >= VIRTQ_MAX_SIZE) 205 220 { 206 221 static volatile uint32_t s_cMessages = 0; … … 208 223 if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold)) 209 224 { 210 LogRel(("%s: too many linked descriptors; " 211 "check if the guest arranges descriptors in a loop.\n", 212 INSTANCE(pVirtio))); 225 LogRel(("too many linked descriptors; " 226 "check if the guest arranges descriptors in a loop.\n")); 213 227 if (ASMAtomicReadU32(&s_cMessages) != 1) 214 LogRel((" %s:(the above error has occured %u times so far)\n",215 INSTANCE(pVirtio),ASMAtomicReadU32(&s_cMessages)));228 LogRel(("(the above error has occured %u times so far)\n", 229 ASMAtomicReadU32(&s_cMessages))); 216 230 ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10); 217 231 } … … 220 234 RT_UNTRUSTED_VALIDATED_FENCE(); 221 235 222 // vqReadDesc(pVirtio, qIdx, uDescIdx, &desc); 236 vqReadDesc(pVirtio, qIdx, uDescIdx, &desc); 237 223 238 if (desc.fFlags & VIRTQ_DESC_F_WRITE) 224 239 { 225 Log2Func(("%s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio), 226 pVirtqProxy->szName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb)); 227 pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]); 240 Log2Func(("%*s IN desc_idx=%u seg=%u addr=%RGp cb=%u\n", 241 RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "", 242 uDescIdx, pDescChain->cSegsIn, desc.pGcPhysBuf, desc.cb)); 243 244 pSeg = &(pDescChain->aSegsIn[pDescChain->cSegsIn++]); 228 245 } 229 246 else 230 247 { 231 Log2Func(("% s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),232 pVirtqProxy->szName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));233 pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]);234 }235 236 pSeg->addr = (RTGCPHYS)desc.pGcPhysBuf; 237 pSeg-> cb = desc.cb;238 pSeg-> pv = NULL;248 Log2Func(("%*s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", 249 RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "", 250 uDescIdx, pDescChain->cSegsOut, desc.pGcPhysBuf, desc.cb)); 251 pSeg = &(pDescChain->aSegsOut[pDescChain->cSegsOut++]); 252 } 253 254 pSeg->pvSeg = (void *)desc.pGcPhysBuf; 255 pSeg->cbSeg = desc.cb; 239 256 240 257 uDescIdx = desc.uDescIdxNext; 241 258 } while (desc.fFlags & VIRTQ_DESC_F_NEXT); 242 259 243 Log2Func(("%s: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pVirtio), 244 pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut)); 260 RTSgBufInit(&pVirtqProxy->inSgBuf, (PCRTSGSEG)&pDescChain->aSegsIn, pDescChain->cSegsIn); 261 RTSgBufInit(&pVirtqProxy->outSgBuf,(PCRTSGSEG)&pDescChain->aSegsOut, pDescChain->cSegsOut); 262 263 *ppInSegs = &pVirtqProxy->inSgBuf; 264 *ppOutSegs = &pVirtqProxy->outSgBuf; 265 266 Log2Func(("%*s -- segs out: %u, segs in: %u --\n", 267 RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "", 268 pDescChain->cSegsOut, pDescChain->cSegsIn)); 245 269 246 270 return VINF_SUCCESS; … … 254 278 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 255 279 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 256 PVIRTQ_ BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;280 PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain; 257 281 258 282 AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], 259 283 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 260 284 261 Log2Func(("%s : %sdesc_idx=%u acb=%u\n",262 INSTANCE(pVirtio), pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn));263 264 uint32_t cbRemaining = p BufVec->cSegsIn;265 266 for (uint32_t iSeg = 0; iSeg < p BufVec->cSegsIn && cbRemaining > 0; ++iSeg)267 { 268 uint32_t cbSegLen = p BufVec->aSegsIn[iSeg].cb;285 Log2Func(("%s desc_idx=%u acb=%u\n", 286 pVirtqProxy->szVirtqName, pDescChain->uHeadIdx, pDescChain->cSegsIn)); 287 288 uint32_t cbRemaining = pDescChain->cSegsIn; 289 290 for (uint32_t iSeg = 0; iSeg < pDescChain->cSegsIn && cbRemaining > 0; ++iSeg) 291 { 292 uint32_t cbSegLen = pDescChain->aSegsIn[iSeg].cbSeg; 269 293 if (cbSegLen > cbRemaining) // last segment only partially used? 270 294 cbSegLen = cbRemaining; 271 295 272 273 if (pBufVec->aSegsIn[iSeg].pv != NULL) 274 { 275 Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", 276 INSTANCE(pVirtio), pVirtqProxy->szName, 277 pVirtqProxy->uUsedIdx, iSeg, 278 (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, 279 pBufVec->aSegsIn[iSeg].cb, cbSegLen)); 280 281 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 282 pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, cbSegLen); 283 } 296 // if (pDescChain->aSegsIn[iSeg].pv != NULL) 297 // { 298 // Log2Func(("%s used_idx=%u seg=%u addr=%p cb=%u acb=%u\n", 299 // pVirtqProxy->szVirtqName, 300 // pVirtqProxy->uUsedIdx, iSeg, 301 // (void *)pDescChain->aSegsIn[iSeg].addr, 302 // pDescChain->aSegsIn[iSeg].cbSeg, cbSegLen)); 303 // 304 // PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 305 // pDescChain->aSegsIn[iSeg].pvSeg, pDescChain->aSegsIn[iSeg].pv, cbSegLen); 306 // } 284 307 cbRemaining -= cbSegLen; 285 308 } 286 309 287 310 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 288 Log2Func(("%s : %sused_idx=%u guest_used_idx=%u id=%u len=%u\n",289 INSTANCE(pVirtio), pVirtqProxy->szName,290 pVirtqProxy->uUsedIdx, uDescIdx, p BufVec->uDescIdx, pBufVec->cSegsIn));311 Log2Func(("%s used_idx=%u guest_used_idx=%u id=%u len=%u\n", 312 pVirtqProxy->szVirtqName, 313 pVirtqProxy->uUsedIdx, uDescIdx, pDescChain->uHeadIdx, pDescChain->cSegsIn)); 291 314 292 315 if (pVirtqProxy->uUsedIdx == vqReadAvailUsedEvent(pVirtio, qIdx)) 293 316 pVirtqProxy->fEventThresholdReached = true; 294 vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, p BufVec->uDescIdx, pBufVec->cSegsIn);317 vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pDescChain->uHeadIdx, pDescChain->cSegsIn); 295 318 296 319 return VINF_SUCCESS; 297 320 } 298 321 299 /** See API comments in header file prototype for description */ 322 /** 323 * See API comments in header file for description 324 */ 300 325 int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx) 301 326 { … … 309 334 310 335 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 311 Log2Func(("%s : %sold_used_idx=%u new_used_idx=%u\n",312 INSTANCE(pVirtio),uDescIdx, pVirtqProxy->uUsedIdx));336 Log2Func(("%s old_used_idx=%u new_used_idx=%u\n", 337 uDescIdx, pVirtqProxy->uUsedIdx)); 313 338 314 339 vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx); … … 318 343 } 319 344 320 /** See API comments in header file prototype for description */ 345 /** 346 * See API comments in header file for description 347 */ 321 348 static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx) 322 349 { … … 324 351 325 352 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 326 Log2Func(("%s : %s notified\n", INSTANCE(pVirtio), pVirtqProxy->szName));353 Log2Func(("%s\n", pVirtqProxy->szVirtqName)); 327 354 328 355 /** Inform client */ … … 343 370 ("Guest driver not in ready state.\n")); 344 371 345 LogFlowFunc(("%s : %savailFlags=%x guestFeatures=%x virtioQueue is %sempty\n",346 INSTANCE(pVirtio), pVirtqProxy->szName, vqReadAvailFlags(pVirtio, qIdx),372 LogFlowFunc(("%s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n", 373 pVirtqProxy->szVirtqName, vqReadAvailFlags(pVirtio, qIdx), 347 374 pVirtio->uDriverFeatures, vqIsEmpty(pVirtio, qIdx) ? "" : "not ")); 348 375 … … 390 417 RT_NOREF(offDelta); 391 418 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 392 LogFunc((" %s\n", INSTANCE(pVirtio)));419 LogFunc(("\n")); 393 420 394 421 pVirtio->pDevInsR3 = pDevIns; … … 406 433 { 407 434 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT) 408 LogFlowFunc((" %s: Cause: queue interrupt\n", INSTANCE(pVirtio)));435 LogFlowFunc(("Cause: queue interrupt\n")); 409 436 else 410 437 if (uCause == VIRTIO_ISR_DEVICE_CONFIG) 411 LogFlowFunc((" %s: Cause: device config\n", INSTANCE(pVirtio)));438 LogFlowFunc(("Cause: device config\n")); 412 439 413 440 pVirtio->uISR |= uCause; … … 423 450 static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio) 424 451 { 425 LogFlowFunc((" %s\n", INSTANCE(pVirtio)));452 LogFlowFunc(("\n")); 426 453 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0); 427 454 } … … 713 740 { 714 741 ++pVirtio->uConfigGeneration; 715 Log2Func(("Bumped cfg. generation to %d because %s 742 Log2Func(("Bumped cfg. generation to %d because %s%s\n", 716 743 pVirtio->uConfigGeneration, 717 744 fDevSpecificFieldChanged ? "<dev cfg changed> " : "", … … 1024 1051 pVirtio->pDevSpecificCfg = pDevSpecificCfg; 1025 1052 1026 pVirtio->pPrevDevSpecificCfg = RTMemAlloc (cbDevSpecificCfg);1053 pVirtio->pPrevDevSpecificCfg = RTMemAllocZ(cbDevSpecificCfg); 1027 1054 if (!pVirtio->pPrevDevSpecificCfg) 1028 1055 { … … 1131 1158 * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram 1132 1159 * of spec shows it as a 32-bit field with upper bits 'reserved' 1133 * Will take spec words very literally for now and check linux driver.1160 * Will take spec words more literally than the diagram for now. 1134 1161 */ 1135 1162 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; … … 1201 1228 * out size, so pad with an extra page */ 1202 1229 1203 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + 4096, 4096),1230 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + 0x1000, 0x1000), 1204 1231 PCI_ADDRESS_SPACE_MEM, virtioR3Map); 1205 1232 if (RT_FAILURE(rc)) … … 1253 1280 { 1254 1281 Log2Func(("%s queue:\n", 1255 " virtqProxy[%u].uAvailIdx = %u\n virtqProxy[%u].uUsedIdx = %u\n"1282 " virtqProxy[%u].uAvailIdx = %u\n virtqProxy[%u].uUsedIdx = %u\n" 1256 1283 " uQueueSize[%u] = %u\n uQueueNotifyOff[%u] = %04x\n" 1257 1284 " uQueueMsixVector[%u] = %04x\n uQueueEnable[%u] = %04x\n" 1258 1285 " pGcPhysQueueDesc[%u] = %RGp\n pGcPhysQueueAvail[%u] = %RGp\n" 1259 1286 " pGcPhysQueueUsed[%u] = %RGp\n", 1260 i, pVirtio->virtqProxy[i].sz Name, i, pVirtio->virtqProxy[i].uAvailIdx,1287 i, pVirtio->virtqProxy[i].szVirtqName, i, pVirtio->virtqProxy[i].uAvailIdx, 1261 1288 i, pVirtio->virtqProxy[i].uUsedIdx, i, pVirtio->uQueueSize[i], 1262 1289 i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i], … … 1319 1346 rc = SSMR3PutU16(pSSM, pVirtio->virtqProxy[i].uAvailIdx); 1320 1347 rc = SSMR3PutU16(pSSM, pVirtio->virtqProxy[i].uUsedIdx); 1321 rc = SSMR3PutMem(pSSM, pVirtio->virtqProxy[i].sz Name, 32);1348 rc = SSMR3PutMem(pSSM, pVirtio->virtqProxy[i].szVirtqName, 32); 1322 1349 } 1323 1350 … … 1378 1405 rc = SSMR3GetU16(pSSM, &pVirtio->virtqProxy[i].uAvailIdx); 1379 1406 rc = SSMR3GetU16(pSSM, &pVirtio->virtqProxy[i].uUsedIdx); 1380 rc = SSMR3GetMem(pSSM, (void *)&pVirtio->virtqProxy[i].sz Name, 32);1407 rc = SSMR3GetMem(pSSM, (void *)&pVirtio->virtqProxy[i].szVirtqName, 32); 1381 1408 } 1382 1409 } -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80340 r80383 23 23 24 24 #include <iprt/ctype.h> 25 #include <iprt/sg.h> 25 26 26 27 typedef void * VIRTIOHANDLE; /**< Opaque handle to the VirtIO framework */ 27 28 28 #define DISABLE_GUEST_DRIVER 029 29 30 30 /** … … 37 37 #define VIRTQ_MAX_SIZE 1024 /**< Max size (# desc elements) of a virtq */ 38 38 #define VIRTQ_MAX_CNT 24 /**< Max queues we allow guest to create */ 39 #define VIRTQ_DESC_MAX_SIZE (2 * 1024 * 1024) 39 40 40 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ 41 41 #define VIRTIOSCSI_REGION_MEM_IO 0 /**< BAR for MMIO (implementation specific) */ 42 42 #define VIRTIOSCSI_REGION_PORT_IO 1 /**< BAR for PORT I/O (impl specific) */ 43 43 #define VIRTIOSCSI_REGION_PCI_CAP 2 /**< BAR for VirtIO Cap. MMIO (impl specific) */ 44 typedef struct VIRTQ_SEG /**< Describes one segment of a buffer vector */45 {46 RTGCPHYS addr; /**< Physical addr. of this segment's buffer */47 void *pv; /**< Buf to hold value to write or read */48 uint32_t cb; /**< Number of bytes to write or read */49 } VIRTQ_SEG_T;50 51 typedef struct VIRTQ_BUF_VECTOR /**< Scatter/gather buffer vector */52 {53 uint32_t uDescIdx; /**< Desc at head of this vector list */54 uint32_t cSegsIn; /**< Count of segments in aSegsIn[] */55 uint32_t cSegsOut; /**< Count of segments in aSegsOut[] */56 VIRTQ_SEG_T aSegsIn[VIRTQ_MAX_SIZE]; /**< List of segments to write to guest */57 VIRTQ_SEG_T aSegsOut[VIRTQ_MAX_SIZE]; /**< List of segments read from guest */58 } VIRTQ_BUF_VECTOR_T, *PVIRTQ_BUF_VECTOR_T;59 44 60 45 /** … … 72 57 uint16_t uRevisionId; /**< PCI Cfg Revision ID */ 73 58 uint16_t uInterruptLine; /**< PCI Cfg Interrupt line */ 74 uint16_t uInterruptPin; /**< PCI Cfg Interrupt Pin*/59 uint16_t uInterruptPin; /**< PCI Cfg Interrupt pin */ 75 60 } VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS; 76 61 … … 151 136 * Allocate client context for client to work with VirtIO-provided with queue 152 137 * As a side effect creates a buffer vector a client can get a pointer to 153 * with a call to virtioQueue BufVec()138 * with a call to virtioQueueDescChain() 154 139 * 155 140 * @param hVirtio - Handle to VirtIO framework … … 164 149 */ 165 150 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName); 151 152 153 /** 154 * Get the features VirtIO is running withnow. 155 * 156 * @returns Features the guest driver has accepted, finalizing the operational features 157 * 158 */ 159 uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio); 160 166 161 /** 167 162 * Detaches from queue and release resources … … 172 167 */ 173 168 int virtioQueueDetach(VIRTIOHANDLE hVirtio, uint16_t qIdx); 174 175 /**176 * Return pointer to buffer vector object associated with queue177 *178 * @param hVirtio - Handle for VirtIO framework179 * @param qIdx - Queue number180 *181 * @returns Pointer pBufVec if success, else NULL182 */183 PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx);184 169 185 170 /** … … 200 185 * @param hVirtio - Handle for VirtIO framework 201 186 * @param qIdx - Queue number 187 * @param ppInSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 188 * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 202 189 * 203 190 * @returns status VINF_SUCCESS - Success 204 191 * VERR_INVALID_STATE - VirtIO not in ready state 205 192 */ 206 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove );193 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs); 207 194 208 195 /** … … 211 198 * @param hVirtio - Handle for VirtIO framework 212 199 * @param qIdx - Queue number 200 * @param ppInSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 201 * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 213 202 * 214 203 * @returns VINF_SUCCESS - Success … … 216 205 * VERR_NOT_AVAILABLE - Queue is empty 217 206 */ 218 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx );207 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs); 219 208 220 209 /** -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80340 r80383 59 59 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET 0x40 /**< Device experienced unrecoverable error */ 60 60 61 /* @def Virtio Device PCI Capabilities type codes */61 /** @def Virtio Device PCI Capabilities type codes */ 62 62 #define VIRTIO_PCI_CAP_COMMON_CFG 1 /**< Common configuration PCI capability ID */ 63 63 #define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /**< Notification area PCI capability ID */ … … 85 85 86 86 /** 87 * Translation of the descriptor chain associated with one element of virtq avail ring into its 88 * IN and OUT components and represented as respective arrays of SG segments. 89 */ 90 typedef struct VIRTQ_DESC_CHAIN /**< Describes a single queue element */ 91 { 92 RTSGSEG aSegsIn[VIRTQ_MAX_SIZE]; /**< List of segments to write to guest */ 93 RTSGSEG aSegsOut[VIRTQ_MAX_SIZE]; /**< List of segments read from guest */ 94 uint32_t uHeadIdx; /**< Index at head desc (source of seg arrays) */ 95 uint32_t cSegsIn; /**< Count of segments in aSegsIn[] */ 96 uint32_t cSegsOut; /**< Count of segments in aSegsOut[] */ 97 } VIRTQ_DESC_CHAIN_T, *PVIRTQ_DESC_CHAIN_T; 98 99 /** 87 100 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification) 88 101 */ 89 102 typedef struct VIRTQ_PROXY 90 103 { 91 const char szName[32]; /**< Dev-specific name of queue */ 92 PVIRTQ_BUF_VECTOR_T pBufVec; /**< Per-queue s/g data. Serialize access! */ 93 uint16_t uAvailIdx; /**< Consumer's position in avail ring */ 94 uint16_t uUsedIdx; /**< Consumer's position in used ring */ 95 bool fEventThresholdReached; /**< Don't lose track while queueing ahead */ 104 RTSGBUF inSgBuf; /**< host-to-guest buffers */ 105 RTSGBUF outSgBuf; /**< guest-to-host buffers */ 106 const char szVirtqName[32]; /**< Dev-specific name of queue */ 107 uint16_t uAvailIdx; /**< Consumer's position in avail ring */ 108 uint16_t uUsedIdx; /**< Consumer's position in used ring */ 109 bool fEventThresholdReached; /**< Don't lose track while queueing ahead */ 110 PVIRTQ_DESC_CHAIN_T pDescChain; /**< Per-queue s/g data. */ 96 111 } VIRTQ_PROXY_T, *PVIRTQ_PROXY_T; 97 112 … … 107 122 uint32_t uDeviceFeatures; /**< RO (device reports features to driver) */ 108 123 uint32_t uDriverFeaturesSelect; /**< RW (driver selects driver features) */ 109 uint32_t uDriverFeatures; /**< RW (driver accepts device features)*/124 uint32_t uDriverFeatures; /**< RW (driver-accepted device features) */ 110 125 uint16_t uMsixConfig; /**< RW (driver sets MSI-X config vector) */ 111 126 uint16_t uNumQueues; /**< RO (device specifies max queues) */ 112 uint8_t uDeviceStatus; /**< RW (driver writes device status, 0 resets)*/127 uint8_t uDeviceStatus; /**< RW (driver writes device status, 0=reset) */ 113 128 uint8_t uConfigGeneration; /**< RO (device changes when changing configs) */ 114 129 … … 136 151 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T; 137 152 138 139 153 /** 140 154 * The core (/common) state of the VirtIO PCI device … … 146 160 PDMPCIDEV dev; /**< PCI device */ 147 161 char szInstance[16]; /**< Instance name, e.g. "VIRTIOSCSI0" */ 148 void * pClientContext; 162 void * pClientContext; /**< Client callback returned on callbacks */ 149 163 150 164 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3 */ … … 177 191 uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */ 178 192 179 VIRTQ_PROXY_T virtqProxy[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */193 VIRTQ_PROXY_T virtqProxy[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */ 180 194 VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */ 181 195 … … 223 237 uint16_t uDescIdx; /**< idx Index of next free ring slot */ 224 238 uint16_t auRing[1]; /**< ring Ring: avail drv to dev bufs */ 225 uint16_t uUsedEventIdx; /**< used_event (if VIRTQ_USED_F_ NO_NOTIFY) */239 uint16_t uUsedEventIdx; /**< used_event (if VIRTQ_USED_F_EVENT_IDX) */ 226 240 } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T; 227 241 … … 237 251 uint16_t uDescIdx; /**< idx Index of next ring slot */ 238 252 VIRTQ_USED_ELEM_T auRing[1]; /**< ring Ring: used dev to drv bufs */ 239 uint16_t uAvailEventIdx; /**< avail_event if (VIRTQ_USED_F_ NO_NOTIFY) */253 uint16_t uAvailEventIdx; /**< avail_event if (VIRTQ_USED_F_EVENT_IDX) */ 240 254 } VIRTQ_USED_T, *PVIRTQ_USED_T; 241 255 … … 335 349 */ 336 350 337 static int vqIsEventNeeded (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);351 static int vqIsEventNeeded (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld); 338 352 static bool vqIsEmpty (PVIRTIOSTATE pVirtio, uint16_t qIdx); 339 353 static void vqReadDesc (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc); … … 361 375 362 376 /** 363 * Accessor for virtq desc spVirtio377 * Accessor for virtq descriptor 364 378 */ 365 379 DECLINLINE(void) vqReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
Note:
See TracChangeset
for help on using the changeset viewer.