VirtualBox

Changeset 80383 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 22, 2019 7:25:38 AM (5 years ago)
Author:
vboxsync
Message:

Storage/DevVirtioSCSI.cpp: Got notification and initial worker thread scheme implemented. Structured queue transition into device code, and reading and parsing controlq header and request queue header. See bugref:9440 Comment 56 for more information.

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r80340 r80383  
    2727#include <VBox/vmm/pdmcritsect.h>
    2828#include <VBox/version.h>
     29#include <VBox/log.h>
    2930#include <iprt/errcore.h>
    30 #include <VBox/log.h>
    3131#include <iprt/assert.h>
    3232#include <iprt/string.h>
     
    3636# include <iprt/alloc.h>
    3737# include <iprt/memcache.h>
     38# include <iprt/semaphore.h>
     39# include <iprt/sg.h>
    3840# include <iprt/param.h>
    3941# include <iprt/uuid.h>
     
    6668#define VIRTIOSCSI_MAX_TARGETS                      1            /**< Can probably determined from higher layers       */
    6769#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?           */
    6971#define VIRTIOSCSI_MAX_SEG_COUNT                    1024         /* < T.B.D. What is a good value for this?           */
    7072#define VIRTIOSCSI_MAX_SECTORS_HINT                 0x10000      /* < VirtIO specification, section 5.6.4             */
     
    8991#define EVENTQ_IDX                                  1            /**< Spec-defined Index of event queue               */
    9092#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
    9798 * of the VirtIO 1.0 specification. This layout maps an MMIO area shared VirtIO guest driver. The VBox VirtIO
    9899 * this virtual controller device implementation is a client of. The frame work calls back whenever the guest driver
     
    111112    uint16_t uMaxTarget;                                         /**< max_target       Hint to guest driver           */
    112113    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
    123116
    124117/**
     
    140133    uint8_t  uLUN[8];                                           /**< lun                                             */
    141134    uint32_t uReason;                                           /**< reason                                          */
    142 } VIRTIO_SCSI_EVENT_T, *PVIRTIO_SCSI_EVENT_T;
     135} VIRTIOSCSI_EVENT_T, *PVIRTIOSCSI_EVENT_T;
    143136
    144137/**
     
    161154#define VIRTIOSCSI_DATA_OUT                         512         /**< Value TBD (see section 5.6.6.1)                 */
    162155
     156#pragma pack(1)
    163157typedef struct virtio_scsi_req_cmd
    164158{
    165159    /* 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()
    193194
    194195/**
     
    218219
    219220/**
     221 * @name VirtIO 1.0 SCSI Host Device Control command before we know type (5.6.6.2)
     222 * @{  */
     223typedef struct virtio_scsi_ctrl
     224{
     225    uint32_t uType;
     226} VIRTIOSCSI_CTRL, *PVIRTIOSCSI_CTRL_T;
     227
     228/**
    220229 * @name VirtIO 1.0 SCSI Host Device command-specific TMF values
    221230 * @{  */
     
    231240/*** @} */
    232241
     242#pragma pack(1)
    233243typedef struct virtio_scsi_ctrl_tmf
    234244{
     
    240250    // Device-writable part
    241251    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)
    243254
    244255/**
     
    253264#define VIRTIOSCSI_T_AN_SUBSCRIBE                 2           /** Asynchronous notification subscription             */
    254265
     266#pragma pack(1)
    255267typedef struct virtio_scsi_ctrl_an
    256268{
     
    262274    uint32_t  uEventActual;                                   /** event_actual                                       */
    263275    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()
    265278
    266279/**
     
    275288/** @} */
    276289
     290
     291/**
     292 * Worker thread context
     293 */
     294typedef struct WORKER
     295{
     296    R3PTRTYPE(PPDMTHREAD)           pThread;
     297    SUPSEMEVENT                     hEvtProcess;
     298    bool                            fSleeping;
     299    bool                            fNotified;
     300} WORKER, *PWORKER;
     301
    277302/**
    278303 * State of a target attached to the VirtIO SCSI Host
     
    281306{
    282307    /** Pointer to PCI device that owns this target instance. - R3 pointer */
    283     R3PTRTYPE(struct VIRTIOSCSI *)  pVirtioScsiR3;
     308    R3PTRTYPE(struct VIRTIOSCSI *)  pThisR3;
    284309
    285310    /** Pointer to attached driver's base interface. */
     
    320345} VIRTIOSCSITARGET, *PVIRTIOSCSITARGET;
    321346
    322 
    323347/**
    324348 *  PDM instance data (state) for VirtIO Host SCSI device
     
    328352typedef struct VIRTIOSCSI
    329353{
    330     /* Opaque handle to VirtIO common framework (must be first item
    331      * 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) */
    332356    VIRTIOHANDLE                    hVirtio;
    333357
    334     /* SCSI target instances data */
     358    /** SCSI target instances data */
    335359    VIRTIOSCSITARGET                aTargetInstances[VIRTIOSCSI_MAX_TARGETS];
    336360
     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;
    337367    /** Instance name */
    338368    const char                      szInstance[16];
     
    372402    R3R0PTRTYPE(PSUPDRVSESSION)     pSupDrvSession;
    373403
    374     /** Worker thread. */
    375     R3PTRTYPE(PPDMTHREAD)           pThreadWrk;
    376 
    377404    /** The event semaphore the processing thread waits on. */
    378     SUPSEMEVENT                     hEvtProcess;
    379405
    380406    /** Number of ports detected */
     
    384410    bool volatile                   fSignalIdle;
    385411
    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;
    387418
    388419
     
    422453 */
    423454#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)) \
    427458             && 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))
    430461
    431462#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), \
    433464            pv, cb, uIntraOffset, fWrite, false, 0);
    434465
    435466#define SCSI_CONFIG_ACCESSOR(member) \
    436467    { \
    437         uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \
     468        uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member); \
    438469        if (fWrite) \
    439             memcpy(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset, (const char *)pv, cb); \
     470            memcpy(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset, (const char *)pv, cb); \
    440471        else \
    441             memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \
     472            memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset), cb); \
    442473        LOG_ACCESSOR(member); \
    443474    }
     
    445476#define SCSI_CONFIG_ACCESSOR_READONLY(member) \
    446477    { \
    447         uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \
     478        uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIOSCSI_CONFIG_T, member); \
    448479        if (fWrite) \
    449480            LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
    450481        else \
    451482        { \
    452             memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \
     483            memcpy((char *)pv, (const char *)(((char *)&pThis->virtioScsiConfig.member) + uIntraOffset), cb); \
    453484            LOG_ACCESSOR(member); \
    454485        } \
     
    479510#endif
    480511
    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 */
     514typedef 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
     528typedef 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
     570static 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
     633static 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 */
     773static 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
     781static 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;
    554825}
    555826
    556827static DECLCALLBACK(void) virtioScsiQueueNotified(VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx)
    557828{
     829    RT_NOREF(hVirtio);
     830
    558831    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];
    567834
    568835    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    }
    572849    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)));
    578851}
    579852
     
    582855    Log2Func(("\n"));
    583856    RT_NOREF(hVirtio);
    584     PVIRTIOSCSI pVirtioScsi = (PVIRTIOSCSI)pClient;
     857    PVIRTIOSCSI pThis = (PVIRTIOSCSI)pClient;
     858    pThis->fVirtioReady = fVirtioReady;
    585859    if (fVirtioReady)
     860    {
    586861        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    }
    587868    else
    588869    {
    589870        Log2Func(("VirtIO is resetting\n"));
    590871        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
    594879
    595880/**
    596881 * Implementation invokes this to reset the VirtIO device
    597882 */
    598 static void virtioScsiDeviceReset(PVIRTIOSCSI pVirtioScsi)
    599 {
    600     pVirtioScsi->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT;
    601     pVirtioScsi->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT;
    602     virtioResetAll(pVirtioScsi->hVirtio);
    603 }
    604 
    605 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pVirtioScsi, uint32_t uOffset,
     883static 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
     890static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pThis, uint32_t uOffset,
    606891                                    const void *pv, size_t cb, uint8_t fWrite)
    607892{
     
    676961{
    677962    int rc = VINF_SUCCESS;
    678     PVIRTIOSCSI  pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
     963    PVIRTIOSCSI  pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    679964
    680965//    LogFunc(("Read from Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
    681966//              uOffset, cb));
    682967
    683     rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, false);
     968    rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, false);
    684969
    685970    return rc;
     
    698983{
    699984    int rc = VINF_SUCCESS;
    700     PVIRTIOSCSI  pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
     985    PVIRTIOSCSI  pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    701986
    702987//    LogFunc(("Write to Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
    703988//              uOffset, cb));
    704989
    705     rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, true);
     990    rc = virtioScsiR3CfgAccessed(pThis, uOffset, pv, cb, true);
    706991
    707992    return rc;
     
    8101095static DECLCALLBACK(void) virtioScsiR3PDMReset(PPDMDEVINS pDevIns)
    8111096{
    812     PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    813     virtioScsiDeviceReset(pVirtioScsi);
     1097    PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
     1098    virtioScsiDeviceReset(pThis);
    8141099
    8151100//    ASMAtomicWriteBool(&pThis->fSignalIdle, true);
     
    8501135    {
    8511136        PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[i];
    852         pTarget->pVirtioScsiR3 = pThis;;
     1137        pTarget->pThisR3 = pThis;;
    8531138    }
    8541139
     
    8631148                                                       uint32_t *piInstance, uint32_t *piLUN)
    8641149{
    865     PVIRTIOSCSITARGET pVirtioScsiTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaPort);
    866     PPDMDEVINS pDevIns = pVirtioScsiTarget->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);
    8671152
    8681153    AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
     
    8721157    *ppcszController = pDevIns->pReg->szName;
    8731158    *piInstance = pDevIns->iInstance;
    874     *piLUN = pVirtioScsiTarget->iLUN;
     1159    *piLUN = pThisTarget->iLUN;
    8751160
    8761161    return VINF_SUCCESS;
     
    8991184/*
    9001185    if (RT_UNLIKELY(pReq->fBIOS))
    901         cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offDst, cbCopy);
     1186        cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(pThis)->VBoxSCSI, pSgBuf, offDst, cbCopy);
    9021187    else
    903         cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offDst, cbCopy);
     1188        cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(pThis), pReq, pSgBuf, offDst, cbCopy);
    9041189    return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
    9051190*/
     
    9291214/*
    9301215    if (RT_UNLIKELY(pReq->fBIOS))
    931         cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offSrc, cbCopy);
     1216        cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(pThis)->VBoxSCSI, pSgBuf, offSrc, cbCopy);
    9321217    else
    933         cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offSrc, cbCopy);
     1218        cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(pThis), pReq, pSgBuf, offSrc, cbCopy);
    9341219    return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
    9351220*/
     
    9501235    RT_NOREF(rcReq);
    9511236    RT_NOREF(hIoReq);
    952 //    virtioScsiR3ReqComplete(pTarget->CTX_SUFF(pVirtioScsi), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
     1237//    virtioScsiR3ReqComplete(pTarget->CTX_SUFF(pThis), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
    9531238    return VINF_SUCCESS;
    9541239}
     
    9701255            /* Make sure the request is not accounted for so the VM can suspend successfully. */
    9711256            uint32_t cTasksActive = ASMAtomicDecU32(&pTarget->cOutstandingRequests);
    972             if (!cTasksActive && pTarget->CTX_SUFF(pVirtioScsi)->fSignalIdle)
    973                 PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(pVirtioScsi)->pDevInsR3);
     1257            if (!cTasksActive && pTarget->CTX_SUFF(pThis)->fSignalIdle)
     1258                PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(pThis)->pDevInsR3);
    9741259            break;
    9751260        }
     
    9891274{
    9901275    PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
    991     PVIRTIOSCSI pThis = pTarget->CTX_SUFF(pVirtioScsi);
     1276    PVIRTIOSCSI pThis = pTarget->CTX_SUFF(pThis);
    9921277
    9931278    if (pThis->pMediaNotify)
     
    9951280}
    9961281
    997 /**
    998  * Transmit queue consumer
    999  * 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 }
    10161282
    10171283
     
    11451411static DECLCALLBACK(void *) virtioScsiR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    11461412{
    1147     PVIRTIOSCSI pVirtioScsi = RT_FROM_MEMBER(pInterface, VIRTIOSCSI, IBase);
    1148 
    1149     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,         &pVirtioScsi->IBase);
    1150     PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS,     &pVirtioScsi->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);
    11511417
    11521418    return NULL;
     
    12331499     * Check the versions here as well since the destructor is *always* called.
    12341500     */
     1501
    12351502    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;
    12371516}
    12381517
     
    12431522    PVIRTIOSCSI  pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
    12441523    int  rc = VINF_SUCCESS;
    1245     bool fBootable = false;
    12461524
    12471525    pThis->pDevInsR3 = pDevIns;
    12481526    pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
    12491527    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
     1528    pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
    12501529
    12511530    LogFunc(("PDM device instance: %d\n", iInstance));
     
    12691548    LogFunc(("NumTargets=%d\n", pThis->cTargets));
    12701549
    1271     rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &fBootable, true);
     1550    rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &pThis->fBootable, true);
    12721551    if (RT_FAILURE(rc))
    12731552         return PDMDEV_SET_ERROR(pDevIns, rc,
    12741553                                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"));
    12761565
    12771566    VIRTIOPCIPARAMS virtioPciParams, *pVirtioPciParams = &virtioPciParams;
     
    12911580    pThis->virtioScsiConfig.uMaxSectors     = VIRTIOSCSI_MAX_SECTORS_HINT;
    12921581    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! */
    12941583    pThis->virtioScsiConfig.uSenseSize      = VIRTIOSCSI_SENSE_SIZE_DEFAULT;
    12951584    pThis->virtioScsiConfig.uCdbSize        = VIRTIOSCSI_CDB_SIZE_DEFAULT;
     
    13081597                         virtioScsiR3LoadExec,
    13091598                         virtioScsiR3LoadDone,
    1310                          sizeof(VIRTIO_SCSI_CONFIG_T) /* cbDevSpecificCap */,
     1599                         sizeof(VIRTIOSCSI_CONFIG_T) /* cbDevSpecificCap */,
    13111600                         (void *)&pThis->virtioScsiConfig /* pDevSpecificCap */);
    13121601
     
    13141603        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO"));
    13151604
     1605
    13161606    RTStrCopy((char *)pThis->szQueueNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
    13171607    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    }
    13201644
    13211645    rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_MEM_IO, 32,
     
    13371661#endif
    13381662
    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 
    13451663    /* Initialize per device instance. */
    13461664    for (RTUINT iLUN = 0; iLUN < VIRTIOSCSI_MAX_TARGETS; iLUN++)
     
    13531671        /* Initialize static parts of the device. */
    13541672        pTarget->iLUN = iLUN;
    1355         pTarget->pVirtioScsiR3 = pThis;
     1673        pTarget->pThisR3 = pThis;
    13561674
    13571675        pTarget->IBase.pfnQueryInterface                 = virtioScsiR3TargetQueryInterface;
     
    14121730        }
    14131731    }
    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 */
    14221732
    14231733    /* Status driver */
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r80340 r80383  
    2828#include <iprt/mem.h>
    2929#include <iprt/assert.h>
     30#include <iprt/sg.h>
    3031#include <VBox/vmm/pdmdev.h>
    3132#include "Virtio_1_0_impl.h"
     
    3536
    3637#ifdef LOG_ENABLED
    37 # define QUEUENAME(s, q) (q->szName)
     38# define QUEUENAME(s, q) (q->szVirtqName)
    3839#endif
    3940
     
    9394}
    9495
     96/**
     97 * See API comments in header file for description
     98 */
    9599int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName)
    96100{
     
    98102    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    99103    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 */
    130121const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    131122{
     
    134125                    ("Guest driver not in ready state.\n"), "<null>");
    135126
    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 */
    139133int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    140134{
     
    150144        return VERR_NOT_AVAILABLE;
    151145
    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));
    154147    pVirtqProxy->uAvailIdx++;
    155148
     
    157150}
    158151
     152
     153/**
     154 * See API comments in header file for description
     155 */
     156uint64_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 */
    159166bool virtioQueueIsEmpty(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    160167{
     
    163170}
    164171
    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 */
     175int 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 */
     183int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove,
     184                PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs)
    172185{
    173186    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    174187    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    175     PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
     188    PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
    176189
    177190    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     
    181194        return VERR_NOT_AVAILABLE;
    182195
    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));
    189204
    190205    if (fRemove)
     
    194209    do
    195210    {
    196         VIRTQ_SEG_T *pSeg;
     211        RTSGSEG *pSeg;
    197212
    198213        /**
     
    202217        * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
    203218        */
    204         if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE)
     219        if (pDescChain->cSegsIn + pDescChain->cSegsOut >= VIRTQ_MAX_SIZE)
    205220        {
    206221            static volatile uint32_t s_cMessages  = 0;
     
    208223            if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold))
    209224            {
    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"));
    213227                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)));
    216230                ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10);
    217231            }
     
    220234        RT_UNTRUSTED_VALIDATED_FENCE();
    221235
    222 //        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
     236        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
     237
    223238        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
    224239        {
    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++]);
    228245        }
    229246        else
    230247        {
    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;
    239256
    240257        uDescIdx = desc.uDescIdxNext;
    241258    } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
    242259
    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));
    245269
    246270    return VINF_SUCCESS;
     
    254278    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    255279    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    256     PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
     280    PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
    257281
    258282    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
    259283                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    260284
    261     Log2Func(("%s: %s desc_idx=%u acb=%u\n",
    262              INSTANCE(pVirtio), pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn));
    263 
    264     uint32_t cbRemaining = pBufVec->cSegsIn;
    265 
    266     for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg)
    267     {
    268         uint32_t cbSegLen = pBufVec->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;
    269293        if (cbSegLen > cbRemaining)   // last segment only partially used?
    270294            cbSegLen = cbRemaining;
    271295
    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//        }
    284307        cbRemaining -= cbSegLen;
    285308    }
    286309
    287310    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
    288     Log2Func(("%s: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n",
    289           INSTANCE(pVirtio), pVirtqProxy->szName,
    290           pVirtqProxy->uUsedIdx, uDescIdx, pBufVec->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));
    291314
    292315    if (pVirtqProxy->uUsedIdx == vqReadAvailUsedEvent(pVirtio, qIdx))
    293316        pVirtqProxy->fEventThresholdReached = true;
    294     vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pBufVec->uDescIdx,  pBufVec->cSegsIn);
     317    vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pDescChain->uHeadIdx,  pDescChain->cSegsIn);
    295318
    296319    return VINF_SUCCESS;
    297320}
    298321
    299  /** See API comments in header file prototype for description */
     322/**
     323 * See API comments in header file for description
     324 */
    300325int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    301326{
     
    309334
    310335    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
    311     Log2Func(("%s: %s old_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));
    313338
    314339    vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx);
     
    318343}
    319344
    320  /** See API comments in header file prototype for description */
     345/**
     346 * See API comments in header file for description
     347 */
    321348static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx)
    322349{
     
    324351
    325352    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    326     Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pVirtqProxy->szName));
     353    Log2Func(("%s\n", pVirtqProxy->szVirtqName));
    327354
    328355    /** Inform client */
     
    343370                    ("Guest driver not in ready state.\n"));
    344371
    345     LogFlowFunc(("%s: %s availFlags=%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),
    347374            pVirtio->uDriverFeatures, vqIsEmpty(pVirtio, qIdx) ? "" : "not "));
    348375
     
    390417    RT_NOREF(offDelta);
    391418    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    392     LogFunc(("%s\n", INSTANCE(pVirtio)));
     419    LogFunc(("\n"));
    393420
    394421    pVirtio->pDevInsR3 = pDevIns;
     
    406433{
    407434   if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
    408        LogFlowFunc(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio)));
     435       LogFlowFunc(("Cause: queue interrupt\n"));
    409436   else
    410437   if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
    411        LogFlowFunc(("%s: Cause: device config\n", INSTANCE(pVirtio)));
     438       LogFlowFunc(("Cause: device config\n"));
    412439
    413440    pVirtio->uISR |= uCause;
     
    423450static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio)
    424451{
    425     LogFlowFunc(("%s\n", INSTANCE(pVirtio)));
     452    LogFlowFunc(("\n"));
    426453    PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0);
    427454}
     
    713740        {
    714741            ++pVirtio->uConfigGeneration;
    715             Log2Func(("Bumped cfg. generation to %d because %s %s\n",
     742            Log2Func(("Bumped cfg. generation to %d because %s%s\n",
    716743                pVirtio->uConfigGeneration,
    717744                fDevSpecificFieldChanged ? "<dev cfg changed> " : "",
     
    10241051    pVirtio->pDevSpecificCfg  = pDevSpecificCfg;
    10251052
    1026     pVirtio->pPrevDevSpecificCfg = RTMemAlloc(cbDevSpecificCfg);
     1053    pVirtio->pPrevDevSpecificCfg = RTMemAllocZ(cbDevSpecificCfg);
    10271054    if (!pVirtio->pPrevDevSpecificCfg)
    10281055    {
     
    11311158     * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram
    11321159     * 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.
    11341161     */
    11351162    pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
     
    12011228     *  out size, so pad with an extra page */
    12021229
    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),
    12041231                                      PCI_ADDRESS_SPACE_MEM, virtioR3Map);
    12051232    if (RT_FAILURE(rc))
     
    12531280    {
    12541281        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"
    12561283                  "  uQueueSize[%u]              = %u\n  uQueueNotifyOff[%u]         = %04x\n"
    12571284                  "  uQueueMsixVector[%u]        = %04x\n  uQueueEnable[%u]            = %04x\n"
    12581285                  "  pGcPhysQueueDesc[%u]        = %RGp\n  pGcPhysQueueAvail[%u]       = %RGp\n"
    12591286                  "  pGcPhysQueueUsed[%u]        = %RGp\n",
    1260                         i, pVirtio->virtqProxy[i].szName, i, pVirtio->virtqProxy[i].uAvailIdx,
     1287                        i, pVirtio->virtqProxy[i].szVirtqName, i, pVirtio->virtqProxy[i].uAvailIdx,
    12611288                        i, pVirtio->virtqProxy[i].uUsedIdx, i, pVirtio->uQueueSize[i],
    12621289                        i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i],
     
    13191346        rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uAvailIdx);
    13201347        rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uUsedIdx);
    1321         rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szName, 32);
     1348        rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szVirtqName, 32);
    13221349    }
    13231350
     
    13781405            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uAvailIdx);
    13791406            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uUsedIdx);
    1380             rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szName, 32);
     1407            rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szVirtqName, 32);
    13811408        }
    13821409    }
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r80340 r80383  
    2323
    2424#include <iprt/ctype.h>
     25#include <iprt/sg.h>
    2526
    2627typedef void * VIRTIOHANDLE;                                     /**< Opaque handle to the VirtIO framework */
    2728
    28 #define DISABLE_GUEST_DRIVER 0
    2929
    3030/**
     
    3737#define VIRTQ_MAX_SIZE                      1024                 /**< Max size (# desc elements) of a virtq    */
    3838#define VIRTQ_MAX_CNT                       24                   /**< Max queues we allow guest to create      */
    39 #define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
     39
    4040#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
    4141#define VIRTIOSCSI_REGION_MEM_IO            0                    /**< BAR for MMIO (implementation specific)   */
    4242#define VIRTIOSCSI_REGION_PORT_IO           1                    /**< BAR for PORT I/O (impl specific)         */
    4343#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;
    5944
    6045/**
     
    7257    uint16_t  uRevisionId;                                       /**< PCI Cfg Revision ID                      */
    7358    uint16_t  uInterruptLine;                                    /**< PCI Cfg Interrupt line                   */
    74     uint16_t  uInterruptPin;                                     /**< PCI Cfg InterruptPin                     */
     59    uint16_t  uInterruptPin;                                     /**< PCI Cfg Interrupt pin                    */
    7560} VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
    7661
     
    151136 * Allocate client context for client to work with VirtIO-provided with queue
    152137 * As a side effect creates a buffer vector a client can get a pointer to
    153  * with a call to virtioQueueBufVec()
     138 * with a call to virtioQueueDescChain()
    154139 *
    155140 * @param  hVirtio   - Handle to VirtIO framework
     
    164149 */
    165150int 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 */
     159uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio);
     160
    166161/**
    167162 * Detaches from queue and release resources
     
    172167 */
    173168int virtioQueueDetach(VIRTIOHANDLE hVirtio, uint16_t qIdx);
    174 
    175 /**
    176  * Return pointer to buffer vector object associated with queue
    177  *
    178  * @param hVirtio   - Handle for VirtIO framework
    179  * @param qIdx      - Queue number
    180  *
    181  * @returns           Pointer pBufVec if success, else NULL
    182  */
    183 PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx);
    184169
    185170/**
     
    200185 * @param hVirtio   - Handle for VirtIO framework
    201186 * @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
    202189 *
    203190 * @returns status    VINF_SUCCESS         - Success
    204191 *                    VERR_INVALID_STATE   - VirtIO not in ready state
    205192 */
    206 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove);
     193int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
    207194
    208195/**
     
    211198 * @param hVirtio   - Handle for VirtIO framework
    212199 * @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
    213202 *
    214203 * @returns           VINF_SUCCESS         - Success
     
    216205 *                    VERR_NOT_AVAILABLE   - Queue is empty
    217206 */
    218 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     207int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
    219208
    220209/**
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80340 r80383  
    5959#define VIRTIO_STATUS_DEVICE_NEEDS_RESET             0x40        /**< Device experienced unrecoverable error    */
    6060
    61 /* @def Virtio Device PCI Capabilities type codes */
     61/** @def Virtio Device PCI Capabilities type codes */
    6262#define VIRTIO_PCI_CAP_COMMON_CFG                       1        /**< Common configuration PCI capability ID    */
    6363#define VIRTIO_PCI_CAP_NOTIFY_CFG                       2        /**< Notification area PCI capability ID       */
     
    8585
    8686/**
     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 */
     90typedef 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/**
    87100 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification)
    88101 */
    89102typedef struct VIRTQ_PROXY
    90103{
    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.                       */
    96111} VIRTQ_PROXY_T, *PVIRTQ_PROXY_T;
    97112
     
    107122    uint32_t  uDeviceFeatures;                                   /**< RO (device reports features to driver)    */
    108123    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)      */
    110125    uint16_t  uMsixConfig;                                       /**< RW (driver sets MSI-X config vector)      */
    111126    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) */
    113128    uint8_t   uConfigGeneration;                                 /**< RO (device changes when changing configs) */
    114129
     
    136151} VIRTIO_PCI_CFG_CAP_T,   *PVIRTIO_PCI_CFG_CAP_T;
    137152
    138 
    139153/**
    140154 * The core (/common) state of the VirtIO PCI device
     
    146160    PDMPCIDEV                 dev;                               /**< PCI device                                */
    147161    char                      szInstance[16];                    /**< Instance name, e.g. "VIRTIOSCSI0"         */
    148     void *                    pClientContext;                     /**< Client callback returned on callbacks     */
     162    void *                    pClientContext;                    /**< Client callback returned on callbacks     */
    149163
    150164    PPDMDEVINSR3              pDevInsR3;                         /**< Device instance - R3                      */
     
    177191    uint8_t                   uConfigGeneration;                 /**< (MMIO) Device config sequencer       HOST */
    178192
    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         */
    180194    VIRTIOCALLBACKS           virtioCallbacks;                   /**< Callback vectors to client                */
    181195
     
    223237    uint16_t  uDescIdx;                                          /**< idx        Index of next free ring slot   */
    224238    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)    */
    226240} VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
    227241
     
    237251    uint16_t  uDescIdx;                                          /**< idx         Index of next ring slot       */
    238252    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)   */
    240254} VIRTQ_USED_T, *PVIRTQ_USED_T;
    241255
     
    335349 */
    336350
    337 static int         vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
     351static int         vqIsEventNeeded        (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
    338352static bool        vqIsEmpty              (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    339353static void        vqReadDesc             (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
     
    361375
    362376/**
    363  * Accessor for virtq descspVirtio
     377 * Accessor for virtq descriptor
    364378 */
    365379DECLINLINE(void) vqReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette