VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp@ 80346

Last change on this file since 80346 was 80340, checked in by vboxsync, 6 years ago

Fixed error in MMIO handling of cfg gen check/increment. Seem to have resolved stack corruption issue caused by putting structs that allocated 1.5MB on the stack in temporary functions to test notification callback and test de-queing data. See bugref:9440 Comment #53 for more info

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.1 KB
Line 
1/* $Id: DevVirtioSCSI.cpp 80340 2019-08-19 07:43:37Z vboxsync $ $Revision: 80340 $ $Date: 2019-08-19 07:43:37 +0000 (Mon, 19 Aug 2019) $ $Author: vboxsync $ */
2/** @file
3 * VBox storage devices - Virtio SCSI Driver
4 *
5 */
6
7/*
8 * Copyright (C) 2006-2019 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*********************************************************************************************************************************
21* Header Files *
22*********************************************************************************************************************************/
23#define LOG_GROUP LOG_GROUP_DRV_SCSI
24
25#include <VBox/vmm/pdmdev.h>
26#include <VBox/vmm/pdmstorageifs.h>
27#include <VBox/vmm/pdmcritsect.h>
28#include <VBox/version.h>
29#include <iprt/errcore.h>
30#include <VBox/log.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include "../build/VBoxDD.h"
34#include <VBox/scsi.h>
35#ifdef IN_RING3
36# include <iprt/alloc.h>
37# include <iprt/memcache.h>
38# include <iprt/param.h>
39# include <iprt/uuid.h>
40#endif
41#include "../VirtIO/Virtio_1_0.h"
42
43#include "VBoxSCSI.h"
44#include "VBoxDD.h"
45
46
47/**
48 * @name VirtIO 1.0 SCSI Host feature bits (See VirtIO 1.0 specification, Section 5.6.3)
49 * @{ */
50#define VIRTIOSCSI_F_INOUT RT_BIT_64(0) /** Request is device readable AND writeable */
51#define VIRTIOSCSI_F_HOTPLUG RT_BIT_64(1) /** Host allows hotplugging SCSI LUNs & targets */
52#define VIRTIOSCSI_F_CHANGE RT_BIT_64(2) /** Host LUNs chgs via VIRTIOSCSI_T_PARAM_CHANGE evt */
53#define VIRTIOSCSI_F_T10_PI RT_BIT_64(3) /** Add T10 port info (DIF/DIX) in SCSI req hdr */
54/** @} */
55
56#define VIRTIOSCSI_HOST_SCSI_ALL_FEATURES \
57 (VIRTIOSCSI_F_INOUT | VIRTIOSCSI_F_HOTPLUG | VIRTIOSCSI_F_CHANGE | VIRTIOSCSI_F_T10_PI)
58
59#define VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED 0 /**< TBD, support at least hotplug & in/out */
60
61/**
62 * TEMPORARY NOTE: following parameter is set to 1 for early development. Will be increased later
63 */
64#define VIRTIOSCSI_REQ_QUEUE_CNT 1 /**< Number of req queues exposed by dev. */
65#define VIRTIOSCSI_QUEUE_CNT VIRTIOSCSI_REQ_QUEUE_CNT + 2
66#define VIRTIOSCSI_MAX_TARGETS 1 /**< Can probably determined from higher layers */
67#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? */
69#define VIRTIOSCSI_MAX_SEG_COUNT 1024 /* < T.B.D. What is a good value for this? */
70#define VIRTIOSCSI_MAX_SECTORS_HINT 0x10000 /* < VirtIO specification, section 5.6.4 */
71#define VIRTIOSCSI_MAX_CHANNEL_HINT 0 /* < VirtIO specification, section 5.6.4 */
72#define VIRTIOSCSI_SAVED_STATE_MINOR_VERSION 0x01 /**< SSM version # */
73
74#define PCI_DEVICE_ID_VIRTIOSCSI_HOST 0x1048 /**< Informs guest driver of type of VirtIO device */
75#define PCI_CLASS_BASE_MASS_STORAGE 0x01 /**< PCI Mass Storage device class */
76#define PCI_CLASS_SUB_SCSI_STORAGE_CONTROLLER 0x00 /**< PCI SCSI Controller subclass */
77#define PCI_CLASS_PROG_UNSPECIFIED 0x00 /**< Programming interface. N/A. */
78#define VIRTIOSCSI_PCI_CLASS 0x01 /**< Base class Mass Storage? */
79#define REQ_ALLOC_SIZE 1024 /**< Allocation size. Need to investigate optimal */
80
81/**
82 * VirtIO SCSI Host Device device-specific queue indicies
83 *
84 * Virtqs (and their indices) are specified for a SCSI Host Device as described in the VirtIO 1.0 specification
85 * section 5.6. Thus there is no need to explicitly indicate the number of queues needed by this device. The number
86 * of req queues is variable and determined by virtio_scsi_config.num_queues. See VirtIO 1.0 spec section 5.6.4
87 */
88#define CONTROLQ_IDX 0 /**< Spec-defined Index of control queue */
89#define EVENTQ_IDX 1 /**< Spec-defined Index of event queue */
90#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
97 * of the VirtIO 1.0 specification. This layout maps an MMIO area shared VirtIO guest driver. The VBox VirtIO
98 * this virtual controller device implementation is a client of. The frame work calls back whenever the guest driver
99 * accesses any part of field in this struct
100 */
101typedef struct virtio_scsi_config
102{
103 uint32_t uNumQueues; /**< num_queues # of req q's exposed by dev */
104 uint32_t uSegMax; /**< seg_max Max # of segs allowed in cmd */
105 uint32_t uMaxSectors; /**< max_sectors Hint to guest max xfer to use */
106 uint32_t uCmdPerLun; /**< cmd_per_lun Max # of link cmd sent per lun */
107 uint32_t uEventInfoSize; /**< event_info_size Fill max, evtq bufs */
108 uint32_t uSenseSize; /**< sense_size Max sense data size dev writes */
109 uint32_t uCdbSize; /**< cdb_size Max CDB size driver writes */
110 uint16_t uMaxChannel; /**< max_channel Hint to guest driver */
111 uint16_t uMaxTarget; /**< max_target Hint to guest driver */
112 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 */
118typedef struct virtio_scsi_ctrl
119{
120 uint32_t type; /**< type */
121 uint8_t response; /**< response */
122} VIRTIO_SCSI_CTRL_T, *PVIRTIO_SCSI_CTRL_T;
123
124/**
125 * @name VirtIO 1.0 SCSI Host Device device specific control types
126 * @{ */
127#define VIRTIOSCSI_T_NO_EVENT 0
128#define VIRTIOSCSI_T_TRANSPORT_RESET 1
129#define VIRTIOSCSI_T_ASYNC_NOTIFY 2 /**< Asynchronous notification */
130#define VIRTIOSCSI_T_PARAM_CHANGE 3
131/** @} */
132
133/**
134 * Device operation: eventq
135 */
136#define VIRTIOSCSI_T_EVENTS_MISSED 0x80000000
137typedef struct virtio_scsi_event {
138 // Device-writable part
139 uint32_t uEvent; /**< event: */
140 uint8_t uLUN[8]; /**< lun */
141 uint32_t uReason; /**< reason */
142} VIRTIO_SCSI_EVENT_T, *PVIRTIO_SCSI_EVENT_T;
143
144/**
145 * @name VirtIO 1.0 SCSI Host Device device specific event types
146 * @{ */
147#define VIRTIOSCSI_EVT_RESET_HARD 0 /**< */
148#define VIRTIOSCSI_EVT_RESET_RESCAN 1 /**< */
149#define VIRTIOSCSI_EVT_RESET_REMOVED 2 /**< */
150/** @} */
151
152/**
153 * Device operation: reqestq
154 *
155 * The following struct is described in VirtIO 1.0 Specification, section 5.6.6.1
156 */
157#define VIRTIOSCSI_SENSE_SIZE_DEFAULT 96 /**< VirtIO 1.0: 96 on reset, guest can change */
158#define VIRTIOSCSI_CDB_SIZE_DEFAULT 32 /**< VirtIO 1.0: 32 on reset, guest can change */
159#define VIRTIOSCSI_PI_BYTES_IN 1 /**< Value TBD (see section 5.6.6.1) */
160#define VIRTIOSCSI_PI_BYTES_OUT 1 /**< Value TBD (see section 5.6.6.1) */
161#define VIRTIOSCSI_DATA_OUT 512 /**< Value TBD (see section 5.6.6.1) */
162
163typedef struct virtio_scsi_req_cmd
164{
165 /* 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;
193
194/**
195 * @name VirtIO 1.0 SCSI Host Device Req command-specific response values
196 * @{ */
197#define VIRTIOSCSI_S_OK 0 /**< control, command */
198#define VIRTIOSCSI_S_OVERRUN 1 /**< control */
199#define VIRTIOSCSI_S_ABORTED 2 /**< control */
200#define VIRTIOSCSI_S_BAD_TARGET 3 /**< control, command */
201#define VIRTIOSCSI_S_RESET 4 /**< control */
202#define VIRTIOSCSI_S_BUSY 5 /**< control, command */
203#define VIRTIOSCSI_S_TRANSPORT_FAILURE 6 /**< control, command */
204#define VIRTIOSCSI_S_TARGET_FAILURE 7 /**< control, command */
205#define VIRTIOSCSI_S_NEXUS_FAILURE 8 /**< control, command */
206#define VIRTIOSCSI_S_FAILURE 9 /**< control, command */
207#define VIRTIOSCSI_S_INCORRECT_LUN 12 /**< command */
208/** @} */
209
210/**
211 * @name VirtIO 1.0 SCSI Host Device command-specific task_attr values
212 * @{ */
213#define VIRTIOSCSI_S_SIMPLE 0 /**< */
214#define VIRTIOSCSI_S_ORDERED 1 /**< */
215#define VIRTIOSCSI_S_HEAD 2 /**< */
216#define VIRTIOSCSI_S_ACA 3 /**< */
217/** @} */
218
219/**
220 * @name VirtIO 1.0 SCSI Host Device command-specific TMF values
221 * @{ */
222#define VIRTIOSCSI_T_TMF 0 /**< */
223#define VIRTIOSCSI_T_TMF_ABORT_TASK 0 /**< */
224#define VIRTIOSCSI_T_TMF_ABORT_TASK_SET 1 /**< */
225#define VIRTIOSCSI_T_TMF_CLEAR_ACA 2 /**< */
226#define VIRTIOSCSI_T_TMF_CLEAR_TASK_SET 3 /**< */
227#define VIRTIOSCSI_T_TMF_I_T_NEXUS_RESET 4 /**< */
228#define VIRTIOSCSI_T_TMF_LOGICAL_UNIT_RESET 5 /**< */
229#define VIRTIOSCSI_T_TMF_QUERY_TASK 6 /**< */
230#define VIRTIOSCSI_T_TMF_QUERY_TASK_SET 7 /**< */
231/*** @} */
232
233typedef struct virtio_scsi_ctrl_tmf
234{
235 // Device-readable part
236 uint32_t uType; /** type */
237 uint32_t uSubtype; /** subtype */
238 uint8_t uLUN[8]; /** lun */
239 uint64_t uId; /** id */
240 // Device-writable part
241 uint8_t uResponse; /** response */
242} VIRTIO_SCSI_CTRL_BUF_T, *PVIRTIO_SCSI_CTRL_BUF_T;
243
244/**
245 * @name VirtIO 1.0 SCSI Host Device device specific tmf control response values
246 * @{ */
247#define VIRTIOSCSI_S_FUNCTION_COMPLETE 0 /**< */
248#define VIRTIOSCSI_S_FUNCTION_SUCCEEDED 10 /**< */
249#define VIRTIOSCSI_S_FUNCTION_REJECTED 11 /**< */
250/** @} */
251
252#define VIRTIOSCSI_T_AN_QUERY 1 /** Asynchronous notification query */
253#define VIRTIOSCSI_T_AN_SUBSCRIBE 2 /** Asynchronous notification subscription */
254
255typedef struct virtio_scsi_ctrl_an
256{
257 // Device-readable part
258 uint32_t uType; /** type */
259 uint8_t uLUN[8]; /** lun */
260 uint32_t uEventRequested; /** event_requested */
261 // Device-writable part
262 uint32_t uEventActual; /** event_actual */
263 uint8_t uResponse; /** response */
264} VIRTIO_SCSI_CTRL_AN, *PVIRTIO_SCSI_CTRL_AN_T;
265
266/**
267 * @name VirtIO 1.0 SCSI Host Device device specific tmf control response values
268 * @{ */
269#define VIRTIOSCSI_EVT_ASYNC_OPERATIONAL_CHANGE 2 /**< */
270#define VIRTIOSCSI_EVT_ASYNC_POWER_MGMT 4 /**< */
271#define VIRTIOSCSI_EVT_ASYNC_EXTERNAL_REQUEST 8 /**< */
272#define VIRTIOSCSI_EVT_ASYNC_MEDIA_CHANGE 16 /**< */
273#define VIRTIOSCSI_EVT_ASYNC_MULTI_HOST 32 /**< */
274#define VIRTIOSCSI_EVT_ASYNC_DEVICE_BUSY 64 /**< */
275/** @} */
276
277/**
278 * State of a target attached to the VirtIO SCSI Host
279 */
280typedef struct VIRTIOSCSITARGET
281{
282 /** Pointer to PCI device that owns this target instance. - R3 pointer */
283 R3PTRTYPE(struct VIRTIOSCSI *) pVirtioScsiR3;
284
285 /** Pointer to attached driver's base interface. */
286 R3PTRTYPE(PPDMIBASE) pDrvBase;
287
288 /** Target LUN */
289 RTUINT iLUN;
290
291 /** Target LUN Description */
292 char * pszLunName;
293
294 /** Target base interface. */
295 PDMIBASE IBase;
296
297 /** Flag whether device is present. */
298 bool fPresent;
299
300 /** Media port interface. */
301 PDMIMEDIAPORT IMediaPort;
302
303 /** Pointer to the attached driver's media interface. */
304 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
305
306 /** Extended media port interface. */
307 PDMIMEDIAEXPORT IMediaExPort;
308
309 /** Pointer to the attached driver's extended media interface. */
310 R3PTRTYPE(PPDMIMEDIAEX) pDrvMediaEx;
311
312 /** Status LED interface */
313 PDMILEDPORTS ILed;
314 /** The status LED state for this device. */
315 PDMLED led;
316
317 /** Number of outstanding tasks on the port. */
318 volatile uint32_t cOutstandingRequests;
319
320} VIRTIOSCSITARGET, *PVIRTIOSCSITARGET;
321
322
323/**
324 * PDM instance data (state) for VirtIO Host SCSI device
325 *
326 * @extends PDMPCIDEV
327 */
328typedef struct VIRTIOSCSI
329{
330 /* Opaque handle to VirtIO common framework (must be first item
331 * in this struct so PDMINS_2_DATA macro's casting works) */
332 VIRTIOHANDLE hVirtio;
333
334 /* SCSI target instances data */
335 VIRTIOSCSITARGET aTargetInstances[VIRTIOSCSI_MAX_TARGETS];
336
337 /** Instance name */
338 const char szInstance[16];
339
340 /** Device-specific spec-based VirtIO queuenames */
341 const char szQueueNames[VIRTIOSCSI_QUEUE_CNT][VIRTIO_MAX_QUEUE_NAME_SIZE];
342
343 /** Track which VirtIO queues we've attached to */
344 bool fQueueAttached[VIRTIOSCSI_QUEUE_CNT];
345
346 /** Device base interface. */
347 PDMIBASE IBase;
348
349 /** Pointer to the device instance. - R3 ptr. */
350 PPDMDEVINSR3 pDevInsR3;
351 /** Pointer to the device instance. - R0 ptr. */
352 PPDMDEVINSR0 pDevInsR0;
353 /** Pointer to the device instance. - RC ptr. */
354 PPDMDEVINSRC pDevInsRC;
355
356 /** Status LUN: LEDs port interface. */
357 PDMILEDPORTS ILeds;
358
359 /** Status LUN: Partner of ILeds. */
360 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
361
362 /** Base address of the memory mapping. */
363 RTGCPHYS GCPhysMMIOBase;
364
365 /** IMediaExPort: Media ejection notification */
366 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
367
368 /** Queue to send tasks to R3. - HC ptr */
369 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
370
371 /** The support driver session handle. */
372 R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession;
373
374 /** Worker thread. */
375 R3PTRTYPE(PPDMTHREAD) pThreadWrk;
376
377 /** The event semaphore the processing thread waits on. */
378 SUPSEMEVENT hEvtProcess;
379
380 /** Number of ports detected */
381 uint64_t cTargets;
382
383 /** True if PDMDevHlpAsyncNotificationCompleted should be called when port goes idle */
384 bool volatile fSignalIdle;
385
386 VIRTIO_SCSI_CONFIG_T virtioScsiConfig;
387
388
389
390} VIRTIOSCSI, *PVIRTIOSCSI;
391
392
393/**
394 * Task state for a CCB request.
395 */
396typedef struct VIRTIOSCSIREQ
397{
398 /** Device this task is assigned to. */
399 PVIRTIOSCSITARGET pTargetDevice;
400 /** The command control block from the guest. */
401// CCBU CCBGuest;
402 /** Guest physical address of th CCB. */
403 RTGCPHYS GCPhysAddrCCB;
404 /** Pointer to the R3 sense buffer. */
405 uint8_t *pbSenseBuffer;
406 /** Flag whether this is a request from the BIOS. */
407 bool fBIOS;
408 /** 24-bit request flag (default is 32-bit). */
409 bool fIs24Bit;
410 /** SCSI status code. */
411 uint8_t u8ScsiSts;
412} VIRTIOSCSIREQ;
413
414/**
415 * This macro resolves to boolean true if uOffset matches a field offset and size exactly,
416 * (or if it is a 64-bit field, if it accesses either 32-bit part as a 32-bit access)
417 * ASSUMED this critereon is mandated by section 4.1.3.1 of the VirtIO 1.0 specification)
418 * This MACRO can be re-written to allow unaligned access to a field (within bounds).
419 *
420 * @param member - Member of VIRTIO_PCI_COMMON_CFG_T
421 * @result - true or false
422 */
423#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)) \
427 && cb == sizeof(uint32_t)) \
428 || (uOffset == RT_UOFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \
429 && cb == RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member))
430
431#define LOG_ACCESSOR(member) \
432 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member), \
433 pv, cb, uIntraOffset, fWrite, false, 0);
434
435#define SCSI_CONFIG_ACCESSOR(member) \
436 { \
437 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \
438 if (fWrite) \
439 memcpy(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset, (const char *)pv, cb); \
440 else \
441 memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \
442 LOG_ACCESSOR(member); \
443 }
444
445#define SCSI_CONFIG_ACCESSOR_READONLY(member) \
446 { \
447 uint32_t uIntraOffset = uOffset - RT_UOFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \
448 if (fWrite) \
449 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \
450 else \
451 { \
452 memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uIntraOffset), cb); \
453 LOG_ACCESSOR(member); \
454 } \
455 }
456
457typedef struct VIRTIOSCSIREQ *PVIRTIOSCSIREQ;
458
459#ifdef BOOTABLE_SUPPORT_TBD
460/** @callback_method_impl{FNIOMIOPORTIN} */
461static DECLCALLBACK(int) virtioScsiR3BiosIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst,
462 uint32_t *pcTransfers, unsigned cb);
463{
464}
465/** @callback_method_impl{FNIOMIOPORTOUT} */
466static DECLCALLBACK(int) virtioScsiR3BiosIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb);
467{
468}
469/** @callback_method_impl{FNIOMIOPORTOUTSTRING} */
470static DECLCALLBACK(int) virtioScsiR3BiosIoPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc,
471 uint32_t *pcTransfers, unsigned cb);
472{
473}
474/** @callback_method_impl{FNIOMIOPORTINSTRING} */
475static DECLCALLBACK(int) virtioScsiR3BiosIoPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst,
476 uint32_t *pcTransfers, unsigned cb);
477{
478}
479#endif
480
481
482
483static 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
507static 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
532static 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));
554}
555
556static DECLCALLBACK(void) virtioScsiQueueNotified(VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx)
557{
558 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 }
567
568 Log2Func(("%s has available data\n", QUEUENAME(qIdx)));
569
570 if (qIdx == CONTROLQ_IDX)
571 virtioScsiHandleControlq(hVirtio, qIdx, QUEUENAME(qIdx));
572 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));
578}
579
580static DECLCALLBACK(void) virtioScsiStatusChanged(VIRTIOHANDLE hVirtio, void *pClient, bool fVirtioReady)
581{
582 Log2Func(("\n"));
583 RT_NOREF(hVirtio);
584 PVIRTIOSCSI pVirtioScsi = (PVIRTIOSCSI)pClient;
585 if (fVirtioReady)
586 Log2Func(("VirtIO ready\n"));
587 else
588 {
589 Log2Func(("VirtIO is resetting\n"));
590 for (int i = 0; i < VIRTIOSCSI_QUEUE_CNT; i++)
591 pVirtioScsi->fQueueAttached[i] = false;
592 }
593}
594
595/**
596 * Implementation invokes this to reset the VirtIO device
597 */
598static 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
605static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pVirtioScsi, uint32_t uOffset,
606 const void *pv, size_t cb, uint8_t fWrite)
607{
608 int rc = VINF_SUCCESS;
609 if (MATCH_SCSI_CONFIG(uNumQueues))
610 {
611 SCSI_CONFIG_ACCESSOR_READONLY(uNumQueues);
612 }
613 else
614 if (MATCH_SCSI_CONFIG(uSegMax))
615 {
616 SCSI_CONFIG_ACCESSOR_READONLY(uSegMax);
617 }
618 else
619 if (MATCH_SCSI_CONFIG(uMaxSectors))
620 {
621 SCSI_CONFIG_ACCESSOR_READONLY(uMaxSectors);
622 }
623 else
624 if (MATCH_SCSI_CONFIG(uCmdPerLun))
625 {
626 SCSI_CONFIG_ACCESSOR_READONLY(uCmdPerLun);
627 }
628 else
629 if (MATCH_SCSI_CONFIG(uEventInfoSize))
630 {
631 SCSI_CONFIG_ACCESSOR_READONLY(uEventInfoSize);
632 }
633 else
634 if (MATCH_SCSI_CONFIG(uSenseSize))
635 {
636 SCSI_CONFIG_ACCESSOR(uSenseSize);
637 }
638 else
639 if (MATCH_SCSI_CONFIG(uCdbSize))
640 {
641 SCSI_CONFIG_ACCESSOR(uCdbSize);
642 }
643 else
644 if (MATCH_SCSI_CONFIG(uMaxChannel))
645 {
646 SCSI_CONFIG_ACCESSOR_READONLY(uMaxChannel);
647 }
648 else
649 if (MATCH_SCSI_CONFIG(uMaxTarget))
650 {
651 SCSI_CONFIG_ACCESSOR_READONLY(uMaxTarget);
652 }
653 else
654 if (MATCH_SCSI_CONFIG(uMaxLun))
655 {
656 SCSI_CONFIG_ACCESSOR_READONLY(uMaxLun);
657 }
658 else
659 {
660 LogFunc(("Bad access by guest to virtio_scsi_config: uoff=%d, cb=%d\n", uOffset, cb));
661 rc = VERR_ACCESS_DENIED;
662 }
663 return rc;
664}
665
666/**
667 * virtio-scsi VirtIO Device-specific capabilities read callback
668 * (other VirtIO capabilities and features are handled in VirtIO implementation)
669 *
670 * @param pDevIns The device instance.
671 * @param uOffset Offset within device specific capabilities struct
672 * @param pv Buffer in which to save read data
673 * @param cb Number of bytes to read
674 */
675static DECLCALLBACK(int) virtioScsiR3DevCapRead(PPDMDEVINS pDevIns, uint32_t uOffset, const void *pv, size_t cb)
676{
677 int rc = VINF_SUCCESS;
678 PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
679
680// LogFunc(("Read from Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
681// uOffset, cb));
682
683 rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, false);
684
685 return rc;
686}
687
688/**
689 * virtio-scsi VirtIO Device-specific capabilities read callback
690 * (other VirtIO capabilities and features are handled in VirtIO implementation)
691 *
692 * @param pDevIns The device instance.
693 * @param uOffset Offset within device specific capabilities struct
694 * @param pv Buffer in which to save read data
695 * @param cb Number of bytes to write
696 */
697static DECLCALLBACK(int) virtioScsiR3DevCapWrite(PPDMDEVINS pDevIns, uint32_t uOffset, const void *pv, size_t cb)
698{
699 int rc = VINF_SUCCESS;
700 PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
701
702// LogFunc(("Write to Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n",
703// uOffset, cb));
704
705 rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, true);
706
707 return rc;
708}
709
710
711/**
712 * Turns on/off the write status LED.
713 *
714 * @param pTarget Pointer to the target device
715 * @param fOn New LED state.
716 */
717void virtioScsiSetWriteLed(PVIRTIOSCSITARGET pTarget, bool fOn)
718{
719 LogFlow(("%s virtioSetWriteLed: %s\n", pTarget->pszLunName, fOn ? "on" : "off"));
720 if (fOn)
721 pTarget->led.Asserted.s.fWriting = pTarget->led.Actual.s.fWriting = 1;
722 else
723 pTarget->led.Actual.s.fWriting = fOn;
724}
725
726/**
727 * Turns on/off the read status LED.
728 *
729 * @param pTarget Pointer to the device state structure.
730 * @param fOn New LED state.
731 */
732void virtioScsiSetReadLed(PVIRTIOSCSITARGET pTarget, bool fOn)
733{
734 LogFlow(("%s virtioSetReadLed: %s\n", pTarget->pszLunName, fOn ? "on" : "off"));
735 if (fOn)
736 pTarget->led.Asserted.s.fReading = pTarget->led.Actual.s.fReading = 1;
737 else
738 pTarget->led.Actual.s.fReading = fOn;
739}
740
741/**
742 * virtio-scsi debugger info callback.
743 *
744 * @param pDevIns The device instance.
745 * @param pHlp The output helpers.
746 * @param pszArgs The arguments.
747 */
748static DECLCALLBACK(void) virtioScsiR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
749{
750 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
751 bool fVerbose = false;
752
753 /* Parse arguments. */
754 if (pszArgs)
755 fVerbose = strstr(pszArgs, "verbose") != NULL;
756
757 /* Show basic information. */
758 pHlp->pfnPrintf(pHlp, "%s#%d: virtio-scsci ",
759 pDevIns->pReg->szName,
760 pDevIns->iInstance);
761 pHlp->pfnPrintf(pHlp, "numTargets=%lu", pThis->cTargets);
762}
763
764/** @callback_method_impl{FNSSMDEVLIVEEXEC} */
765static DECLCALLBACK(int) virtioScsiR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
766{
767 LogFunc(("callback"));
768 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
769 RT_NOREF(pThis);
770 RT_NOREF(uPass);
771 RT_NOREF(pSSM);
772 return VINF_SSM_DONT_CALL_AGAIN;
773}
774
775/** @callback_method_impl{FNSSMDEVLOADEXEC} */
776static DECLCALLBACK(int) virtioScsiR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
777{
778 LogFunc(("callback"));
779 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
780 RT_NOREF(pThis);
781 RT_NOREF(uPass);
782 RT_NOREF(pSSM);
783 RT_NOREF(uVersion);
784 return VINF_SSM_DONT_CALL_AGAIN;
785}
786
787/** @callback_method_impl{FNSSMDEVSAVEEXEC} */
788static DECLCALLBACK(int) virtioScsiR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
789{
790 LogFunc(("callback"));
791 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
792 RT_NOREF(pThis);
793 RT_NOREF(pSSM);
794 return VINF_SUCCESS;
795}
796
797/** @callback_method_impl{FNSSMDEVLOADDONE} */
798static DECLCALLBACK(int) virtioScsiR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
799{
800 LogFunc(("callback"));
801 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
802 RT_NOREF(pThis);
803 RT_NOREF(pSSM);
804 return VINF_SUCCESS;
805}
806
807/**
808 * @copydoc FNPDMDEVRESET
809 */
810static DECLCALLBACK(void) virtioScsiR3PDMReset(PPDMDEVINS pDevIns)
811{
812 PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
813 virtioScsiDeviceReset(pVirtioScsi);
814
815// ASMAtomicWriteBool(&pThis->fSignalIdle, true);
816// if (!virtioScsiR3AllAsyncIOIsFinished(pDevIns))
817// PDMDevHlpSetAsyncNotification(pDevIns, virtioScsiR3IsAsyncResetDone);
818// else
819// {
820// ASMAtomicWriteBool(&pThis->fSignalIdle, false);
821// }
822
823}
824
825/**
826 * Device relocation callback.
827 *
828 * When this callback is called the device instance data, and if the
829 * device have a GC component, is being relocated, or/and the selectors
830 * have been changed. The device must use the chance to perform the
831 * necessary pointer relocations and data updates.
832 *
833 * Before the GC code is executed the first time, this function will be
834 * called with a 0 delta so GC pointer calculations can be one in one place.
835 *
836 * @param pDevIns Pointer to the device instance.
837 * @param offDelta The relocation delta relative to the old location.
838 *
839 * @remark A relocation CANNOT fail.
840 */
841static DECLCALLBACK(void) virtioScsiR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
842{
843 LogFunc(("Relocating virtio-scsi"));
844 RT_NOREF(offDelta);
845 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
846
847 pThis->pDevInsR3 = pDevIns;
848
849 for (uint32_t i = 0; i < VIRTIOSCSI_MAX_TARGETS; i++)
850 {
851 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[i];
852 pTarget->pVirtioScsiR3 = pThis;;
853 }
854
855 /**
856 * Important: Forward to virtio framework!
857 */
858 virtioRelocate(pDevIns, offDelta);
859
860}
861
862static DECLCALLBACK(int) virtioScsiR3QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
863 uint32_t *piInstance, uint32_t *piLUN)
864{
865 PVIRTIOSCSITARGET pVirtioScsiTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaPort);
866 PPDMDEVINS pDevIns = pVirtioScsiTarget->CTX_SUFF(pVirtioScsi)->CTX_SUFF(pDevIns);
867
868 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
869 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
870 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
871
872 *ppcszController = pDevIns->pReg->szName;
873 *piInstance = pDevIns->iInstance;
874 *piLUN = pVirtioScsiTarget->iLUN;
875
876 return VINF_SUCCESS;
877}
878
879/**
880 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
881 */
882static DECLCALLBACK(int) virtioScsiR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
883 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
884 size_t cbCopy)
885{
886 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
887 PVIRTIOSCSIREQ pReq = (PVIRTIOSCSIREQ)pvIoReqAlloc;
888 size_t cbCopied = 0;
889 RT_NOREF(pTarget);
890 RT_NOREF(pReq);
891 RT_NOREF(pInterface);
892 RT_NOREF(pvIoReqAlloc);
893 RT_NOREF(offDst);
894 RT_NOREF(pSgBuf);
895 RT_NOREF(hIoReq);
896 RT_NOREF(cbCopy);
897 RT_NOREF(cbCopied);
898
899/*
900 if (RT_UNLIKELY(pReq->fBIOS))
901 cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offDst, cbCopy);
902 else
903 cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offDst, cbCopy);
904 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
905*/
906 return 0; /* placeholder */
907}
908
909/**
910 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
911 */
912static DECLCALLBACK(int) virtioScsiR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
913 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
914 size_t cbCopy)
915{
916 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
917 PVIRTIOSCSIREQ pReq = (PVIRTIOSCSIREQ)pvIoReqAlloc;
918 size_t cbCopied = 0;
919 RT_NOREF(pTarget);
920 RT_NOREF(pReq);
921 RT_NOREF(pInterface);
922 RT_NOREF(pvIoReqAlloc);
923 RT_NOREF(offSrc);
924 RT_NOREF(pSgBuf);
925 RT_NOREF(hIoReq);
926 RT_NOREF(cbCopy);
927 RT_NOREF(cbCopied);
928
929/*
930 if (RT_UNLIKELY(pReq->fBIOS))
931 cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offSrc, cbCopy);
932 else
933 cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offSrc, cbCopy);
934 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
935*/
936 return 0; /* placeholder */
937
938}
939
940/**
941 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
942 */
943static DECLCALLBACK(int) virtioScsiR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
944 void *pvIoReqAlloc, int rcReq)
945{
946 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
947 RT_NOREF(pTarget);
948 RT_NOREF(pInterface);
949 RT_NOREF(pvIoReqAlloc);
950 RT_NOREF(rcReq);
951 RT_NOREF(hIoReq);
952// virtioScsiR3ReqComplete(pTarget->CTX_SUFF(pVirtioScsi), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
953 return VINF_SUCCESS;
954}
955
956/**
957 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
958 */
959static DECLCALLBACK(void) virtioScsiR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
960 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
961{
962
963 RT_NOREF4(pInterface, hIoReq, pvIoReqAlloc, enmState);
964 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
965
966 switch (enmState)
967 {
968 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
969 {
970 /* Make sure the request is not accounted for so the VM can suspend successfully. */
971 uint32_t cTasksActive = ASMAtomicDecU32(&pTarget->cOutstandingRequests);
972 if (!cTasksActive && pTarget->CTX_SUFF(pVirtioScsi)->fSignalIdle)
973 PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(pVirtioScsi)->pDevInsR3);
974 break;
975 }
976 case PDMMEDIAEXIOREQSTATE_ACTIVE:
977 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
978 ASMAtomicIncU32(&pTarget->cOutstandingRequests);
979 break;
980 default:
981 AssertMsgFailed(("Invalid request state given %u\n", enmState));
982 }
983}
984
985/**
986 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
987 */
988static DECLCALLBACK(void) virtioScsiR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
989{
990 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
991 PVIRTIOSCSI pThis = pTarget->CTX_SUFF(pVirtioScsi);
992
993 if (pThis->pMediaNotify)
994 virtioScsiSetWriteLed(pTarget, false);
995}
996
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 */
1006static 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
1017
1018/**
1019 * Gets the pointer to the status LED of a unit.
1020 *
1021 * @returns VBox status code.
1022 * @param pInterface Pointer to the interface structure containing the called function pointer.
1023 * @param iLUN The unit which status LED we desire.
1024 * @param ppLed Where to store the LED pointer.
1025 */
1026static DECLCALLBACK(int) virtioScsiR3TargetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
1027{
1028 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, ILed);
1029 if (iLUN == 0)
1030 {
1031 *ppLed = &pTarget->led;
1032 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
1033 return VINF_SUCCESS;
1034 }
1035 return VERR_PDM_LUN_NOT_FOUND;
1036 }
1037
1038
1039/**
1040 * Gets the pointer to the status LED of a unit.
1041 *
1042 * @returns VBox status code.
1043 * @param pInterface Pointer to the interface structure containing the called function pointer.
1044 * @param iLUN The unit which status LED we desire.
1045 * @param ppLed Where to store the LED pointer.
1046 */
1047static DECLCALLBACK(int) virtioScsiR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
1048{
1049 PVIRTIOSCSI pThis = RT_FROM_MEMBER(pInterface, VIRTIOSCSI, ILeds);
1050 if (iLUN < pThis->cTargets)
1051 {
1052 *ppLed = &pThis->aTargetInstances[iLUN].led;
1053 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
1054 return VINF_SUCCESS;
1055 }
1056 return VERR_PDM_LUN_NOT_FOUND;
1057}
1058
1059
1060/**
1061 * Memory mapped I/O Handler for read operations.
1062 *
1063 * @returns VBox status code.
1064 *
1065 * @param pDevIns The device instance.
1066 * @param pvUser User argument.
1067 * @param GCPhysAddr Physical address (in GC) where the read starts.
1068 * @param pv Where to store the result.
1069 * @param cb Number of bytes read.
1070 */
1071PDMBOTHCBDECL(int) virtioScsiMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1072{
1073 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
1074 LogFunc(("Read from MMIO area\n"));
1075 return VINF_SUCCESS;
1076}
1077
1078/**
1079 * Memory mapped I/O Handler for write operations.
1080 *
1081 * @returns VBox status code.
1082 *
1083 * @param pDevIns The device instance.
1084 * @param pvUser User argument.
1085 * @param GCPhysAddr Physical address (in GC) where the read starts.
1086 * @param pv Where to fetch the result.
1087 * @param cb Number of bytes to write.
1088 */
1089PDMBOTHCBDECL(int) virtioScsiMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1090{
1091 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
1092 LogFunc(("Write to MMIO area\n"));
1093 return VINF_SUCCESS;
1094}
1095
1096/**
1097 * @callback_method_impl{FNPCIIOREGIONMAP}
1098 */
1099static DECLCALLBACK(int) virtioScsiR3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
1100 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
1101{
1102 RT_NOREF(pPciDev, iRegion);
1103 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
1104 int rc = VINF_SUCCESS;
1105
1106 Assert(cb >= 32);
1107
1108 switch (iRegion)
1109 {
1110 case 0:
1111 LogFunc(("virtio-scsi MMIO mapped at GCPhysAddr=%RGp cb=%RGp\n", GCPhysAddress, cb));
1112
1113 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
1114 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
1115 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1116 virtioScsiMMIOWrite, virtioScsiMMIORead,
1117 "virtio-scsi MMIO");
1118 pThis->GCPhysMMIOBase = RT_SUCCESS(rc) ? GCPhysAddress : 0;
1119 return rc;
1120 case 1:
1121 /* VirtIO 1.0 doesn't uses Port I/O (Virtio 0.95 e.g. "legacy", does) */
1122 AssertMsgFailed(("virtio-scsi: Port I/O not supported by this Host SCSI device\n"));
1123 default:
1124 AssertMsgFailed(("Invalid enmType=%d\n", enmType));
1125 }
1126 return VERR_GENERAL_FAILURE; /* Should never get here */
1127}
1128
1129/**
1130 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1131 */
1132static DECLCALLBACK(void *) virtioScsiR3TargetQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1133{
1134 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IBase);
1135 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pTarget->IBase);
1136 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pTarget->IMediaPort);
1137 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pTarget->IMediaExPort);
1138 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pTarget->ILed);
1139 return NULL;
1140}
1141
1142/**
1143 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1144 */
1145static DECLCALLBACK(void *) virtioScsiR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1146{
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);
1151
1152 return NULL;
1153}
1154
1155/**
1156 * Detach notification.
1157 *
1158 * One harddisk at one port has been unplugged.
1159 * The VM is suspended at this point.
1160 *
1161 * @param pDevIns The device instance.
1162 * @param iLUN The logical unit which is being detached.
1163 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1164 */
1165static DECLCALLBACK(void) virtioScsiR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1166{
1167 RT_NOREF(fFlags);
1168 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
1169 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
1170
1171 LogFunc((""));
1172
1173 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1174 ("virtio-scsi: Device does not support hotplugging\n"));
1175
1176 /*
1177 * Zero some important members.
1178 */
1179 pTarget->fPresent = false;
1180 pTarget->pDrvBase = NULL;
1181}
1182
1183/**
1184 * Attach command.
1185 *
1186 * This is called when we change block driver.
1187 *
1188 * @returns VBox status code.
1189 * @param pDevIns The device instance.
1190 * @param iLUN The logical unit which is being detached.
1191 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1192 */
1193static DECLCALLBACK(int) virtioScsiR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1194{
1195 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
1196 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
1197 int rc;
1198
1199 pThis->pDevInsR3 = pDevIns;
1200 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1201 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1202
1203 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1204 ("virtio-scsi: Device does not support hotplugging\n"),
1205 VERR_INVALID_PARAMETER);
1206
1207 /* the usual paranoia */
1208 AssertRelease(!pTarget->pDrvBase);
1209 Assert(pTarget->iLUN == iLUN);
1210
1211 /*
1212 * Try attach the SCSI driver and get the interfaces,
1213 * required as well as optional.
1214 */
1215 rc = PDMDevHlpDriverAttach(pDevIns, pTarget->iLUN, &pDevIns->IBase,
1216 &pTarget->pDrvBase, (const char *)&pTarget->pszLunName);
1217 if (RT_SUCCESS(rc))
1218 pTarget->fPresent = true;
1219 else
1220 AssertMsgFailed(("Failed to attach %s. rc=%Rrc\n", pTarget->pszLunName, rc));
1221
1222 if (RT_FAILURE(rc))
1223 {
1224 pTarget->fPresent = false;
1225 pTarget->pDrvBase = NULL;
1226 }
1227 return rc;
1228}
1229
1230static DECLCALLBACK(int) virtioScsiDestruct(PPDMDEVINS pDevIns)
1231{
1232 /*
1233 * Check the versions here as well since the destructor is *always* called.
1234 */
1235 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1236 return VINF_SUCCESS;
1237}
1238
1239static DECLCALLBACK(int) virtioScsiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg){
1240
1241 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1242
1243 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
1244 int rc = VINF_SUCCESS;
1245 bool fBootable = false;
1246
1247 pThis->pDevInsR3 = pDevIns;
1248 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1249 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1250
1251 LogFunc(("PDM device instance: %d\n", iInstance));
1252 RTStrPrintf((char *)pThis->szInstance, sizeof(pThis->szInstance), "VIRTIOSCSI%d", iInstance);
1253
1254 /*
1255 * Validate and read configuration.
1256 */
1257 if (!CFGMR3AreValuesValid(pCfg,"NumTargets\0"
1258 "Bootable\0"
1259 /* "GCEnabled\0" TBD */
1260 /* "R0Enabled\0" TBD */
1261 ))
1262 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1263 N_("virtio-scsi configuration error: unknown option specified"));
1264
1265 rc = CFGMR3QueryIntegerDef(pCfg, "NumTargets", &pThis->cTargets, true);
1266 if (RT_FAILURE(rc))
1267 return PDMDEV_SET_ERROR(pDevIns, rc,
1268 N_("virtio-scsi configuration error: failed to read NumTargets as integer"));
1269 LogFunc(("NumTargets=%d\n", pThis->cTargets));
1270
1271 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &fBootable, true);
1272 if (RT_FAILURE(rc))
1273 return PDMDEV_SET_ERROR(pDevIns, rc,
1274 N_("virtio-scsi configuration error: failed to read Bootable as boolean"));
1275 LogFunc(("Bootable=%RTbool (unimplemented)\n", fBootable));
1276
1277 VIRTIOPCIPARAMS virtioPciParams, *pVirtioPciParams = &virtioPciParams;
1278 pVirtioPciParams->uDeviceId = PCI_DEVICE_ID_VIRTIOSCSI_HOST;
1279 pVirtioPciParams->uClassBase = PCI_CLASS_BASE_MASS_STORAGE;
1280 pVirtioPciParams->uClassSub = PCI_CLASS_SUB_SCSI_STORAGE_CONTROLLER;
1281 pVirtioPciParams->uClassProg = PCI_CLASS_PROG_UNSPECIFIED;
1282 pVirtioPciParams->uSubsystemId = PCI_DEVICE_ID_VIRTIOSCSI_HOST; /* Virtio 1.0 spec allows PCI Device ID here */
1283 pVirtioPciParams->uInterruptLine = 0x00;
1284 pVirtioPciParams->uInterruptPin = 0x01;
1285
1286 pThis->IBase.pfnQueryInterface = virtioScsiR3DeviceQueryInterface;
1287
1288 /* Configure virtio_scsi_config that transacts via VirtIO implementation's Dev. Specific Cap callbacks */
1289 pThis->virtioScsiConfig.uNumQueues = VIRTIOSCSI_REQ_QUEUE_CNT;
1290 pThis->virtioScsiConfig.uSegMax = VIRTIOSCSI_MAX_SEG_COUNT;
1291 pThis->virtioScsiConfig.uMaxSectors = VIRTIOSCSI_MAX_SECTORS_HINT;
1292 pThis->virtioScsiConfig.uCmdPerLun = VIRTIOSCSI_MAX_COMMANDS_PER_LUN;
1293 pThis->virtioScsiConfig.uEventInfoSize = sizeof(VIRTIO_SCSI_EVENT_T); /* Spec says at least this size! */
1294 pThis->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT;
1295 pThis->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT;
1296 pThis->virtioScsiConfig.uMaxChannel = VIRTIOSCSI_MAX_CHANNEL_HINT;
1297 pThis->virtioScsiConfig.uMaxTarget = pThis->cTargets;
1298 pThis->virtioScsiConfig.uMaxLun = VIRTIOSCSI_MAX_LUN;
1299
1300 rc = virtioConstruct(pDevIns, pThis, &pThis->hVirtio, pVirtioPciParams, pThis->szInstance,
1301 VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED,
1302 virtioScsiR3DevCapRead,
1303 virtioScsiR3DevCapWrite,
1304 virtioScsiStatusChanged,
1305 virtioScsiQueueNotified,
1306 virtioScsiR3LiveExec,
1307 virtioScsiR3SaveExec,
1308 virtioScsiR3LoadExec,
1309 virtioScsiR3LoadDone,
1310 sizeof(VIRTIO_SCSI_CONFIG_T) /* cbDevSpecificCap */,
1311 (void *)&pThis->virtioScsiConfig /* pDevSpecificCap */);
1312
1313 if (RT_FAILURE(rc))
1314 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO"));
1315
1316 RTStrCopy((char *)pThis->szQueueNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
1317 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);
1320
1321 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_MEM_IO, 32,
1322 PCI_ADDRESS_SPACE_MEM, virtioScsiR3Map);
1323 if (RT_FAILURE(rc))
1324 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: cannot register PCI mmio address space"));
1325
1326#ifdef BOOTABLE_SUPPORT_TBD
1327 if (fBootable)
1328 {
1329 /* Register I/O port space for BIOS access. */
1330 rc = PDMDevHlpIOPortRegister(pDevIns, VIRTIOSCSI_BIOS_IO_PORT, 4, NULL,
1331 virtioScsiR3BiosIoPortWrite, virtioScsiR3BiosIoPortRead,
1332 virtioScsiR3BiosIoPortWriteStr, virtioScsiR3BiosIoPortReadStr,
1333 "virtio-scsi BIOS");
1334 if (RT_FAILURE(rc))
1335 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi cannot register BIOS I/O handlers"));
1336 }
1337#endif
1338
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 /* Initialize per device instance. */
1346 for (RTUINT iLUN = 0; iLUN < VIRTIOSCSI_MAX_TARGETS; iLUN++)
1347 {
1348 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
1349
1350 if (RTStrAPrintf(&pTarget->pszLunName, "VSCSILUN%u", iLUN) < 0)
1351 AssertLogRelFailedReturn(VERR_NO_MEMORY);
1352
1353 /* Initialize static parts of the device. */
1354 pTarget->iLUN = iLUN;
1355 pTarget->pVirtioScsiR3 = pThis;
1356
1357 pTarget->IBase.pfnQueryInterface = virtioScsiR3TargetQueryInterface;
1358
1359 /* IMediaPort and IMediaExPort interfaces provide callbacks for VD media and downstream driver access */
1360 pTarget->IMediaPort.pfnQueryDeviceLocation = virtioScsiR3QueryDeviceLocation;
1361 pTarget->IMediaExPort.pfnIoReqCompleteNotify = virtioScsiR3IoReqCompleteNotify;
1362 pTarget->IMediaExPort.pfnIoReqCopyFromBuf = virtioScsiR3IoReqCopyFromBuf;
1363 pTarget->IMediaExPort.pfnIoReqCopyToBuf = virtioScsiR3IoReqCopyToBuf;
1364 pTarget->IMediaExPort.pfnIoReqStateChanged = virtioScsiR3IoReqStateChanged;
1365 pTarget->IMediaExPort.pfnMediumEjected = virtioScsiR3MediumEjected;
1366 pTarget->IMediaExPort.pfnIoReqQueryBuf = NULL;
1367 pTarget->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
1368 pTarget->IBase.pfnQueryInterface = virtioScsiR3TargetQueryInterface;
1369 pTarget->ILed.pfnQueryStatusLed = virtioScsiR3TargetQueryStatusLed;
1370 pThis->ILeds.pfnQueryStatusLed = virtioScsiR3DeviceQueryStatusLed;
1371 pTarget->led.u32Magic = PDMLED_MAGIC;
1372
1373 LogFunc(("Attaching LUN: %s\n", pTarget->pszLunName));
1374
1375 AssertReturn(iLUN < RT_ELEMENTS(pThis->aTargetInstances), VERR_PDM_NO_SUCH_LUN);
1376 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pTarget->IBase, &pTarget->pDrvBase, (const char *)&pTarget->pszLunName);
1377 if (RT_SUCCESS(rc))
1378 {
1379 pTarget->fPresent = true;
1380
1381 /* DrvSCSI.cpp currently implements the IMedia and IMediaEx interfaces, so those
1382 * are the interfaces that will be used to pass SCSI requests down to the
1383 * DrvSCSI driver to eventually make it down to the VD layer */
1384 pTarget->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pTarget->pDrvBase, PDMIMEDIA);
1385 AssertMsgReturn(VALID_PTR(pTarget->pDrvMedia),
1386 ("virtio-scsi configuration error: LUN#%d missing basic media interface!\n", pTarget->iLUN),
1387 VERR_PDM_MISSING_INTERFACE);
1388
1389 /* Get the extended media interface. */
1390 pTarget->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pTarget->pDrvBase, PDMIMEDIAEX);
1391 AssertMsgReturn(VALID_PTR(pTarget->pDrvMediaEx),
1392 ("virtio-scsi configuration error: LUN#%d missing extended media interface!\n", pTarget->iLUN),
1393 VERR_PDM_MISSING_INTERFACE);
1394
1395 rc = pTarget->pDrvMediaEx->pfnIoReqAllocSizeSet(pTarget->pDrvMediaEx, REQ_ALLOC_SIZE /*TBD*/);
1396 AssertMsgReturn(VALID_PTR(pTarget->pDrvMediaEx),
1397 ("virtio-scsi configuration error: LUN#%u: Failed to set I/O request size!\n", pTarget->iLUN),
1398 rc);
1399
1400 }
1401 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1402 {
1403 pTarget->fPresent = false;
1404 pTarget->pDrvBase = NULL;
1405 rc = VINF_SUCCESS;
1406 Log(("virtio-scsi: no driver attached to device %s\n", pTarget->pszLunName));
1407 }
1408 else
1409 {
1410 AssertLogRelMsgFailed(("virtio-scsi: Failed to attach %s\n", pTarget->pszLunName));
1411 return rc;
1412 }
1413 }
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
1423 /* Status driver */
1424 PPDMIBASE pUpBase;
1425 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pUpBase, "Status Port");
1426 if (RT_FAILURE(rc))
1427 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
1428
1429 /*
1430 * Register the debugger info callback.
1431 */
1432 char szTmp[128];
1433 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
1434 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "virtio-scsi info", virtioScsiR3Info);
1435
1436 return rc;
1437}
1438
1439/**
1440 * The device registration structure.
1441 */
1442const PDMDEVREG g_DeviceVirtioSCSI =
1443{
1444 /* u32Version */
1445 PDM_DEVREG_VERSION,
1446 /* szName */
1447 "virtio-scsi",
1448 /* szRCMod */
1449 "VBoxDDRC.rc",
1450 /* szR0Mod */
1451 "VBoxDDR0.r0",
1452 /* pszDescription */
1453 "Virtio Host SCSI.\n",
1454 /* fFlags */
1455#ifdef VIRTIOSCSI_GC_SUPPORT
1456 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1457#else
1458 PDM_DEVREG_FLAGS_DEFAULT_BITS,
1459#endif
1460 /* fClass */
1461 PDM_DEVREG_CLASS_MISC,
1462 /* cMaxInstances */
1463 ~0U,
1464 /* cbInstance */
1465 sizeof(VIRTIOSCSI),
1466 /* pfnConstruct */
1467 virtioScsiConstruct,
1468 /* pfnDestruct */
1469 virtioScsiDestruct,
1470 /* pfnRelocate */
1471 virtioScsiR3Relocate,
1472 /* pfnMemSetup */
1473 NULL,
1474 /* pfnPowerOn */
1475 NULL,
1476 /* pfnReset */
1477 virtioScsiR3PDMReset,
1478 /* pfnSuspend */
1479 NULL,
1480 /* pfnResume */
1481 NULL,
1482 /* pfnAttach */
1483 virtioScsiR3Attach,
1484 /* pfnDetach */
1485 virtioScsiR3Detach,
1486 /* pfnQueryInterface */
1487 NULL,
1488 /* pfnInitComplete */
1489 NULL,
1490 /* pfnPowerOff */
1491 NULL,
1492 /* pfnSoftReset */
1493 NULL,
1494 /* u32VersionEnd */
1495 PDM_DEVREG_VERSION
1496};
Note: See TracBrowser for help on using the repository browser.

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