VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvSCSI.cpp@ 64401

Last change on this file since 64401 was 64226, checked in by vboxsync, 8 years ago

DrvSCSI: Get rid of the deprecated PDMISCSICONNECTOR and PDMISCSIPORT interfaces now that every device emulation was converted to the new interface

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.8 KB
Line 
1/* $Id: DrvSCSI.cpp 64226 2016-10-12 13:11:22Z vboxsync $ */
2/** @file
3 * VBox storage drivers: Generic SCSI command parser and execution driver
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22//#define DEBUG
23#define LOG_GROUP LOG_GROUP_DRV_SCSI
24#include <VBox/vmm/pdmdrv.h>
25#include <VBox/vmm/pdmifs.h>
26#include <VBox/vmm/pdmqueue.h>
27#include <VBox/vmm/pdmstorageifs.h>
28#include <VBox/vmm/pdmthread.h>
29#include <VBox/vscsi.h>
30#include <VBox/scsi.h>
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/mem.h>
34#include <iprt/req.h>
35#include <iprt/semaphore.h>
36#include <iprt/string.h>
37#include <iprt/uuid.h>
38
39#include "VBoxDD.h"
40
41/** The maximum number of release log entries per device. */
42#define MAX_LOG_REL_ERRORS 1024
43
44/**
45 * Eject state.
46 */
47typedef struct DRVSCSIEJECTSTATE
48{
49 /** The item core for the PDM queue. */
50 PDMQUEUEITEMCORE Core;
51 /** Event semaphore to signal when complete. */
52 RTSEMEVENT hSemEvt;
53 /** Status of the eject operation. */
54 int rcReq;
55} DRVSCSIEJECTSTATE;
56typedef DRVSCSIEJECTSTATE *PDRVSCSIEJECTSTATE;
57
58/**
59 * SCSI driver private per request data.
60 */
61typedef struct DRVSCSIREQ
62{
63 /** Size of the guest buffer. */
64 size_t cbBuf;
65 /** Temporary buffer holding the data. */
66 void *pvBuf;
67 /** Data segment. */
68 RTSGSEG Seg;
69 /** Transfer direction. */
70 PDMMEDIAEXIOREQSCSITXDIR enmXferDir;
71 /** The VSCSI request handle. */
72 VSCSIREQ hVScsiReq;
73 /** Where to store the SCSI status code. */
74 uint8_t *pu8ScsiSts;
75 /** Start of the request data for the device above us. */
76 uint8_t abAlloc[1];
77} DRVSCSIREQ;
78/** Pointer to the driver private per request data. */
79typedef DRVSCSIREQ *PDRVSCSIREQ;
80
81/**
82 * SCSI driver instance data.
83 *
84 * @implements PDMIMEDIAEXPORT
85 * @implements PDMIMEDIAEX
86 * @implements PDMIMOUNTNOTIFY
87 */
88typedef struct DRVSCSI
89{
90 /** Pointer driver instance. */
91 PPDMDRVINS pDrvIns;
92
93 /** Pointer to the attached driver's base interface. */
94 PPDMIBASE pDrvBase;
95 /** Pointer to the attached driver's block interface. */
96 PPDMIMEDIA pDrvMedia;
97 /** Pointer to the attached driver's extended media interface. */
98 PPDMIMEDIAEX pDrvMediaEx;
99 /** Pointer to the attached driver's mount interface. */
100 PPDMIMOUNT pDrvMount;
101 /** Pointer to the extended media port interface of the device above. */
102 PPDMIMEDIAEXPORT pDevMediaExPort;
103 /** Pointer to the media port interface of the device above. */
104 PPDMIMEDIAPORT pDevMediaPort;
105 /** pointer to the Led port interface of the dveice above. */
106 PPDMILEDPORTS pLedPort;
107 /** The media interface for the device above. */
108 PDMIMEDIA IMedia;
109 /** The extended media interface for the device above. */
110 PDMIMEDIAEX IMediaEx;
111 /** The media port interface. */
112 PDMIMEDIAPORT IPort;
113 /** The optional extended media port interface. */
114 PDMIMEDIAEXPORT IPortEx;
115 /** The mount notify interface. */
116 PDMIMOUNTNOTIFY IMountNotify;
117 /** Fallback status LED state for this drive.
118 * This is used in case the device doesn't has a LED interface. */
119 PDMLED Led;
120 /** Pointer to the status LED for this drive. */
121 PPDMLED pLed;
122
123 /** VSCSI device handle. */
124 VSCSIDEVICE hVScsiDevice;
125 /** VSCSI LUN handle. */
126 VSCSILUN hVScsiLun;
127 /** I/O callbacks. */
128 VSCSILUNIOCALLBACKS VScsiIoCallbacks;
129
130 /** Indicates whether PDMDrvHlpAsyncNotificationCompleted should be called by
131 * any of the dummy functions. */
132 bool volatile fDummySignal;
133 /** Release statistics: number of bytes written. */
134 STAMCOUNTER StatBytesWritten;
135 /** Release statistics: number of bytes read. */
136 STAMCOUNTER StatBytesRead;
137 /** Release statistics: Current I/O depth. */
138 volatile uint32_t StatIoDepth;
139 /** Errors printed in the release log. */
140 unsigned cErrors;
141
142 /** Size of the I/O request to allocate. */
143 size_t cbIoReqAlloc;
144 /** Size of a VSCSI I/O request. */
145 size_t cbVScsiIoReqAlloc;
146 /** Queue to defer unmounting to EMT. */
147 PPDMQUEUE pQueue;
148} DRVSCSI, *PDRVSCSI;
149
150/** Convert a VSCSI I/O request handle to the associated PDMIMEDIAEX I/O request. */
151#define DRVSCSI_VSCSIIOREQ_2_PDMMEDIAEXIOREQ(a_hVScsiIoReq) (*(PPDMMEDIAEXIOREQ)((uint8_t *)(a_hVScsiIoReq) - sizeof(PDMMEDIAEXIOREQ)))
152/** Convert a PDMIMEDIAEX I/O additional request memory to a VSCSI I/O request. */
153#define DRVSCSI_PDMMEDIAEXIOREQ_2_VSCSIIOREQ(a_pvIoReqAlloc) ((VSCSIIOREQ)((uint8_t *)(a_pvIoReqAlloc) + sizeof(PDMMEDIAEXIOREQ)))
154
155/**
156 * Returns whether the given status code indicates a non fatal error.
157 *
158 * @returns True if the error can be fixed by the user after the VM was suspended.
159 * False if not and the error should be reported to the guest.
160 * @param rc The status code to check.
161 */
162DECLINLINE(bool) drvscsiIsRedoPossible(int rc)
163{
164 if ( rc == VERR_DISK_FULL
165 || rc == VERR_FILE_TOO_BIG
166 || rc == VERR_BROKEN_PIPE
167 || rc == VERR_NET_CONNECTION_REFUSED
168 || rc == VERR_VD_DEK_MISSING)
169 return true;
170
171 return false;
172}
173
174/* -=-=-=-=- VScsiIoCallbacks -=-=-=-=- */
175
176/**
177 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunReqAllocSizeSet}
178 */
179static DECLCALLBACK(int) drvscsiReqAllocSizeSet(VSCSILUN hVScsiLun, void *pvScsiLunUser, size_t cbVScsiIoReqAlloc)
180{
181 RT_NOREF(hVScsiLun);
182 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
183
184 /* We need to store the I/O request handle so we can get it when VSCSI queues an I/O request. */
185 int rc = pThis->pDrvMediaEx->pfnIoReqAllocSizeSet(pThis->pDrvMediaEx, cbVScsiIoReqAlloc + sizeof(PDMMEDIAEXIOREQ));
186 if (RT_SUCCESS(rc))
187 pThis->cbVScsiIoReqAlloc = cbVScsiIoReqAlloc + sizeof(PDMMEDIAEXIOREQ);
188
189 return rc;
190}
191
192/**
193 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunReqAlloc}
194 */
195static DECLCALLBACK(int) drvscsiReqAlloc(VSCSILUN hVScsiLun, void *pvScsiLunUser,
196 uint64_t u64Tag, PVSCSIIOREQ phVScsiIoReq)
197{
198 RT_NOREF(hVScsiLun);
199 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
200 PDMMEDIAEXIOREQ hIoReq;
201 void *pvIoReqAlloc;
202 int rc = pThis->pDrvMediaEx->pfnIoReqAlloc(pThis->pDrvMediaEx, &hIoReq, &pvIoReqAlloc, u64Tag,
203 PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
204 if (RT_SUCCESS(rc))
205 {
206 PPDMMEDIAEXIOREQ phIoReq = (PPDMMEDIAEXIOREQ)pvIoReqAlloc;
207
208 *phIoReq = hIoReq;
209 *phVScsiIoReq = (VSCSIIOREQ)(phIoReq + 1);
210 }
211
212 return rc;
213}
214
215/**
216 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunReqFree}
217 */
218static DECLCALLBACK(int) drvscsiReqFree(VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)
219{
220 RT_NOREF(hVScsiLun);
221 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
222 PDMMEDIAEXIOREQ hIoReq = DRVSCSI_VSCSIIOREQ_2_PDMMEDIAEXIOREQ(hVScsiIoReq);
223
224 return pThis->pDrvMediaEx->pfnIoReqFree(pThis->pDrvMediaEx, hIoReq);
225}
226
227/**
228 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunMediumGetSize}
229 */
230static DECLCALLBACK(int) drvscsiGetSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pcbSize)
231{
232 RT_NOREF(hVScsiLun);
233 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
234
235 *pcbSize = pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
236
237 return VINF_SUCCESS;
238}
239
240/**
241 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunMediumGetSectorSize}
242 */
243static DECLCALLBACK(int) drvscsiGetSectorSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint32_t *pcbSectorSize)
244{
245 RT_NOREF(hVScsiLun);
246 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
247
248 *pcbSectorSize = pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
249
250 return VINF_SUCCESS;
251}
252
253/**
254 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunMediumSetLock}
255 */
256static DECLCALLBACK(int) drvscsiSetLock(VSCSILUN hVScsiLun, void *pvScsiLunUser, bool fLocked)
257{
258 RT_NOREF(hVScsiLun);
259 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
260
261 if (fLocked)
262 pThis->pDrvMount->pfnLock(pThis->pDrvMount);
263 else
264 pThis->pDrvMount->pfnUnlock(pThis->pDrvMount);
265
266 return VINF_SUCCESS;
267}
268
269/** @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunMediumEject} */
270static DECLCALLBACK(int) drvscsiEject(VSCSILUN hVScsiLun, void *pvScsiLunUser)
271{
272 RT_NOREF(hVScsiLun);
273 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
274 int rc = VINF_SUCCESS;
275 RTSEMEVENT hSemEvt = NIL_RTSEMEVENT;
276
277 /* This must be done from EMT. */
278 rc = RTSemEventCreate(&hSemEvt);
279 if (RT_SUCCESS(rc))
280 {
281 PDRVSCSIEJECTSTATE pEjectState = (PDRVSCSIEJECTSTATE)PDMQueueAlloc(pThis->pQueue);
282 if (pEjectState)
283 {
284 pEjectState->hSemEvt = hSemEvt;
285 PDMQueueInsert(pThis->pQueue, &pEjectState->Core);
286
287 /* Wait for completion. */
288 rc = RTSemEventWait(pEjectState->hSemEvt, RT_INDEFINITE_WAIT);
289 if (RT_SUCCESS(rc))
290 rc = pEjectState->rcReq;
291 }
292 else
293 rc = VERR_NO_MEMORY;
294
295 RTSemEventDestroy(pEjectState->hSemEvt);
296 }
297
298 return rc;
299}
300
301/**
302 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunReqTransferEnqueue}
303 */
304static DECLCALLBACK(int) drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)
305{
306 RT_NOREF(hVScsiLun);
307 int rc = VINF_SUCCESS;
308 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
309 PDMMEDIAEXIOREQ hIoReq = DRVSCSI_VSCSIIOREQ_2_PDMMEDIAEXIOREQ(hVScsiIoReq);
310
311 LogFlowFunc(("Enqueuing hVScsiIoReq=%#p\n", hVScsiIoReq));
312
313 VSCSIIOREQTXDIR enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
314 switch (enmTxDir)
315 {
316 case VSCSIIOREQTXDIR_FLUSH:
317 {
318 rc = pThis->pDrvMediaEx->pfnIoReqFlush(pThis->pDrvMediaEx, hIoReq);
319 if ( RT_FAILURE(rc)
320 && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
321 LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
322 pThis->pDrvIns->iInstance, rc));
323 break;
324 }
325 case VSCSIIOREQTXDIR_UNMAP:
326 {
327 PCRTRANGE paRanges;
328 unsigned cRanges;
329
330 rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges);
331 AssertRC(rc);
332
333 pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
334 rc = pThis->pDrvMediaEx->pfnIoReqDiscard(pThis->pDrvMediaEx, hIoReq, cRanges);
335 if ( RT_FAILURE(rc)
336 && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
337 LogRel(("SCSI#%u: Discard returned rc=%Rrc\n",
338 pThis->pDrvIns->iInstance, rc));
339 break;
340 }
341 case VSCSIIOREQTXDIR_READ:
342 case VSCSIIOREQTXDIR_WRITE:
343 {
344 uint64_t uOffset = 0;
345 size_t cbTransfer = 0;
346 size_t cbSeg = 0;
347 PCRTSGSEG paSeg = NULL;
348 unsigned cSeg = 0;
349
350 rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer,
351 &cSeg, &cbSeg, &paSeg);
352 AssertRC(rc);
353
354 if (enmTxDir == VSCSIIOREQTXDIR_READ)
355 {
356 pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
357 rc = pThis->pDrvMediaEx->pfnIoReqRead(pThis->pDrvMediaEx, hIoReq, uOffset, cbTransfer);
358 STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer);
359 }
360 else
361 {
362 pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
363 rc = pThis->pDrvMediaEx->pfnIoReqWrite(pThis->pDrvMediaEx, hIoReq, uOffset, cbTransfer);
364 STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer);
365 }
366
367 if ( RT_FAILURE(rc)
368 && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
369 LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
370 pThis->pDrvIns->iInstance,
371 enmTxDir == VSCSIIOREQTXDIR_READ
372 ? "Read"
373 : "Write",
374 uOffset,
375 cbTransfer, rc));
376 break;
377 }
378 default:
379 AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir));
380 }
381
382 if (rc == VINF_SUCCESS)
383 {
384 if (enmTxDir == VSCSIIOREQTXDIR_READ)
385 pThis->pLed->Actual.s.fReading = 0;
386 else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
387 pThis->pLed->Actual.s.fWriting = 0;
388 else
389 AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
390
391 VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS, false);
392 rc = VINF_SUCCESS;
393 }
394 else if (rc == VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
395 rc = VINF_SUCCESS;
396 else if (RT_FAILURE(rc))
397 {
398 if (enmTxDir == VSCSIIOREQTXDIR_READ)
399 pThis->pLed->Actual.s.fReading = 0;
400 else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
401 pThis->pLed->Actual.s.fWriting = 0;
402 else
403 AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
404
405 VSCSIIoReqCompleted(hVScsiIoReq, rc, drvscsiIsRedoPossible(rc));
406 rc = VINF_SUCCESS;
407 }
408 else
409 AssertMsgFailed(("Invalid return code rc=%Rrc\n", rc));
410
411 return rc;
412}
413
414/**
415 * @interface_method_impl{VSCSILUNIOCALLBACKS,pfnVScsiLunGetFeatureFlags}
416 */
417static DECLCALLBACK(int) drvscsiGetFeatureFlags(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pfFeatures)
418{
419 RT_NOREF(hVScsiLun);
420 PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
421
422 *pfFeatures = 0;
423
424 uint32_t fFeatures = 0;
425 int rc = pThis->pDrvMediaEx->pfnQueryFeatures(pThis->pDrvMediaEx, &fFeatures);
426 if (RT_SUCCESS(rc) && (fFeatures & PDMIMEDIAEX_FEATURE_F_DISCARD))
427 *pfFeatures |= VSCSI_LUN_FEATURE_UNMAP;
428
429 if ( pThis->pDrvMedia
430 && pThis->pDrvMedia->pfnIsNonRotational(pThis->pDrvMedia))
431 *pfFeatures |= VSCSI_LUN_FEATURE_NON_ROTATIONAL;
432
433 if (pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia))
434 *pfFeatures |= VSCSI_LUN_FEATURE_READONLY;
435
436 return VINF_SUCCESS;
437}
438
439
440/* -=-=-=-=- IPortEx -=-=-=-=- */
441
442/**
443 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
444 */
445static DECLCALLBACK(int) drvscsiIoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
446 void *pvIoReqAlloc, int rcReq)
447{
448 RT_NOREF1(hIoReq);
449
450 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IPortEx);
451 VSCSIIOREQ hVScsiIoReq = DRVSCSI_PDMMEDIAEXIOREQ_2_VSCSIIOREQ(pvIoReqAlloc);
452 VSCSIIOREQTXDIR enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
453
454 LogFlowFunc(("Request hVScsiIoReq=%#p completed\n", hVScsiIoReq));
455
456 if (enmTxDir == VSCSIIOREQTXDIR_READ)
457 pThis->pLed->Actual.s.fReading = 0;
458 else if ( enmTxDir == VSCSIIOREQTXDIR_WRITE
459 || enmTxDir == VSCSIIOREQTXDIR_UNMAP)
460 pThis->pLed->Actual.s.fWriting = 0;
461 else
462 AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
463
464 if (RT_SUCCESS(rcReq))
465 VSCSIIoReqCompleted(hVScsiIoReq, rcReq, false /* fRedoPossible */);
466 else
467 {
468 pThis->cErrors++;
469 if (pThis->cErrors < MAX_LOG_REL_ERRORS)
470 {
471 if (enmTxDir == VSCSIIOREQTXDIR_FLUSH)
472 LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
473 pThis->pDrvIns->iInstance, rcReq));
474 else if (enmTxDir == VSCSIIOREQTXDIR_UNMAP)
475 LogRel(("SCSI#%u: Unmap returned rc=%Rrc\n",
476 pThis->pDrvIns->iInstance, rcReq));
477 else
478 {
479 uint64_t uOffset = 0;
480 size_t cbTransfer = 0;
481 size_t cbSeg = 0;
482 PCRTSGSEG paSeg = NULL;
483 unsigned cSeg = 0;
484
485 VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer,
486 &cSeg, &cbSeg, &paSeg);
487
488 LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
489 pThis->pDrvIns->iInstance,
490 enmTxDir == VSCSIIOREQTXDIR_READ
491 ? "Read"
492 : "Write",
493 uOffset,
494 cbTransfer, rcReq));
495 }
496 }
497
498 VSCSIIoReqCompleted(hVScsiIoReq, rcReq, drvscsiIsRedoPossible(rcReq));
499 }
500
501 return VINF_SUCCESS;
502}
503
504/**
505 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
506 */
507static DECLCALLBACK(int) drvscsiIoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
508 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
509 size_t cbCopy)
510{
511 RT_NOREF2(pInterface, hIoReq);
512
513 VSCSIIOREQ hVScsiIoReq = DRVSCSI_PDMMEDIAEXIOREQ_2_VSCSIIOREQ(pvIoReqAlloc);
514 uint64_t uOffset = 0;
515 size_t cbTransfer = 0;
516 size_t cbSeg = 0;
517 PCRTSGSEG paSeg = NULL;
518 unsigned cSeg = 0;
519 size_t cbCopied = 0;
520
521 int rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer, &cSeg, &cbSeg, &paSeg);
522 if (RT_SUCCESS(rc))
523 {
524 RTSGBUF SgBuf;
525 RTSgBufInit(&SgBuf, paSeg, cSeg);
526
527 RTSgBufAdvance(&SgBuf, offDst);
528 cbCopied = RTSgBufCopy(&SgBuf, pSgBuf, cbCopy);
529 }
530
531 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
532}
533
534/**
535 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
536 */
537static DECLCALLBACK(int) drvscsiIoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
538 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
539 size_t cbCopy)
540{
541 RT_NOREF2(pInterface, hIoReq);
542
543 VSCSIIOREQ hVScsiIoReq = DRVSCSI_PDMMEDIAEXIOREQ_2_VSCSIIOREQ(pvIoReqAlloc);
544 uint64_t uOffset = 0;
545 size_t cbTransfer = 0;
546 size_t cbSeg = 0;
547 PCRTSGSEG paSeg = NULL;
548 unsigned cSeg = 0;
549 size_t cbCopied = 0;
550
551 int rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer, &cSeg, &cbSeg, &paSeg);
552 if (RT_SUCCESS(rc))
553 {
554 RTSGBUF SgBuf;
555 RTSgBufInit(&SgBuf, paSeg, cSeg);
556
557 RTSgBufAdvance(&SgBuf, offSrc);
558 cbCopied = RTSgBufCopy(pSgBuf, &SgBuf, cbCopy);
559 }
560
561 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
562}
563
564/**
565 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqQueryDiscardRanges}
566 */
567static DECLCALLBACK(int) drvscsiIoReqQueryDiscardRanges(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
568 void *pvIoReqAlloc, uint32_t idxRangeStart,
569 uint32_t cRanges, PRTRANGE paRanges,
570 uint32_t *pcRanges)
571{
572 RT_NOREF2(pInterface, hIoReq);
573
574 VSCSIIOREQ hVScsiIoReq = DRVSCSI_PDMMEDIAEXIOREQ_2_VSCSIIOREQ(pvIoReqAlloc);
575 PCRTRANGE paRangesVScsi;
576 unsigned cRangesVScsi;
577
578 int rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRangesVScsi, &cRangesVScsi);
579 if (RT_SUCCESS(rc))
580 {
581 uint32_t cRangesCopy = RT_MIN(cRangesVScsi - idxRangeStart, cRanges);
582 Assert( idxRangeStart < cRangesVScsi
583 && (idxRangeStart + cRanges) <= cRangesVScsi);
584
585 memcpy(paRanges, &paRangesVScsi[idxRangeStart], cRangesCopy * sizeof(RTRANGE));
586 *pcRanges = cRangesCopy;
587 }
588 return rc;
589}
590
591/**
592 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
593 */
594static DECLCALLBACK(void) drvscsiIoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
595 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
596{
597 RT_NOREF2(hIoReq, pvIoReqAlloc);
598 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IPortEx);
599
600 switch (enmState)
601 {
602 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
603 {
604 /* Make sure the request is not accounted for so the VM can suspend successfully. */
605 uint32_t cTasksActive = ASMAtomicDecU32(&pThis->StatIoDepth);
606 if (!cTasksActive && pThis->fDummySignal)
607 PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
608 break;
609 }
610 case PDMMEDIAEXIOREQSTATE_ACTIVE:
611 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
612 ASMAtomicIncU32(&pThis->StatIoDepth);
613 break;
614 default:
615 AssertMsgFailed(("Invalid request state given %u\n", enmState));
616 }
617
618 pThis->pDevMediaExPort->pfnIoReqStateChanged(pThis->pDevMediaExPort, hIoReq, pvIoReqAlloc, enmState);
619}
620
621
622/* -=-=-=-=- IMedia -=-=-=-=- */
623
624/** @interface_method_impl{PDMIMEDIA,pfnGetSize} */
625static DECLCALLBACK(uint64_t) drvscsiGetSize(PPDMIMEDIA pInterface)
626{
627 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
628 return pThis->pDrvMedia->pfnGetSize(pThis->pDrvMedia);
629}
630
631/** @interface_method_impl{PDMIMEDIA,pfnGetSectorSize} */
632static DECLCALLBACK(uint32_t) drvscsiGetSectorSize(PPDMIMEDIA pInterface)
633{
634 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
635 return pThis->pDrvMedia->pfnGetSectorSize(pThis->pDrvMedia);
636}
637
638/** @interface_method_impl{PDMIMEDIA,pfnIsReadOnly} */
639static DECLCALLBACK(bool) drvscsiIsReadOnly(PPDMIMEDIA pInterface)
640{
641 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
642 return pThis->pDrvMedia->pfnIsReadOnly(pThis->pDrvMedia);
643}
644
645/** @interface_method_impl{PDMIMEDIA,pfnIsNonRotational} */
646static DECLCALLBACK(bool) drvscsiIsNonRotational(PPDMIMEDIA pInterface)
647{
648 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
649 return pThis->pDrvMedia->pfnIsNonRotational(pThis->pDrvMedia);
650}
651
652/** @interface_method_impl{PDMIMEDIA,pfnBiosGetPCHSGeometry} */
653static DECLCALLBACK(int) drvscsiBiosGetPCHSGeometry(PPDMIMEDIA pInterface,
654 PPDMMEDIAGEOMETRY pPCHSGeometry)
655{
656 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
657 return pThis->pDrvMedia->pfnBiosGetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
658}
659
660/** @interface_method_impl{PDMIMEDIA,pfnBiosSetPCHSGeometry} */
661static DECLCALLBACK(int) drvscsiBiosSetPCHSGeometry(PPDMIMEDIA pInterface,
662 PCPDMMEDIAGEOMETRY pPCHSGeometry)
663{
664 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
665 return pThis->pDrvMedia->pfnBiosSetPCHSGeometry(pThis->pDrvMedia, pPCHSGeometry);
666}
667
668/** @interface_method_impl{PDMIMEDIA,pfnBiosGetLCHSGeometry} */
669static DECLCALLBACK(int) drvscsiBiosGetLCHSGeometry(PPDMIMEDIA pInterface,
670 PPDMMEDIAGEOMETRY pLCHSGeometry)
671{
672 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
673 return pThis->pDrvMedia->pfnBiosGetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
674}
675
676/** @interface_method_impl{PDMIMEDIA,pfnBiosSetLCHSGeometry} */
677static DECLCALLBACK(int) drvscsiBiosSetLCHSGeometry(PPDMIMEDIA pInterface,
678 PCPDMMEDIAGEOMETRY pLCHSGeometry)
679{
680 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
681 return pThis->pDrvMedia->pfnBiosSetLCHSGeometry(pThis->pDrvMedia, pLCHSGeometry);
682}
683
684/** @interface_method_impl{PDMIMEDIA,pfnBiosIsVisible} */
685static DECLCALLBACK(bool) drvscsiBiosIsVisible(PPDMIMEDIA pInterface)
686{
687 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
688 return pThis->pDrvMedia->pfnBiosIsVisible(pThis->pDrvMedia);
689}
690
691/** @interface_method_impl{PDMIMEDIA,pfnGetType} */
692static DECLCALLBACK(PDMMEDIATYPE) drvscsiGetType(PPDMIMEDIA pInterface)
693{
694 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
695 VSCSILUNTYPE enmLunType;
696 PDMMEDIATYPE enmMediaType = PDMMEDIATYPE_ERROR;
697
698 int rc = VSCSIDeviceLunQueryType(pThis->hVScsiDevice, 0, &enmLunType);
699 if (RT_SUCCESS(rc))
700 {
701 switch (enmLunType)
702 {
703 case VSCSILUNTYPE_SBC:
704 enmMediaType = PDMMEDIATYPE_HARD_DISK;
705 break;
706 case VSCSILUNTYPE_MMC:
707 enmMediaType = PDMMEDIATYPE_CDROM;
708 break;
709 default:
710 enmMediaType = PDMMEDIATYPE_ERROR;
711 break;
712 }
713 }
714
715 return enmMediaType;
716}
717
718/** @interface_method_impl{PDMIMEDIA,pfnGetUuid} */
719static DECLCALLBACK(int) drvscsiGetUuid(PPDMIMEDIA pInterface, PRTUUID pUuid)
720{
721 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMedia);
722
723 int rc = VINF_SUCCESS;
724 if (pThis->pDrvMedia)
725 rc = pThis->pDrvMedia->pfnGetUuid(pThis->pDrvMedia, pUuid);
726 else
727 RTUuidClear(pUuid);
728
729 return rc;
730}
731
732/* -=-=-=-=- IMediaEx -=-=-=-=- */
733
734/** @interface_method_impl{PDMIMEDIAEX,pfnQueryFeatures} */
735static DECLCALLBACK(int) drvscsiQueryFeatures(PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)
736{
737 RT_NOREF1(pInterface);
738
739 *pfFeatures = PDMIMEDIAEX_FEATURE_F_RAWSCSICMD;
740 return VINF_SUCCESS;
741}
742
743/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAllocSizeSet} */
744static DECLCALLBACK(int) drvscsiIoReqAllocSizeSet(PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)
745{
746 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMediaEx);
747
748 pThis->cbIoReqAlloc = RT_OFFSETOF(DRVSCSIREQ, abAlloc[cbIoReqAlloc]);
749 return VINF_SUCCESS;
750}
751
752/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqAlloc} */
753static DECLCALLBACK(int) drvscsiIoReqAlloc(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc,
754 PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)
755{
756 RT_NOREF2(uIoReqId, fFlags);
757
758 int rc = VINF_SUCCESS;
759 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMediaEx);
760 PDRVSCSIREQ pReq = (PDRVSCSIREQ)RTMemAllocZ(pThis->cbIoReqAlloc);
761 if (RT_LIKELY(pReq))
762 {
763 *phIoReq = (PDMMEDIAEXIOREQ)pReq;
764 *ppvIoReqAlloc = &pReq->abAlloc[0];
765 }
766 else
767 rc = VERR_NO_MEMORY;
768
769 return rc;
770}
771
772/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFree} */
773static DECLCALLBACK(int) drvscsiIoReqFree(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
774{
775 RT_NOREF1(pInterface);
776 PDRVSCSIREQ pReq = (PDRVSCSIREQ)hIoReq;
777
778 RTMemFree(pReq);
779 return VINF_SUCCESS;
780}
781
782/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQueryResidual} */
783static DECLCALLBACK(int) drvscsiIoReqQueryResidual(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)
784{
785 RT_NOREF2(pInterface, hIoReq);
786
787 *pcbResidual = 0; /** @todo: Implement. */
788 return VINF_SUCCESS;
789}
790
791/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancelAll} */
792static DECLCALLBACK(int) drvscsiIoReqCancelAll(PPDMIMEDIAEX pInterface)
793{
794 RT_NOREF1(pInterface);
795 return VINF_SUCCESS;
796}
797
798/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqCancel} */
799static DECLCALLBACK(int) drvscsiIoReqCancel(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)
800{
801 RT_NOREF2(pInterface, uIoReqId);
802 return VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND;
803}
804
805/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqRead} */
806static DECLCALLBACK(int) drvscsiIoReqRead(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)
807{
808 RT_NOREF4(pInterface, hIoReq, off, cbRead);
809 return VERR_NOT_SUPPORTED;
810}
811
812/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqWrite} */
813static DECLCALLBACK(int) drvscsiIoReqWrite(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)
814{
815 RT_NOREF4(pInterface, hIoReq, off, cbWrite);
816 return VERR_NOT_SUPPORTED;
817}
818
819/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqFlush} */
820static DECLCALLBACK(int) drvscsiIoReqFlush(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)
821{
822 RT_NOREF2(pInterface, hIoReq);
823 return VERR_NOT_SUPPORTED;
824}
825
826/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqDiscard} */
827static DECLCALLBACK(int) drvscsiIoReqDiscard(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)
828{
829 RT_NOREF3(pInterface, hIoReq, cRangesMax);
830 return VERR_NOT_SUPPORTED;
831}
832
833/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSendScsiCmd} */
834static DECLCALLBACK(int) drvscsiIoReqSendScsiCmd(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint32_t uLun,
835 const uint8_t *pbCdb, size_t cbCdb, PDMMEDIAEXIOREQSCSITXDIR enmTxDir,
836 size_t cbBuf, uint8_t *pabSense, size_t cbSense, uint8_t *pu8ScsiSts,
837 uint32_t cTimeoutMillies)
838{
839 RT_NOREF1(cTimeoutMillies);
840
841 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMediaEx);
842 PDRVSCSIREQ pReq = (PDRVSCSIREQ)hIoReq;
843 int rc = VINF_SUCCESS;
844
845 Log(("Dump for pReq=%#p Command: %s\n", pReq, SCSICmdText(pbCdb[0])));
846 Log(("cbCdb=%u\n", cbCdb));
847 for (uint32_t i = 0; i < cbCdb; i++)
848 Log(("pbCdb[%u]=%#x\n", i, pbCdb[i]));
849 Log(("cbBuf=%zu\n", cbBuf));
850
851 pReq->enmXferDir = enmTxDir;
852 pReq->cbBuf = cbBuf;
853 pReq->pu8ScsiSts = pu8ScsiSts;
854
855 /* Allocate and sync buffers if a data transfer is indicated. */
856 if (cbBuf)
857 {
858 pReq->pvBuf = RTMemAlloc(cbBuf);
859 if (RT_UNLIKELY(!pReq->pvBuf))
860 rc = VERR_NO_MEMORY;
861 }
862
863 if (RT_SUCCESS(rc))
864 {
865 pReq->Seg.pvSeg = pReq->pvBuf;
866 pReq->Seg.cbSeg = cbBuf;
867
868 if ( cbBuf
869 && ( enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN
870 || enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE))
871 {
872 RTSGBUF SgBuf;
873 RTSgBufInit(&SgBuf, &pReq->Seg, 1);
874 rc = pThis->pDevMediaExPort->pfnIoReqCopyToBuf(pThis->pDevMediaExPort, hIoReq, &pReq->abAlloc[0],
875 0, &SgBuf, cbBuf);
876 }
877
878 if (RT_SUCCESS(rc))
879 {
880 rc = VSCSIDeviceReqCreate(pThis->hVScsiDevice, &pReq->hVScsiReq,
881 uLun, (uint8_t *)pbCdb, cbCdb, cbBuf, 1, &pReq->Seg,
882 pabSense, cbSense, pReq);
883 if (RT_SUCCESS(rc))
884 {
885 ASMAtomicIncU32(&pThis->StatIoDepth);
886 rc = VSCSIDeviceReqEnqueue(pThis->hVScsiDevice, pReq->hVScsiReq);
887 if (RT_SUCCESS(rc))
888 rc = VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS;
889 }
890 }
891 }
892
893 return rc;
894}
895
896/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetActiveCount} */
897static DECLCALLBACK(uint32_t) drvscsiIoReqGetActiveCount(PPDMIMEDIAEX pInterface)
898{
899 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMediaEx);
900 return pThis->StatIoDepth;
901}
902
903/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqGetSuspendedCount} */
904static DECLCALLBACK(uint32_t) drvscsiIoReqGetSuspendedCount(PPDMIMEDIAEX pInterface)
905{
906 RT_NOREF1(pInterface);
907 return 0;
908}
909
910/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedStart} */
911static DECLCALLBACK(int) drvscsiIoReqQuerySuspendedStart(PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)
912{
913 RT_NOREF3(pInterface, phIoReq, ppvIoReqAlloc);
914 return VERR_NOT_IMPLEMENTED;
915}
916
917/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqQuerySuspendedNext} */
918static DECLCALLBACK(int) drvscsiIoReqQuerySuspendedNext(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq,
919 PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)
920{
921 RT_NOREF4(pInterface, hIoReq, phIoReqNext, ppvIoReqAllocNext);
922 return VERR_NOT_IMPLEMENTED;
923}
924
925/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedSave} */
926static DECLCALLBACK(int) drvscsiIoReqSuspendedSave(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
927{
928 RT_NOREF3(pInterface, pSSM, hIoReq);
929 return VERR_NOT_IMPLEMENTED;
930}
931
932/** @interface_method_impl{PDMIMEDIAEX,pfnIoReqSuspendedLoad} */
933static DECLCALLBACK(int) drvscsiIoReqSuspendedLoad(PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)
934{
935 RT_NOREF3(pInterface, pSSM, hIoReq);
936 return VERR_NOT_IMPLEMENTED;
937}
938
939
940static DECLCALLBACK(void) drvscsiIoReqVScsiReqCompleted(VSCSIDEVICE hVScsiDevice, void *pVScsiDeviceUser,
941 void *pVScsiReqUser, int rcScsiCode, bool fRedoPossible, int rcReq)
942{
943 RT_NOREF2(hVScsiDevice, fRedoPossible);
944 PDRVSCSI pThis = (PDRVSCSI)pVScsiDeviceUser;
945 PDRVSCSIREQ pReq = (PDRVSCSIREQ)pVScsiReqUser;
946
947 ASMAtomicDecU32(&pThis->StatIoDepth);
948
949 /* Sync buffers. */
950 if ( RT_SUCCESS(rcReq)
951 && pReq->cbBuf
952 && ( pReq->enmXferDir == PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN
953 || pReq->enmXferDir == PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE))
954 {
955 RTSGBUF SgBuf;
956 RTSgBufInit(&SgBuf, &pReq->Seg, 1);
957 int rcCopy = pThis->pDevMediaExPort->pfnIoReqCopyFromBuf(pThis->pDevMediaExPort, (PDMMEDIAEXIOREQ)pReq,
958 &pReq->abAlloc[0], 0, &SgBuf, pReq->cbBuf);
959 if (RT_FAILURE(rcCopy))
960 rcReq = rcCopy;
961 }
962
963 if (pReq->pvBuf)
964 {
965 RTMemFree(pReq->pvBuf);
966 pReq->pvBuf = NULL;
967 }
968
969 *pReq->pu8ScsiSts = (uint8_t)rcScsiCode;
970 int rc = pThis->pDevMediaExPort->pfnIoReqCompleteNotify(pThis->pDevMediaExPort, (PDMMEDIAEXIOREQ)pReq,
971 &pReq->abAlloc[0], rcReq);
972 AssertRC(rc); RT_NOREF(rc);
973
974 if (RT_UNLIKELY(pThis->fDummySignal) && !pThis->StatIoDepth)
975 PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
976}
977
978/**
979 * Consumer for the queue
980 *
981 * @returns Success indicator.
982 * If false the item will not be removed and the flushing will stop.
983 * @param pDrvIns The driver instance.
984 * @param pItem The item to consume. Upon return this item will be freed.
985 */
986static DECLCALLBACK(bool) drvscsiR3NotifyQueueConsumer(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItem)
987{
988 PDRVSCSIEJECTSTATE pEjectState = (PDRVSCSIEJECTSTATE)pItem;
989 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
990
991 int rc = pThis->pDrvMount->pfnUnmount(pThis->pDrvMount, false/*=fForce*/, true/*=fEject*/);
992 Assert(RT_SUCCESS(rc) || rc == VERR_PDM_MEDIA_LOCKED || rc == VERR_PDM_MEDIA_NOT_MOUNTED);
993 if (RT_SUCCESS(rc))
994 pThis->pDevMediaExPort->pfnMediumEjected(pThis->pDevMediaExPort);
995
996 pEjectState->rcReq = rc;
997 RTSemEventSignal(pEjectState->hSemEvt);
998 return true;
999}
1000
1001/* -=-=-=-=- IBase -=-=-=-=- */
1002
1003/**
1004 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1005 */
1006static DECLCALLBACK(void *) drvscsiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1007{
1008 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1009 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1010
1011 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNT, pThis->pDrvMount);
1012 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1013 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEX, pThis->pDevMediaExPort ? &pThis->IMediaEx : NULL);
1014 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIA, pThis->pDrvMedia ? &pThis->IMedia : NULL);
1015 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->IPort);
1016 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUNTNOTIFY, &pThis->IMountNotify);
1017 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->IPortEx);
1018 return NULL;
1019}
1020
1021static DECLCALLBACK(int) drvscsiQueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
1022 uint32_t *piInstance, uint32_t *piLUN)
1023{
1024 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IPort);
1025
1026 return pThis->pDevMediaPort->pfnQueryDeviceLocation(pThis->pDevMediaPort, ppcszController,
1027 piInstance, piLUN);
1028}
1029
1030/**
1031 * Called when media is mounted.
1032 *
1033 * @param pInterface Pointer to the interface structure containing the called function pointer.
1034 */
1035static DECLCALLBACK(void) drvscsiMountNotify(PPDMIMOUNTNOTIFY pInterface)
1036{
1037 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMountNotify);
1038 LogFlowFunc(("mounting LUN#%p\n", pThis->hVScsiLun));
1039
1040 /* Ignore the call if we're called while being attached. */
1041 if (!pThis->pDrvMedia)
1042 return;
1043
1044 /* Let the LUN know that a medium was mounted. */
1045 VSCSILunMountNotify(pThis->hVScsiLun);
1046}
1047
1048/**
1049 * Called when media is unmounted
1050 *
1051 * @param pInterface Pointer to the interface structure containing the called function pointer.
1052 */
1053static DECLCALLBACK(void) drvscsiUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
1054{
1055 PDRVSCSI pThis = RT_FROM_MEMBER(pInterface, DRVSCSI, IMountNotify);
1056 LogFlowFunc(("unmounting LUN#%p\n", pThis->hVScsiLun));
1057
1058 /* Let the LUN know that the medium was unmounted. */
1059 VSCSILunUnmountNotify(pThis->hVScsiLun);
1060}
1061
1062/**
1063 * Worker for drvscsiReset, drvscsiSuspend and drvscsiPowerOff.
1064 *
1065 * @param pDrvIns The driver instance.
1066 * @param pfnAsyncNotify The async callback.
1067 */
1068static void drvscsiR3ResetOrSuspendOrPowerOff(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1069{
1070 RT_NOREF1(pfnAsyncNotify);
1071
1072 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1073
1074 if (pThis->StatIoDepth > 0)
1075 ASMAtomicWriteBool(&pThis->fDummySignal, true);
1076}
1077
1078/**
1079 * Callback employed by drvscsiSuspend and drvscsiPowerOff.
1080 *
1081 * @returns true if we've quiesced, false if we're still working.
1082 * @param pDrvIns The driver instance.
1083 */
1084static DECLCALLBACK(bool) drvscsiIsAsyncSuspendOrPowerOffDone(PPDMDRVINS pDrvIns)
1085{
1086 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1087
1088 if (pThis->StatIoDepth > 0)
1089 return false;
1090 else
1091 return true;
1092}
1093
1094/**
1095 * @copydoc FNPDMDRVPOWEROFF
1096 */
1097static DECLCALLBACK(void) drvscsiPowerOff(PPDMDRVINS pDrvIns)
1098{
1099 drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
1100}
1101
1102/**
1103 * @copydoc FNPDMDRVSUSPEND
1104 */
1105static DECLCALLBACK(void) drvscsiSuspend(PPDMDRVINS pDrvIns)
1106{
1107 drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
1108}
1109
1110/**
1111 * Callback employed by drvscsiReset.
1112 *
1113 * @returns true if we've quiesced, false if we're still working.
1114 * @param pDrvIns The driver instance.
1115 */
1116static DECLCALLBACK(bool) drvscsiIsAsyncResetDone(PPDMDRVINS pDrvIns)
1117{
1118 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1119
1120 if (pThis->StatIoDepth > 0)
1121 return false;
1122 else
1123 return true;
1124}
1125
1126/** @copydoc FNPDMDRVATTACH */
1127static DECLCALLBACK(int) drvscsiAttach(PPDMDRVINS pDrvIns, uint32_t fFlags)
1128{
1129 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1130
1131 LogFlowFunc(("pDrvIns=%#p fFlags=%#x\n", pDrvIns, fFlags));
1132
1133 AssertMsgReturn((fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
1134 ("SCSI: Hotplugging is not supported\n"),
1135 VERR_INVALID_PARAMETER);
1136
1137 /*
1138 * Try attach driver below and query it's media interface.
1139 */
1140 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase);
1141 AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc);
1142
1143 /*
1144 * Query the media interface.
1145 */
1146 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIA);
1147 AssertMsgReturn(VALID_PTR(pThis->pDrvMedia), ("VSCSI configuration error: No media interface!\n"),
1148 VERR_PDM_MISSING_INTERFACE);
1149
1150 /* Query the extended media interface. */
1151 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIAEX);
1152 AssertMsgReturn(VALID_PTR(pThis->pDrvMediaEx), ("VSCSI configuration error: No extended media interface!\n"),
1153 VERR_PDM_MISSING_INTERFACE);
1154
1155 pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT);
1156
1157 if (pThis->cbVScsiIoReqAlloc)
1158 {
1159 rc = pThis->pDrvMediaEx->pfnIoReqAllocSizeSet(pThis->pDrvMediaEx, pThis->cbVScsiIoReqAlloc);
1160 AssertMsgReturn(RT_SUCCESS(rc), ("Setting the I/O request allocation size failed with rc=%Rrc\n", rc), rc);
1161 }
1162
1163 if (pThis->pDrvMount)
1164 {
1165 if (pThis->pDrvMount->pfnIsMounted(pThis->pDrvMount))
1166 {
1167 rc = VINF_SUCCESS; VSCSILunMountNotify(pThis->hVScsiLun);
1168 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being mounted\n"), rc);
1169 }
1170 else
1171 {
1172 rc = VINF_SUCCESS; VSCSILunUnmountNotify(pThis->hVScsiLun);
1173 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being unmounted\n"), rc);
1174 }
1175 }
1176
1177 return rc;
1178}
1179
1180/** @copydoc FNPDMDRVDETACH */
1181static DECLCALLBACK(void) drvscsiDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
1182{
1183 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1184
1185 LogFlowFunc(("pDrvIns=%#p fFlags=%#x\n", pDrvIns, fFlags));
1186
1187 AssertMsgReturnVoid((fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG),
1188 ("SCSI: Hotplugging is not supported\n"));
1189
1190 /*
1191 * Zero some important members.
1192 */
1193 pThis->pDrvBase = NULL;
1194 pThis->pDrvMedia = NULL;
1195 pThis->pDrvMediaEx = NULL;
1196 pThis->pDrvMount = NULL;
1197
1198 VSCSILunUnmountNotify(pThis->hVScsiLun);
1199}
1200
1201/**
1202 * @copydoc FNPDMDRVRESET
1203 */
1204static DECLCALLBACK(void) drvscsiReset(PPDMDRVINS pDrvIns)
1205{
1206 drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncResetDone);
1207}
1208
1209/**
1210 * Destruct a driver instance.
1211 *
1212 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1213 * resources can be freed correctly.
1214 *
1215 * @param pDrvIns The driver instance data.
1216 */
1217static DECLCALLBACK(void) drvscsiDestruct(PPDMDRVINS pDrvIns)
1218{
1219 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1220 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1221
1222 /* Free the VSCSI device and LUN handle. */
1223 if (pThis->hVScsiDevice)
1224 {
1225 VSCSILUN hVScsiLun;
1226 int rc = VSCSIDeviceLunDetach(pThis->hVScsiDevice, 0, &hVScsiLun);
1227 AssertRC(rc);
1228
1229 Assert(hVScsiLun == pThis->hVScsiLun);
1230 rc = VSCSILunDestroy(hVScsiLun);
1231 AssertRC(rc);
1232 rc = VSCSIDeviceDestroy(pThis->hVScsiDevice);
1233 AssertRC(rc);
1234
1235 pThis->hVScsiDevice = NULL;
1236 pThis->hVScsiLun = NULL;
1237 }
1238
1239 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesRead);
1240 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatBytesWritten);
1241 PDMDrvHlpSTAMDeregister(pDrvIns, (void *)&pThis->StatIoDepth);
1242}
1243
1244/**
1245 * Construct a block driver instance.
1246 *
1247 * @copydoc FNPDMDRVCONSTRUCT
1248 */
1249static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1250{
1251 int rc = VINF_SUCCESS;
1252 PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
1253 LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg));
1254 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1255
1256 /*
1257 * Initialize the instance data.
1258 */
1259 pThis->pDrvIns = pDrvIns;
1260
1261 pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface;
1262
1263 /* IMedia */
1264 pThis->IMedia.pfnRead = NULL;
1265 pThis->IMedia.pfnReadPcBios = NULL;
1266 pThis->IMedia.pfnWrite = NULL;
1267 pThis->IMedia.pfnFlush = NULL;
1268 pThis->IMedia.pfnSendCmd = NULL;
1269 pThis->IMedia.pfnMerge = NULL;
1270 pThis->IMedia.pfnSetSecKeyIf = NULL;
1271 pThis->IMedia.pfnGetSize = drvscsiGetSize;
1272 pThis->IMedia.pfnGetSectorSize = drvscsiGetSectorSize;
1273 pThis->IMedia.pfnIsReadOnly = drvscsiIsReadOnly;
1274 pThis->IMedia.pfnIsNonRotational = drvscsiIsNonRotational;
1275 pThis->IMedia.pfnBiosGetPCHSGeometry = drvscsiBiosGetPCHSGeometry;
1276 pThis->IMedia.pfnBiosSetPCHSGeometry = drvscsiBiosSetPCHSGeometry;
1277 pThis->IMedia.pfnBiosGetLCHSGeometry = drvscsiBiosGetLCHSGeometry;
1278 pThis->IMedia.pfnBiosSetLCHSGeometry = drvscsiBiosSetLCHSGeometry;
1279 pThis->IMedia.pfnBiosIsVisible = drvscsiBiosIsVisible;
1280 pThis->IMedia.pfnGetType = drvscsiGetType;
1281 pThis->IMedia.pfnGetUuid = drvscsiGetUuid;
1282 pThis->IMedia.pfnDiscard = NULL;
1283
1284 /* IMediaEx */
1285 pThis->IMediaEx.pfnQueryFeatures = drvscsiQueryFeatures;
1286 pThis->IMediaEx.pfnIoReqAllocSizeSet = drvscsiIoReqAllocSizeSet;
1287 pThis->IMediaEx.pfnIoReqAlloc = drvscsiIoReqAlloc;
1288 pThis->IMediaEx.pfnIoReqFree = drvscsiIoReqFree;
1289 pThis->IMediaEx.pfnIoReqQueryResidual = drvscsiIoReqQueryResidual;
1290 pThis->IMediaEx.pfnIoReqCancelAll = drvscsiIoReqCancelAll;
1291 pThis->IMediaEx.pfnIoReqCancel = drvscsiIoReqCancel;
1292 pThis->IMediaEx.pfnIoReqRead = drvscsiIoReqRead;
1293 pThis->IMediaEx.pfnIoReqWrite = drvscsiIoReqWrite;
1294 pThis->IMediaEx.pfnIoReqFlush = drvscsiIoReqFlush;
1295 pThis->IMediaEx.pfnIoReqDiscard = drvscsiIoReqDiscard;
1296 pThis->IMediaEx.pfnIoReqSendScsiCmd = drvscsiIoReqSendScsiCmd;
1297 pThis->IMediaEx.pfnIoReqGetActiveCount = drvscsiIoReqGetActiveCount;
1298 pThis->IMediaEx.pfnIoReqGetSuspendedCount = drvscsiIoReqGetSuspendedCount;
1299 pThis->IMediaEx.pfnIoReqQuerySuspendedStart = drvscsiIoReqQuerySuspendedStart;
1300 pThis->IMediaEx.pfnIoReqQuerySuspendedNext = drvscsiIoReqQuerySuspendedNext;
1301 pThis->IMediaEx.pfnIoReqSuspendedSave = drvscsiIoReqSuspendedSave;
1302 pThis->IMediaEx.pfnIoReqSuspendedLoad = drvscsiIoReqSuspendedLoad;
1303
1304 pThis->IMountNotify.pfnMountNotify = drvscsiMountNotify;
1305 pThis->IMountNotify.pfnUnmountNotify = drvscsiUnmountNotify;
1306 pThis->IPort.pfnQueryDeviceLocation = drvscsiQueryDeviceLocation;
1307 pThis->IPortEx.pfnIoReqCompleteNotify = drvscsiIoReqCompleteNotify;
1308 pThis->IPortEx.pfnIoReqCopyFromBuf = drvscsiIoReqCopyFromBuf;
1309 pThis->IPortEx.pfnIoReqCopyToBuf = drvscsiIoReqCopyToBuf;
1310 pThis->IPortEx.pfnIoReqQueryDiscardRanges = drvscsiIoReqQueryDiscardRanges;
1311 pThis->IPortEx.pfnIoReqStateChanged = drvscsiIoReqStateChanged;
1312
1313 /* Query the optional media port interface above. */
1314 pThis->pDevMediaPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAPORT);
1315
1316 /* Query the optional extended media port interface above. */
1317 pThis->pDevMediaExPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIMEDIAEXPORT);
1318
1319 AssertMsgReturn(pThis->pDevMediaExPort,
1320 ("Missing extended media port interface above\n"), VERR_PDM_MISSING_INTERFACE);
1321
1322 /* Query the optional LED interface above. */
1323 pThis->pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
1324 if (pThis->pLedPort != NULL)
1325 {
1326 /* Get The Led. */
1327 rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed);
1328 if (RT_FAILURE(rc))
1329 pThis->pLed = &pThis->Led;
1330 }
1331 else
1332 pThis->pLed = &pThis->Led;
1333
1334 /*
1335 * Validate and read configuration.
1336 */
1337 if (!CFGMR3AreValuesValid(pCfg, ""))
1338 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1339 N_("SCSI configuration error: unknown option specified"));
1340
1341 /*
1342 * Try attach driver below and query it's media interface.
1343 */
1344 rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase);
1345 AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc);
1346
1347 /*
1348 * Query the media interface.
1349 */
1350 pThis->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIA);
1351 AssertMsgReturn(VALID_PTR(pThis->pDrvMedia), ("VSCSI configuration error: No media interface!\n"),
1352 VERR_PDM_MISSING_INTERFACE);
1353
1354 /* Query the extended media interface. */
1355 pThis->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMEDIAEX);
1356 AssertMsgReturn(VALID_PTR(pThis->pDrvMediaEx), ("VSCSI configuration error: No extended media interface!\n"),
1357 VERR_PDM_MISSING_INTERFACE);
1358
1359 pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT);
1360
1361 PDMMEDIATYPE enmType = pThis->pDrvMedia->pfnGetType(pThis->pDrvMedia);
1362 VSCSILUNTYPE enmLunType;
1363 switch (enmType)
1364 {
1365 case PDMMEDIATYPE_HARD_DISK:
1366 enmLunType = VSCSILUNTYPE_SBC;
1367 break;
1368 case PDMMEDIATYPE_CDROM:
1369 case PDMMEDIATYPE_DVD:
1370 enmLunType = VSCSILUNTYPE_MMC;
1371 break;
1372 default:
1373 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS,
1374 N_("Only hard disks and CD/DVD-ROMs are currently supported as SCSI devices (enmType=%d)"),
1375 enmType);
1376 }
1377 if ( ( enmType == PDMMEDIATYPE_DVD
1378 || enmType == PDMMEDIATYPE_CDROM)
1379 && !pThis->pDrvMount)
1380 {
1381 AssertMsgFailed(("Internal error: cdrom without a mountable interface\n"));
1382 return VERR_INTERNAL_ERROR;
1383 }
1384
1385 /* Create VSCSI device and LUN. */
1386 pThis->VScsiIoCallbacks.pfnVScsiLunReqAllocSizeSet = drvscsiReqAllocSizeSet;
1387 pThis->VScsiIoCallbacks.pfnVScsiLunReqAlloc = drvscsiReqAlloc;
1388 pThis->VScsiIoCallbacks.pfnVScsiLunReqFree = drvscsiReqFree;
1389 pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize;
1390 pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSectorSize = drvscsiGetSectorSize;
1391 pThis->VScsiIoCallbacks.pfnVScsiLunMediumEject = drvscsiEject;
1392 pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue;
1393 pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags;
1394 pThis->VScsiIoCallbacks.pfnVScsiLunMediumSetLock = drvscsiSetLock;
1395
1396 rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiIoReqVScsiReqCompleted, pThis);
1397 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n", rc), rc);
1398 rc = VSCSILunCreate(&pThis->hVScsiLun, enmLunType, &pThis->VScsiIoCallbacks,
1399 pThis);
1400 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI LUN rc=%Rrc\n", rc), rc);
1401 rc = VSCSIDeviceLunAttach(pThis->hVScsiDevice, pThis->hVScsiLun, 0);
1402 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to attached the LUN to the SCSI device\n"), rc);
1403
1404 /// @todo This is a very hacky way of telling the LUN whether a medium was mounted.
1405 // The mount/unmount interface doesn't work in a very sensible manner!
1406 if (pThis->pDrvMount)
1407 {
1408 if (pThis->pDrvMount->pfnIsMounted(pThis->pDrvMount))
1409 {
1410 rc = VINF_SUCCESS; VSCSILunMountNotify(pThis->hVScsiLun);
1411 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being mounted\n"), rc);
1412 }
1413 else
1414 {
1415 rc = VINF_SUCCESS; VSCSILunUnmountNotify(pThis->hVScsiLun);
1416 AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being unmounted\n"), rc);
1417 }
1418 }
1419
1420 const char *pszCtrl = NULL;
1421 uint32_t iCtrlInstance = 0;
1422 uint32_t iCtrlLun = 0;
1423
1424 rc = pThis->pDevMediaPort->pfnQueryDeviceLocation(pThis->pDevMediaPort, &pszCtrl, &iCtrlInstance, &iCtrlLun);
1425 if (RT_SUCCESS(rc))
1426 {
1427 const char *pszCtrlId = strcmp(pszCtrl, "Msd") == 0 ? "USB"
1428 : strcmp(pszCtrl, "lsilogicsas") == 0 ? "SAS"
1429 : "SCSI";
1430 /* Register statistics counter. */
1431 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
1432 "Amount of data read.", "/Devices/%s%u/%u/ReadBytes", pszCtrlId, iCtrlInstance, iCtrlLun);
1433 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
1434 "Amount of data written.", "/Devices/%s%u/%u/WrittenBytes", pszCtrlId, iCtrlInstance, iCtrlLun);
1435 PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->StatIoDepth, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
1436 "Number of active tasks.", "/Devices/%s%u/%u/IoDepth", pszCtrlId, iCtrlInstance, iCtrlLun);
1437 }
1438
1439 pThis->StatIoDepth = 0;
1440
1441 uint32_t fFeatures = 0;
1442 rc = pThis->pDrvMediaEx->pfnQueryFeatures(pThis->pDrvMediaEx, &fFeatures);
1443 if (RT_FAILURE(rc))
1444 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1445 N_("VSCSI configuration error: Failed to query features of device"));
1446 if (fFeatures & PDMIMEDIAEX_FEATURE_F_DISCARD)
1447 LogRel(("SCSI#%d: Enabled UNMAP support\n", pDrvIns->iInstance));
1448
1449 rc = PDMDrvHlpQueueCreate(pDrvIns, sizeof(DRVSCSIEJECTSTATE), 1, 0, drvscsiR3NotifyQueueConsumer,
1450 "SCSI-Eject", &pThis->pQueue);
1451 if (RT_FAILURE(rc))
1452 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1453 N_("VSCSI configuration error: Failed to create notification queue"));
1454
1455 return VINF_SUCCESS;
1456}
1457
1458/**
1459 * SCSI driver registration record.
1460 */
1461const PDMDRVREG g_DrvSCSI =
1462{
1463 /* u32Version */
1464 PDM_DRVREG_VERSION,
1465 /* szName */
1466 "SCSI",
1467 /* szRCMod */
1468 "",
1469 /* szR0Mod */
1470 "",
1471 /* pszDescription */
1472 "Generic SCSI driver.",
1473 /* fFlags */
1474 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1475 /* fClass. */
1476 PDM_DRVREG_CLASS_SCSI,
1477 /* cMaxInstances */
1478 ~0U,
1479 /* cbInstance */
1480 sizeof(DRVSCSI),
1481 /* pfnConstruct */
1482 drvscsiConstruct,
1483 /* pfnDestruct */
1484 drvscsiDestruct,
1485 /* pfnRelocate */
1486 NULL,
1487 /* pfnIOCtl */
1488 NULL,
1489 /* pfnPowerOn */
1490 NULL,
1491 /* pfnReset */
1492 drvscsiReset,
1493 /* pfnSuspend */
1494 drvscsiSuspend,
1495 /* pfnResume */
1496 NULL,
1497 /* pfnAttach */
1498 drvscsiAttach,
1499 /* pfnDetach */
1500 drvscsiDetach,
1501 /* pfnPowerOff */
1502 drvscsiPowerOff,
1503 /* pfnSoftReset */
1504 NULL,
1505 /* u32EndVersion */
1506 PDM_DRVREG_VERSION
1507};
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