VirtualBox

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

Last change on this file since 80108 was 80108, checked in by vboxsync, 5 years ago

Implemented virtio_pci_cfg_cap interface of VirtIO 1.0 spec, section 4.1.4.7. (See #9440, Comment #40)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.3 KB
Line 
1/* $Id: DevVirtioSCSI.cpp 80108 2019-08-01 20:24:22Z vboxsync $ $Revision: 80108 $ $Date: 2019-08-01 20:24:22 +0000 (Thu, 01 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#define VIRTIOSCSI_MAX_TARGETS 1
47#define VIRTIOSCSI_SAVED_STATE_MINOR_VERSION 0x01
48#define REQ_ALLOC_SIZE 1024 /* TBD */
49
50#define PCI_VENDOR_ID_VIRTIO 0x1AF4
51#define PCI_DEVICE_ID_VIRTIOSCSI_HOST 0x1048
52#define PCI_CLASS_BASE_MASS_STORAGE 0x01
53#define PCI_CLASS_SUB_SCSI_STORAGE_CONTROLLER 0x00
54#define PCI_CLASS_PROG_UNSPECIFIED 0x00
55#define VIRTIOSCSI_NAME_FMT "VIRTIOSCSI%d" /* "VSCSI" *might* be ambiguous with VBoxSCSI? */
56#define VIRTIOSCSI_PCI_CLASS 0x01 /* Base class Mass Storage? */
57#define VIRTIOSCSI_N_QUEUES 3 /* Control, Event, Request */
58#define VIRTIOSCSI_REGION_MEM_IO 0
59#define VIRTIOSCSI_REGION_PORT_IO 1
60#define VIRTIOSCSI_REGION_PCI_CAP 2
61
62/**
63 * Definitions that follow are based on the VirtIO 1.0 specification.
64 * Struct names are the same. The field names have been adapted to VirtualBox
65 * data type + camel case annotation, with the original field name from the
66 * VirtIO specification in the field's comment.
67 */
68
69/** @name VirtIO 1.0 SCSI Host feature bits
70 * @{ */
71#define VIRTIOSCSI_F_INOUT RT_BIT_64(0) /** Request is device readable AND writeable */
72#define VIRTIOSCSI_F_HOTPLUG RT_BIT_64(1) /** Host SHOULD allow hotplugging SCSI LUNs & targets */
73#define VIRTIOSCSI_F_CHANGE RT_BIT_64(2) /** Host reports LUN changes via VIRTIOSCSI_T_PARAM_CHANGE event */
74#define VIRTIOSCSI_F_T10_PI RT_BIT_64(3) /** Ext. flds for T10 prot info (DIF/DIX) in SCSI req hdr */
75/** @} */
76
77/**
78 * Features VirtIO 1.0 Host SCSI controller offers guest driver
79 */
80#define VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED VIRTIOSCSI_F_INOUT \
81 | VIRTIOSCSI_F_HOTPLUG \
82 | VIRTIOSCSI_F_CHANGE \
83 | VIRTIOSCSI_F_T10_PI \
84
85typedef struct VIRTIO_PCI_DEV_CAP_T
86{
87 uint32_t uTestField1;
88 uint32_t uTestField2;
89} VIRTIO_PCI_DEV_CAP_T, *PVIRTIO_PCI_DEV_CAP_T;
90
91/**
92 * State of a target attached to the VirtIO SCSI Host
93 */
94typedef struct VIRTIOSCSITARGET
95{
96 /** Pointer to PCI device that owns this target instance. - R3 pointer */
97 R3PTRTYPE(struct VIRTIOSCSI *) pVirtioScsiR3;
98
99 /** Pointer to attached driver's base interface. */
100 R3PTRTYPE(PPDMIBASE) pDrvBase;
101
102 /** Target LUN */
103 RTUINT iLUN;
104
105 /** Target LUN Description */
106 char * pszLunName;
107
108 /** Target base interface. */
109 PDMIBASE IBase;
110
111 /** Flag whether device is present. */
112 bool fPresent;
113
114
115 /** Media port interface. */
116 PDMIMEDIAPORT IMediaPort;
117 /** Pointer to the attached driver's media interface. */
118 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
119
120
121 /** Extended media port interface. */
122 PDMIMEDIAEXPORT IMediaExPort;
123 /** Pointer to the attached driver's extended media interface. */
124 R3PTRTYPE(PPDMIMEDIAEX) pDrvMediaEx;
125
126
127 /** Status LED interface */
128 PDMILEDPORTS ILed;
129 /** The status LED state for this device. */
130 PDMLED led;
131
132 /** Number of outstanding tasks on the port. */
133 volatile uint32_t cOutstandingRequests;
134
135 R3PTRTYPE(PVQUEUE) pCtlQueue; // ? TBD
136 R3PTRTYPE(PVQUEUE) pEvtQueue; // ? TBD
137 R3PTRTYPE(PVQUEUE) pReqQueue; // ? TBD
138
139} VIRTIOSCSITARGET, *PVIRTIOSCSITARGET;
140
141
142/**
143 * PDM instance data (state) for VirtIO Host SCSI device
144 *
145 * @extends PDMPCIDEV
146 */
147typedef struct VIRTIOSCSI
148{
149 /* virtioState must be first member */
150 VIRTIOSTATE virtioState;
151
152 VIRTIO_PCI_DEV_CAP_T devSpecificCap;
153
154 /* SCSI target instances data */
155 VIRTIOSCSITARGET aTargetInstances[VIRTIOSCSI_MAX_TARGETS];
156
157 /** Device base interface. */
158 PDMIBASE IBase;
159
160 /** Pointer to the device instance. - R3 ptr. */
161 PPDMDEVINSR3 pDevInsR3;
162 /** Pointer to the device instance. - R0 ptr. */
163 PPDMDEVINSR0 pDevInsR0;
164 /** Pointer to the device instance. - RC ptr. */
165 PPDMDEVINSRC pDevInsRC;
166
167 /** Status LUN: LEDs port interface. */
168 PDMILEDPORTS ILeds;
169
170 /** Status LUN: Partner of ILeds. */
171 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
172
173 /** Base address of the memory mapping. */
174 RTGCPHYS GCPhysMMIOBase;
175
176 /** IMediaExPort: Media ejection notification */
177 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
178
179 /** Queue to send tasks to R3. - HC ptr */
180 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
181
182 /** The support driver session handle. */
183 R3R0PTRTYPE(PSUPDRVSESSION) pSupDrvSession;
184
185 /** Worker thread. */
186 R3PTRTYPE(PPDMTHREAD) pThreadWrk;
187
188 /** The event semaphore the processing thread waits on. */
189 SUPSEMEVENT hEvtProcess;
190
191 /** Number of ports detected */
192 uint64_t cTargets;
193
194 /** True if PDMDevHlpAsyncNotificationCompleted should be called when port goes idle */
195 bool volatile fSignalIdle;
196
197} VIRTIOSCSI, *PVIRTIOSCSI;
198
199
200
201//pk: Needed for virtioIO (e.g. to talk to devSCSI? TBD ??
202/**
203 * Task state for a CCB request.
204 */
205typedef struct VIRTIOSCSIREQ
206{
207 /** Device this task is assigned to. */
208 PVIRTIOSCSITARGET pTargetDevice;
209 /** The command control block from the guest. */
210// CCBU CCBGuest;
211 /** Guest physical address of th CCB. */
212 RTGCPHYS GCPhysAddrCCB;
213 /** Pointer to the R3 sense buffer. */
214 uint8_t *pbSenseBuffer;
215 /** Flag whether this is a request from the BIOS. */
216 bool fBIOS;
217 /** 24-bit request flag (default is 32-bit). */
218 bool fIs24Bit;
219 /** SCSI status code. */
220 uint8_t u8ScsiSts;
221} VIRTIOSCSIREQ;
222typedef struct VIRTIOSCSIREQ *PVIRTIOSCSIREQ;
223
224
225#define CDB_SIZE 1 /* logic tbd */
226#define SENSE_SIZE 1 /* logic tbd */
227#define PI_BYTES_OUT 1 /* logic tbd */
228#define PI_BYTES_IN 1 /* logic tbd */
229#define DATA_OUT 1 /* logic tbd */
230typedef struct virtio_scsi_req_cmd
231{
232 /* Device-readable part */
233 uint8_t uLUN[8]; /** lun */
234 uint64_t uId; /** id */
235 uint8_t uTaskAttr; /** task_attr */
236 uint8_t uPrio; /** prio */
237 uint8_t uCrn; /** crn */
238 uint8_t uCdb[CDB_SIZE]; /** cdb */
239
240 /** Following three fields only present if VIRTIOSCSI_F_T10_PI negotiated */
241
242 uint32_t uPiBytesOut; /** pi_bytesout */
243 uint32_t uPiBytesIn; /** pi_bytesin */
244 uint8_t uPiOut[PI_BYTES_OUT]; /** pi_out[] */
245
246 uint8_t uDataOut[DATA_OUT]; /** dataout */
247
248 /* Device-writable part */
249 uint32_t uSenseLen; /** sense_len */
250 uint32_t uResidual; /** residual */
251 uint16_t uStatusQualifier; /** status_qualifier */
252 uint8_t uStatus; /** status */
253 uint8_t uResponse; /** response */
254 uint8_t uSense[SENSE_SIZE]; /** sense */
255
256 /** Following two fields only present if VIRTIOSCSI_F_T10_PI negotiated */
257 uint8_t uPiIn[PI_BYTES_IN]; /** pi_in[] */
258 uint8_t uDataIn[]; /** detain; */
259} VIRTIOSCSIREQCMD, *PVIRTIOSCSIREQCMD;
260
261/** Command-specific response values */
262#define VIRTIOSCSI_S_OK 0 /* control, command */
263#define VIRTIOSCSI_S_OVERRUN 1 /* control */
264#define VIRTIOSCSI_S_ABORTED 2 /* control */
265#define VIRTIOSCSI_S_BAD_TARGET 3 /* control, command */
266#define VIRTIOSCSI_S_RESET 4 /* control */
267#define VIRTIOSCSI_S_BUSY 5 /* control, command */
268#define VIRTIOSCSI_S_TRANSPORT_FAILURE 6 /* control, command */
269#define VIRTIOSCSI_S_TARGET_FAILURE 7 /* control, command */
270#define VIRTIOSCSI_S_NEXUS_FAILURE 8 /* control, command */
271#define VIRTIOSCSI_S_FAILURE 9 /* control, command */
272#define VIRTIOSCSI_S_INCORRECT_LUN 12 /* command */
273
274
275/** task_attr */
276#define VIRTIOSCSI_S_SIMPLE 0
277#define VIRTIOSCSI_S_ORDERED 1
278#define VIRTIOSCSI_S_HEAD 2
279#define VIRTIOSCSI_S_ACA 3
280
281#define VIRTIOSCSI_T_TMF 0
282#define VIRTIOSCSI_T_TMF_ABORT_TASK 0
283#define VIRTIOSCSI_T_TMF_ABORT_TASK_SET 1
284#define VIRTIOSCSI_T_TMF_CLEAR_ACA 2
285#define VIRTIOSCSI_T_TMF_CLEAR_TASK_SET 3
286#define VIRTIOSCSI_T_TMF_I_T_NEXUS_RESET 4
287#define VIRTIOSCSI_T_TMF_LOGICAL_UNIT_RESET 5
288#define VIRTIOSCSI_T_TMF_QUERY_TASK 6
289#define VIRTIOSCSI_T_TMF_QUERY_TASK_SET 7
290
291typedef struct virtio_scsi_ctrl_tmf
292{
293 // Device-readable part
294 uint32_t uType; /** type */
295 uint32_t uSubtype; /** subtype */
296 uint8_t uLUN[8]; /** lun */
297 uint64_t uId; /** id */
298 // Device-writable part
299 uint8_t uResponse; /** response */
300} VIRTIOSCSICTRLBUF, *PVIRTIOSCSICTRLBUF;
301
302/* command-specific response values */
303
304#define VIRTIOSCSI_S_FUNCTION_COMPLETE 0
305#define VIRTIOSCSI_S_FUNCTION_SUCCEEDED 10
306#define VIRTIOSCSI_S_FUNCTION_REJECTED 11
307
308#define VIRTIOSCSI_T_AN_QUERY 1 /** Asynchronous notification query */
309#define VIRTIOSCSI_T_AN_SUBSCRIBE 2 /** Asynchronous notification subscription */
310
311typedef struct virtio_scsi_ctrl_an
312{
313 // Device-readable part
314 uint32_t uType; /** type */
315 uint8_t uLUN[8]; /** lun */
316 uint32_t uEventRequested; /** event_requested */
317 // Device-writable part
318 uint32_t uEventActual; /** event_actual */
319 uint8_t uResponse; /** response */
320} VIRTIOSCSICTRLAN, *PVIRTIOSCSICTRLAN;
321
322#define VIRTIOSCSI_EVT_ASYNC_OPERATIONAL_CHANGE 2
323#define VIRTIOSCSI_EVT_ASYNC_POWER_MGMT 4
324#define VIRTIOSCSI_EVT_ASYNC_EXTERNAL_REQUEST 8
325#define VIRTIOSCSI_EVT_ASYNC_MEDIA_CHANGE 16
326#define VIRTIOSCSI_EVT_ASYNC_MULTI_HOST 32
327#define VIRTIOSCSI_EVT_ASYNC_DEVICE_BUSY 64
328
329/** Device operation: controlq */
330
331typedef struct virtio_scsi_ctrl
332{
333 uint32_t type; /** type */
334 uint8_t response; /** response */
335} VIRTIOSCSICTRL, *PVIRTIOSCSICTRL;
336
337#define VIRTIOSCSI_T_NO_EVENT 0
338
339#define VIRTIOSCSI_T_TRANSPORT_RESET 1
340#define VIRTIOSCSI_T_ASYNC_NOTIFY 2 /** Asynchronous notification */
341#define VIRTIOSCSI_T_PARAM_CHANGE 3
342
343#define VIRTIOSCSI_EVT_RESET_HARD 0
344#define VIRTIOSCSI_EVT_RESET_RESCAN 1
345#define VIRTIOSCSI_EVT_RESET_REMOVED 2
346
347/** Device operation: eventq */
348
349#define VIRTIOSCSI_T_EVENTS_MISSED 0x80000000
350typedef struct virtio_scsi_event {
351 // Device-writable part
352 uint32_t uEvent; /** event: */
353 uint8_t uLUN[8]; /** lun */
354 uint32_t uReason; /** reason */
355} VIRTIOSCSIEVENT, *PVIRTIOSCSIEVENT;
356
357
358/*********************************************************************************************************************************/
359
360#ifdef BOOTABLE_SUPPORT_TBD
361/** @callback_method_impl{FNIOMIOPORTIN} */
362static DECLCALLBACK(int) virtioScsiR3BiosIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst,
363 uint32_t *pcTransfers, unsigned cb);
364{
365}
366/** @callback_method_impl{FNIOMIOPORTOUT} */
367static DECLCALLBACK(int) virtioScsiR3BiosIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb);
368{
369}
370/** @callback_method_impl{FNIOMIOPORTOUTSTRING} */
371static DECLCALLBACK(int) virtioScsiR3BiosIoPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc,
372 uint32_t *pcTransfers, unsigned cb);
373{
374}
375/** @callback_method_impl{FNIOMIOPORTINSTRING} */
376static DECLCALLBACK(int) virtioScsiR3BiosIoPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst,
377 uint32_t *pcTransfers, unsigned cb);
378{
379}
380#endif
381
382/**
383 * Turns on/off the write status LED.
384 *
385 * @param pTarget Pointer to the target device
386 * @param fOn New LED state.
387 */
388void virtioScsiSetWriteLed(PVIRTIOSCSITARGET pTarget, bool fOn)
389{
390 LogFlow(("%s virtioSetWriteLed: %s\n", pTarget->pszLunName, fOn ? "on" : "off"));
391 if (fOn)
392 pTarget->led.Asserted.s.fWriting = pTarget->led.Actual.s.fWriting = 1;
393 else
394 pTarget->led.Actual.s.fWriting = fOn;
395}
396
397/**
398 * Turns on/off the read status LED.
399 *
400 * @param pTarget Pointer to the device state structure.
401 * @param fOn New LED state.
402 */
403void virtioScsiSetReadLed(PVIRTIOSCSITARGET pTarget, bool fOn)
404{
405 LogFlow(("%s virtioSetReadLed: %s\n", pTarget->pszLunName, fOn ? "on" : "off"));
406 if (fOn)
407 pTarget->led.Asserted.s.fReading = pTarget->led.Actual.s.fReading = 1;
408 else
409 pTarget->led.Actual.s.fReading = fOn;
410}
411
412/**
413 * virtio-scsi debugger info callback.
414 *
415 * @param pDevIns The device instance.
416 * @param pHlp The output helpers.
417 * @param pszArgs The arguments.
418 */
419static DECLCALLBACK(void) virtioScsiR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
420{
421 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
422 bool fVerbose = false;
423
424 /* Parse arguments. */
425 if (pszArgs)
426 fVerbose = strstr(pszArgs, "verbose") != NULL;
427
428 /* Show basic information. */
429 pHlp->pfnPrintf(pHlp, "%s#%d: virtio-scsci ",
430 pDevIns->pReg->szName,
431 pDevIns->iInstance);
432 pHlp->pfnPrintf(pHlp, "numTargets=%lu", pThis->cTargets);
433}
434
435/** @callback_method_impl{FNSSMDEVLIVEEXEC} */
436static DECLCALLBACK(int) virtioScsiR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
437{
438 LogFunc(("callback"));
439 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
440 RT_NOREF(pThis);
441 RT_NOREF(uPass);
442 RT_NOREF(pSSM);
443 return VINF_SSM_DONT_CALL_AGAIN;
444}
445
446/** @callback_method_impl{FNSSMDEVLOADEXEC} */
447static DECLCALLBACK(int) virtioScsiR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
448{
449 LogFunc(("callback"));
450 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
451 RT_NOREF(pThis);
452 RT_NOREF(uPass);
453 RT_NOREF(pSSM);
454 RT_NOREF(uVersion);
455 return VINF_SSM_DONT_CALL_AGAIN;
456}
457
458/** @callback_method_impl{FNSSMDEVSAVEEXEC} */
459static DECLCALLBACK(int) virtioScsiR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
460{
461 LogFunc(("callback"));
462 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
463 RT_NOREF(pThis);
464 RT_NOREF(pSSM);
465 return VINF_SUCCESS;
466}
467
468/** @callback_method_impl{FNSSMDEVLOADDONE} */
469static DECLCALLBACK(int) virtioScsiR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
470{
471 LogFunc(("callback"));
472 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
473 RT_NOREF(pThis);
474 RT_NOREF(pSSM);
475 return VINF_SUCCESS;
476}
477
478/**
479 * @copydoc FNPDMDEVRESET
480 */
481static DECLCALLBACK(void) virtioScsiR3Reset(PPDMDEVINS pDevIns)
482{
483 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
484 NOREF(pThis);
485
486// ASMAtomicWriteBool(&pThis->fSignalIdle, true);
487// if (!virtioScsiR3AllAsyncIOIsFinished(pDevIns))
488// PDMDevHlpSetAsyncNotification(pDevIns, virtioScsiR3IsAsyncResetDone);
489// else
490// {
491// ASMAtomicWriteBool(&pThis->fSignalIdle, false);
492// }
493}
494
495static DECLCALLBACK(void) virtioScsiR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
496{
497 LogFunc(("Relocating virtio-scsi"));
498 RT_NOREF(offDelta);
499 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
500
501 pThis->pDevInsR3 = pDevIns;
502
503 for (uint32_t i = 0; i < VIRTIOSCSI_MAX_TARGETS; i++)
504 {
505 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[i];
506 pTarget->pVirtioScsiR3 = pThis;;
507 }
508
509}
510
511static DECLCALLBACK(int) virtioScsiR3QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
512 uint32_t *piInstance, uint32_t *piLUN)
513{
514 PVIRTIOSCSITARGET pVirtioScsiTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaPort);
515 PPDMDEVINS pDevIns = pVirtioScsiTarget->CTX_SUFF(pVirtioScsi)->CTX_SUFF(pDevIns);
516
517 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
518 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
519 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
520
521 *ppcszController = pDevIns->pReg->szName;
522 *piInstance = pDevIns->iInstance;
523 *piLUN = pVirtioScsiTarget->iLUN;
524
525 return VINF_SUCCESS;
526}
527
528/**
529 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
530 */
531static DECLCALLBACK(int) virtioScsiR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
532 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
533 size_t cbCopy)
534{
535 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
536 PVIRTIOSCSIREQ pReq = (PVIRTIOSCSIREQ)pvIoReqAlloc;
537 size_t cbCopied = 0;
538 RT_NOREF(pTarget);
539 RT_NOREF(pReq);
540 RT_NOREF(pInterface);
541 RT_NOREF(pvIoReqAlloc);
542 RT_NOREF(offDst);
543 RT_NOREF(pSgBuf);
544 RT_NOREF(hIoReq);
545 RT_NOREF(cbCopy);
546 RT_NOREF(cbCopied);
547
548/*
549 if (RT_UNLIKELY(pReq->fBIOS))
550 cbCopied = vboxscsiCopyToBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offDst, cbCopy);
551 else
552 cbCopied = virtioScsiR3CopySgBufToGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offDst, cbCopy);
553 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
554*/
555 return 0; /* placeholder */
556}
557
558/**
559 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
560 */
561static DECLCALLBACK(int) virtioScsiR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
562 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
563 size_t cbCopy)
564{
565 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
566 PVIRTIOSCSIREQ pReq = (PVIRTIOSCSIREQ)pvIoReqAlloc;
567 size_t cbCopied = 0;
568 RT_NOREF(pTarget);
569 RT_NOREF(pReq);
570 RT_NOREF(pInterface);
571 RT_NOREF(pvIoReqAlloc);
572 RT_NOREF(offSrc);
573 RT_NOREF(pSgBuf);
574 RT_NOREF(hIoReq);
575 RT_NOREF(cbCopy);
576 RT_NOREF(cbCopied);
577
578/*
579 if (RT_UNLIKELY(pReq->fBIOS))
580 cbCopied = vboxscsiCopyFromBuf(&pTarget->CTX_SUFF(pVirtioScsi)->VBoxSCSI, pSgBuf, offSrc, cbCopy);
581 else
582 cbCopied = vboxscsiR3CopySgBufFromGuest(pTarget->CTX_SUFF(pVirtioScsi), pReq, pSgBuf, offSrc, cbCopy);
583 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
584*/
585 return 0; /* placeholder */
586
587}
588
589/**
590 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
591 */
592static DECLCALLBACK(int) virtioScsiR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
593 void *pvIoReqAlloc, int rcReq)
594{
595 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
596 RT_NOREF(pTarget);
597 RT_NOREF(pInterface);
598 RT_NOREF(pvIoReqAlloc);
599 RT_NOREF(rcReq);
600 RT_NOREF(hIoReq);
601// virtioScsiR3ReqComplete(pTarget->CTX_SUFF(pVirtioScsi), (VIRTIOSCSIREQ)pvIoReqAlloc, rcReq);
602 return VINF_SUCCESS;
603}
604
605/**
606 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
607 */
608static DECLCALLBACK(void) virtioScsiR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
609 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
610{
611
612 RT_NOREF4(pInterface, hIoReq, pvIoReqAlloc, enmState);
613 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
614
615 switch (enmState)
616 {
617 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
618 {
619 /* Make sure the request is not accounted for so the VM can suspend successfully. */
620 uint32_t cTasksActive = ASMAtomicDecU32(&pTarget->cOutstandingRequests);
621 if (!cTasksActive && pTarget->CTX_SUFF(pVirtioScsi)->fSignalIdle)
622 PDMDevHlpAsyncNotificationCompleted(pTarget->CTX_SUFF(pVirtioScsi)->pDevInsR3);
623 break;
624 }
625 case PDMMEDIAEXIOREQSTATE_ACTIVE:
626 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
627 ASMAtomicIncU32(&pTarget->cOutstandingRequests);
628 break;
629 default:
630 AssertMsgFailed(("Invalid request state given %u\n", enmState));
631 }
632}
633
634/**
635 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
636 */
637static DECLCALLBACK(void) virtioScsiR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
638{
639 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IMediaExPort);
640 PVIRTIOSCSI pThis = pTarget->CTX_SUFF(pVirtioScsi);
641
642 if (pThis->pMediaNotify)
643 virtioScsiSetWriteLed(pTarget, false);
644}
645
646/**
647 * Transmit queue consumer
648 * Queue a new async task.
649 *
650 * @returns Success indicator.
651 * If false the item will not be removed and the flushing will stop.
652 * @param pDevIns The device instance.
653 * @param pItem The item to consume. Upon return this item will be freed.
654 */
655static DECLCALLBACK(bool) virtioScsiR3NotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
656{
657 RT_NOREF(pItem);
658 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
659
660 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess);
661 AssertRC(rc);
662
663 return true;
664}
665
666
667/**
668 * Gets the pointer to the status LED of a unit.
669 *
670 * @returns VBox status code.
671 * @param pInterface Pointer to the interface structure containing the called function pointer.
672 * @param iLUN The unit which status LED we desire.
673 * @param ppLed Where to store the LED pointer.
674 */
675static DECLCALLBACK(int) virtioScsiR3TargetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
676{
677 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, ILed);
678 if (iLUN == 0)
679 {
680 *ppLed = &pTarget->led;
681 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
682 return VINF_SUCCESS;
683 }
684 return VERR_PDM_LUN_NOT_FOUND;
685 }
686
687
688/**
689 * Gets the pointer to the status LED of a unit.
690 *
691 * @returns VBox status code.
692 * @param pInterface Pointer to the interface structure containing the called function pointer.
693 * @param iLUN The unit which status LED we desire.
694 * @param ppLed Where to store the LED pointer.
695 */
696static DECLCALLBACK(int) virtioScsiR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
697{
698 PVIRTIOSCSI pThis = RT_FROM_MEMBER(pInterface, VIRTIOSCSI, ILeds);
699 if (iLUN < pThis->cTargets)
700 {
701 *ppLed = &pThis->aTargetInstances[iLUN].led;
702 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
703 return VINF_SUCCESS;
704 }
705 return VERR_PDM_LUN_NOT_FOUND;
706}
707
708/**
709 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
710 */
711static DECLCALLBACK(void *) virtioScsiR3TargetQueryInterface(PPDMIBASE pInterface, const char *pszIID)
712{
713 PVIRTIOSCSITARGET pTarget = RT_FROM_MEMBER(pInterface, VIRTIOSCSITARGET, IBase);
714 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pTarget->IBase);
715 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pTarget->IMediaPort);
716 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pTarget->IMediaExPort);
717 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pTarget->ILed);
718 return NULL;
719}
720
721/**
722 * virtio-scsi VirtIO Device-specific capabilities read callback
723 * (other VirtIO capabilities and features are handled in VirtIO implementation)
724 *
725 * @param pDevIns The device instance.
726 * @param GCPhysAddr Guest driver physical address to read
727 * @param pvBuf Buffer in which to save read data
728 * @param cbRead Number of bytes to read
729 */
730static DECLCALLBACK(int) virtioScsiR3DevCapRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhysAddr, const void *pvBuf, size_t cbRead)
731{
732/*TBD*/
733 LogFunc(("Read from Device-Specific capabilities\n"));
734 RT_NOREF(pDevIns);
735 RT_NOREF(GCPhysAddr);
736 RT_NOREF(pvBuf);
737 RT_NOREF(cbRead);
738 int rv = VINF_SUCCESS;
739 return rv;
740}
741
742/**
743 * virtio-scsi VirtIO Device-specific capabilities read callback
744 * (other VirtIO capabilities and features are handled in VirtIO implementation)
745 *
746 * @param pDevIns The device instance.
747 * @param GCPhysAddr Guest driver physical address to write
748 * @param pvBuf Buffer in which to save read data
749 * @param cbWrite Number of bytes to write
750 */
751static DECLCALLBACK(int) virtioScsiR3DevCapWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhysAddr, const void *pvBuf, size_t cbWrite)
752{
753/*TBD*/
754 LogFunc(("Write to Device-Specific capabilities\n"));
755 RT_NOREF(pDevIns);
756 RT_NOREF(GCPhysAddr);
757 RT_NOREF(pvBuf);
758 RT_NOREF(cbWrite);
759 int rv = VINF_SUCCESS;
760 return rv;
761}
762
763
764/**
765 * Memory mapped I/O Handler for read operations.
766 *
767 * @returns VBox status code.
768 *
769 * @param pDevIns The device instance.
770 * @param pvUser User argument.
771 * @param GCPhysAddr Physical address (in GC) where the read starts.
772 * @param pv Where to store the result.
773 * @param cb Number of bytes read.
774 */
775PDMBOTHCBDECL(int) virtioScsiMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
776{
777 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
778 LogFunc(("Read from MMIO area\n"));
779 return VINF_SUCCESS;
780}
781
782/**
783 * Memory mapped I/O Handler for write operations.
784 *
785 * @returns VBox status code.
786 *
787 * @param pDevIns The device instance.
788 * @param pvUser User argument.
789 * @param GCPhysAddr Physical address (in GC) where the read starts.
790 * @param pv Where to fetch the result.
791 * @param cb Number of bytes to write.
792 */
793PDMBOTHCBDECL(int) virtioScsiMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
794{
795 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
796 LogFunc(("Write to MMIO area\n"));
797 return VINF_SUCCESS;
798}
799
800/**
801 * @callback_method_impl{FNPCIIOREGIONMAP}
802 */
803static DECLCALLBACK(int) virtioScsiR3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
804 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
805{
806 RT_NOREF(pPciDev, iRegion);
807 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
808 int rc = VINF_SUCCESS;
809
810 Assert(cb >= 32);
811
812 switch (iRegion)
813 {
814 case 0:
815 LogFunc(("virtio-scsi MMIO mapped at GCPhysAddr=%RGp cb=%RGp\n", GCPhysAddress, cb));
816
817 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
818 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
819 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
820 virtioScsiMMIOWrite, virtioScsiMMIORead,
821 "virtio-scsi MMIO");
822 pThis->GCPhysMMIOBase = RT_SUCCESS(rc) ? GCPhysAddress : 0;
823 return rc;
824 case 1:
825 /* VirtIO 1.0 doesn't uses Port I/O (Virtio 0.95 e.g. "legacy", does) */
826 AssertMsgFailed(("virtio-scsi: Port I/O not supported by this Host SCSI device\n"));
827 default:
828 AssertMsgFailed(("Invalid enmType=%d\n", enmType));
829 }
830 return VERR_GENERAL_FAILURE; /* Should never get here */
831}
832
833/**
834 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
835 */
836static DECLCALLBACK(void *) virtioScsiR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
837{
838 PVIRTIOSCSI pVirtioScsi = RT_FROM_MEMBER(pInterface, VIRTIOSCSI, IBase);
839
840 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pVirtioScsi->IBase);
841 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pVirtioScsi->ILeds);
842
843 return NULL;
844}
845
846
847/**
848 * Detach notification.
849 *
850 * One harddisk at one port has been unplugged.
851 * The VM is suspended at this point.
852 *
853 * @param pDevIns The device instance.
854 * @param iLUN The logical unit which is being detached.
855 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
856 */
857static DECLCALLBACK(void) virtioScsiR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
858{
859 RT_NOREF(fFlags);
860 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
861 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
862
863 LogFunc((""));
864
865 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
866 ("virtio-scsi: Device does not support hotplugging\n"));
867
868 /*
869 * Zero some important members.
870 */
871 pTarget->fPresent = false;
872 pTarget->pDrvBase = NULL;
873}
874
875/**
876 * Attach command.
877 *
878 * This is called when we change block driver.
879 *
880 * @returns VBox status code.
881 * @param pDevIns The device instance.
882 * @param iLUN The logical unit which is being detached.
883 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
884 */
885static DECLCALLBACK(int) virtioScsiR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
886{
887 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
888 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
889 int rc;
890
891 pThis->pDevInsR3 = pDevIns;
892 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
893 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
894
895 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
896 ("virtio-scsi: Device does not support hotplugging\n"),
897 VERR_INVALID_PARAMETER);
898
899 /* the usual paranoia */
900 AssertRelease(!pTarget->pDrvBase);
901 Assert(pTarget->iLUN == iLUN);
902
903 /*
904 * Try attach the SCSI driver and get the interfaces,
905 * required as well as optional.
906 */
907 rc = PDMDevHlpDriverAttach(pDevIns, pTarget->iLUN, &pDevIns->IBase,
908 &pTarget->pDrvBase, (const char *)&pTarget->pszLunName);
909 if (RT_SUCCESS(rc))
910 pTarget->fPresent = true;
911 else
912 AssertMsgFailed(("Failed to attach %s. rc=%Rrc\n", pTarget->pszLunName, rc));
913
914 if (RT_FAILURE(rc))
915 {
916 pTarget->fPresent = false;
917 pTarget->pDrvBase = NULL;
918 }
919 return rc;
920}
921
922static DECLCALLBACK(int) virtioScsiDestruct(PPDMDEVINS pDevIns)
923{
924 /*
925 * Check the versions here as well since the destructor is *always* called.
926 */
927 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
928 return VINF_SUCCESS;
929}
930
931static DECLCALLBACK(int) virtioScsiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg){
932
933 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
934
935 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);
936 int rc = VINF_SUCCESS;
937 bool fBootable = true;
938
939 pThis->pDevInsR3 = pDevIns;
940 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
941 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
942
943 LogFunc(("PDM device instance: %d\n", iInstance));
944
945 /*
946 * Validate and read configuration.
947 */
948 if (!CFGMR3AreValuesValid(pCfg,"NumTargets\0"
949 "Bootable\0"
950 /* "GCEnabled\0" TBD */
951 /* "R0Enabled\0" TBD */
952 ))
953 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
954 N_("virtio-scsi configuration error: unknown option specified"));
955
956 rc = CFGMR3QueryIntegerDef(pCfg, "NumTargets", &pThis->cTargets, true);
957 if (RT_FAILURE(rc))
958 return PDMDEV_SET_ERROR(pDevIns, rc,
959 N_("virtio-scsi configuration error: failed to read NumTargets as integer"));
960 LogFunc(("NumTargets=%d\n", pThis->cTargets));
961
962 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &fBootable, true);
963 if (RT_FAILURE(rc))
964 return PDMDEV_SET_ERROR(pDevIns, rc,
965 N_("virtio-scsi configuration error: failed to read Bootable as boolean"));
966 LogFunc(("Bootable=%RTbool (unimplemented)\n", fBootable));
967
968 VIRTIOPCIPARAMS virtioPciParams, *pVirtioPciParams = &virtioPciParams;
969 pVirtioPciParams->uDeviceId = PCI_DEVICE_ID_VIRTIOSCSI_HOST;
970 pVirtioPciParams->uClassBase = PCI_CLASS_BASE_MASS_STORAGE;
971 pVirtioPciParams->uClassSub = PCI_CLASS_SUB_SCSI_STORAGE_CONTROLLER;
972 pVirtioPciParams->uClassProg = PCI_CLASS_PROG_UNSPECIFIED;
973 pVirtioPciParams->uSubsystemId = PCI_DEVICE_ID_VIRTIOSCSI_HOST; /* Virtio 1.0 spec allows PCI Device ID here */
974 pVirtioPciParams->uInterruptLine = 0x00;
975 pVirtioPciParams->uInterruptPin = 0x01;
976
977 PVIRTIOSTATE pVirtio = &(pThis->virtioState);
978
979 virtioSetHostFeatures(pVirtio, VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED);
980
981 pThis->IBase.pfnQueryInterface = virtioScsiR3DeviceQueryInterface;
982
983 rc = virtioConstruct(pDevIns, pVirtio, iInstance, pVirtioPciParams,
984 VIRTIOSCSI_NAME_FMT, VIRTIOSCSI_N_QUEUES, VIRTIOSCSI_REGION_PCI_CAP,
985 virtioScsiR3DevCapRead, virtioScsiR3DevCapWrite,
986 sizeof(VIRTIO_PCI_DEV_CAP_T ) /* cbDevSpecificCap */,
987 false /* fHaveDevSpecificCap */, 0 /* uNotifyOffMultiplier */);
988
989
990 if (RT_FAILURE(rc))
991 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: failed to initialize VirtIO"));
992
993
994 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_MEM_IO, 32,
995 PCI_ADDRESS_SPACE_MEM, virtioScsiR3Map);
996 if (RT_FAILURE(rc))
997 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi: cannot register PCI mmio address space"));
998
999#ifdef BOOTABLE_SUPPORT_TBD
1000 if (fBootable)
1001 {
1002 /* Register I/O port space for BIOS access. */
1003 rc = PDMDevHlpIOPortRegister(pDevIns, VIRTIOSCSI_BIOS_IO_PORT, 4, NULL,
1004 virtioScsiR3BiosIoPortWrite, virtioScsiR3BiosIoPortRead,
1005 virtioScsiR3BiosIoPortWriteStr, virtioScsiR3BiosIoPortReadStr,
1006 "virtio-scsi BIOS");
1007 if (RT_FAILURE(rc))
1008 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi cannot register BIOS I/O handlers"));
1009 }
1010#endif
1011
1012 /* Initialize task queue. */
1013 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 5, 0,
1014 virtioScsiR3NotifyQueueConsumer, true, "VirtioTask", &pThis->pNotifierQueueR3);
1015 if (RT_FAILURE(rc))
1016 return rc;
1017
1018 /* Initialize per device instance. */
1019 for (RTUINT iLUN = 0; iLUN < VIRTIOSCSI_MAX_TARGETS; iLUN++)
1020 {
1021 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[iLUN];
1022
1023 if (RTStrAPrintf(&pTarget->pszLunName, "vSCSI%u", iLUN) < 0)
1024 AssertLogRelFailedReturn(VERR_NO_MEMORY);
1025
1026 /* Initialize static parts of the device. */
1027 pTarget->iLUN = iLUN;
1028 pTarget->pVirtioScsiR3 = pThis;
1029
1030 pTarget->IBase.pfnQueryInterface = virtioScsiR3TargetQueryInterface;
1031
1032 /* IMediaPort and IMediaExPort interfaces provide callbacks for VD media and downstream driver access */
1033 pTarget->IMediaPort.pfnQueryDeviceLocation = virtioScsiR3QueryDeviceLocation;
1034 pTarget->IMediaExPort.pfnIoReqCompleteNotify = virtioScsiR3IoReqCompleteNotify;
1035 pTarget->IMediaExPort.pfnIoReqCopyFromBuf = virtioScsiR3IoReqCopyFromBuf;
1036 pTarget->IMediaExPort.pfnIoReqCopyToBuf = virtioScsiR3IoReqCopyToBuf;
1037 pTarget->IMediaExPort.pfnIoReqStateChanged = virtioScsiR3IoReqStateChanged;
1038 pTarget->IMediaExPort.pfnMediumEjected = virtioScsiR3MediumEjected;
1039 pTarget->IMediaExPort.pfnIoReqQueryBuf = NULL;
1040 pTarget->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
1041 pTarget->IBase.pfnQueryInterface = virtioScsiR3TargetQueryInterface;
1042 pTarget->ILed.pfnQueryStatusLed = virtioScsiR3TargetQueryStatusLed;
1043 pThis->ILeds.pfnQueryStatusLed = virtioScsiR3DeviceQueryStatusLed;
1044 pTarget->led.u32Magic = PDMLED_MAGIC;
1045
1046 LogFunc(("Attaching LUN: %s\n", pTarget->pszLunName));
1047
1048 /* Attach this SCSI driver (upstream driver pre-determined statically outside this module) */
1049 AssertReturn(iLUN < RT_ELEMENTS(pThis->aTargetInstances), VERR_PDM_NO_SUCH_LUN);
1050 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pTarget->IBase, &pTarget->pDrvBase, (const char *)&pTarget->pszLunName);
1051 if (RT_SUCCESS(rc))
1052 {
1053 pTarget->fPresent = true;
1054
1055 pTarget->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pTarget->pDrvBase, PDMIMEDIA);
1056 AssertMsgReturn(VALID_PTR(pTarget->pDrvMedia),
1057 ("virtio-scsi configuration error: LUN#%d missing basic media interface!\n", pTarget->iLUN),
1058 VERR_PDM_MISSING_INTERFACE);
1059
1060 /* Get the extended media interface. */
1061 pTarget->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pTarget->pDrvBase, PDMIMEDIAEX);
1062 AssertMsgReturn(VALID_PTR(pTarget->pDrvMediaEx),
1063 ("virtio-scsi configuration error: LUN#%d missing extended media interface!\n", pTarget->iLUN),
1064 VERR_PDM_MISSING_INTERFACE);
1065
1066 rc = pTarget->pDrvMediaEx->pfnIoReqAllocSizeSet(pTarget->pDrvMediaEx, REQ_ALLOC_SIZE /*TBD*/);
1067 AssertMsgReturn(VALID_PTR(pTarget->pDrvMediaEx),
1068 ("virtio-scsi configuration error: LUN#%u: Failed to set I/O request size!\n", pTarget->iLUN),
1069 rc);
1070
1071 }
1072 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1073 {
1074 pTarget->fPresent = false;
1075 pTarget->pDrvBase = NULL;
1076 rc = VINF_SUCCESS;
1077 Log(("virtio-scsi: no driver attached to device %s\n", pTarget->pszLunName));
1078 }
1079 else
1080 {
1081 AssertLogRelMsgFailed(("virtio-scsi: Failed to attach %s\n", pTarget->pszLunName));
1082 return rc;
1083 }
1084 }
1085
1086 rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIOSCSI_SAVED_STATE_MINOR_VERSION, sizeof(*pThis), NULL,
1087 NULL, virtioScsiR3LiveExec, NULL,
1088 NULL, virtioScsiR3SaveExec, NULL,
1089 NULL, virtioScsiR3LoadExec, virtioScsiR3LoadDone);
1090 if (RT_FAILURE(rc))
1091 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-scsi cannot register save state handlers"));
1092
1093 /* Status driver */
1094 PPDMIBASE pUpBase;
1095 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pUpBase, "Status Port");
1096 if (RT_FAILURE(rc))
1097 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
1098
1099 /*
1100 * Register the debugger info callback.
1101 */
1102 char szTmp[128];
1103 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
1104 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "virtio-scsi info", virtioScsiR3Info);
1105
1106 return rc;
1107}
1108
1109/**
1110 * The device registration structure.
1111 */
1112const PDMDEVREG g_DeviceVirtioSCSI =
1113{
1114 /* u32Version */
1115 PDM_DEVREG_VERSION,
1116 /* szName */
1117 "virtio-scsi",
1118 /* szRCMod */
1119 "VBoxDDRC.rc",
1120 /* szR0Mod */
1121 "VBoxDDR0.r0",
1122 /* pszDescription */
1123 "Virtio Host SCSI.\n",
1124 /* fFlags */
1125#ifdef VIRTIOSCSI_GC_SUPPORT
1126 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1127#else
1128 PDM_DEVREG_FLAGS_DEFAULT_BITS,
1129#endif
1130 /* fClass */
1131 PDM_DEVREG_CLASS_MISC,
1132 /* cMaxInstances */
1133 ~0U,
1134 /* cbInstance */
1135 sizeof(VIRTIOSCSI),
1136 /* pfnConstruct */
1137 virtioScsiConstruct,
1138 /* pfnDestruct */
1139 virtioScsiDestruct,
1140 /* pfnRelocate */
1141 virtioScsiR3Relocate,
1142 /* pfnMemSetup */
1143 NULL,
1144 /* pfnPowerOn */
1145 NULL,
1146 /* pfnReset */
1147 virtioScsiR3Reset,
1148 /* pfnSuspend */
1149 NULL,
1150 /* pfnResume */
1151 NULL,
1152 /* pfnAttach */
1153 virtioScsiR3Attach,
1154 /* pfnDetach */
1155 virtioScsiR3Detach,
1156 /* pfnQueryInterface */
1157 NULL,
1158 /* pfnInitComplete */
1159 NULL,
1160 /* pfnPowerOff */
1161 NULL,
1162 /* pfnSoftReset */
1163 NULL,
1164 /* u32VersionEnd */
1165 PDM_DEVREG_VERSION
1166};
1167
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