VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/UsbMsd.cpp@ 53097

Last change on this file since 53097 was 53097, checked in by vboxsync, 10 years ago

USB: Beginnings of emulated USB3 devices.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.3 KB
Line 
1/* $Id: UsbMsd.cpp 53097 2014-10-20 17:37:27Z vboxsync $ */
2/** @file
3 * UsbMSD - USB Mass Storage Device Emulation.
4 */
5
6/*
7 * Copyright (C) 2007-2012 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_USB_MSD
22#include <VBox/vmm/pdmusb.h>
23#include <VBox/log.h>
24#include <VBox/err.h>
25#include <VBox/scsi.h>
26#include <iprt/assert.h>
27#include <iprt/critsect.h>
28#include <iprt/mem.h>
29#include <iprt/semaphore.h>
30#include <iprt/string.h>
31#include <iprt/uuid.h>
32#include "VBoxDD.h"
33
34
35/*******************************************************************************
36* Defined Constants And Macros *
37*******************************************************************************/
38/** @name USB MSD string IDs
39 * @{ */
40#define USBMSD_STR_ID_MANUFACTURER 1
41#define USBMSD_STR_ID_PRODUCT_HD 2
42#define USBMSD_STR_ID_PRODUCT_CDROM 3
43/** @} */
44
45/** @name USB MSD vendor and product IDs
46 * @{ */
47#define VBOX_USB_VENDOR 0x80EE
48#define USBMSD_PID_HD 0x0030
49#define USBMSD_PID_CD 0x0031
50/** @} */
51
52/** Saved state version. */
53#define USB_MSD_SAVED_STATE_VERSION 1
54
55/*******************************************************************************
56* Structures and Typedefs *
57*******************************************************************************/
58
59/**
60 * USB MSD Command Block Wrapper or CBW. The command block
61 * itself (CBWCB) contains protocol-specific data (here SCSI).
62 */
63#pragma pack(1)
64typedef struct USBCBW
65{
66 uint32_t dCBWSignature;
67#define USBCBW_SIGNATURE UINT32_C(0x43425355)
68 uint32_t dCBWTag;
69 uint32_t dCBWDataTransferLength;
70 uint8_t bmCBWFlags;
71#define USBCBW_DIR_MASK RT_BIT(7)
72#define USBCBW_DIR_OUT 0
73#define USBCBW_DIR_IN RT_BIT(7)
74 uint8_t bCBWLun;
75 uint8_t bCBWCBLength;
76 uint8_t CBWCB[16];
77} USBCBW;
78#pragma pack()
79AssertCompileSize(USBCBW, 31);
80/** Pointer to a Command Block Wrapper. */
81typedef USBCBW *PUSBCBW;
82/** Pointer to a const Command Block Wrapper. */
83typedef const USBCBW *PCUSBCBW;
84
85/**
86 * USB MSD Command Status Wrapper or CSW.
87 */
88#pragma pack(1)
89typedef struct USBCSW
90{
91 uint32_t dCSWSignature;
92#define USBCSW_SIGNATURE UINT32_C(0x53425355)
93 uint32_t dCSWTag;
94 uint32_t dCSWDataResidue;
95#define USBCSW_STATUS_OK UINT8_C(0)
96#define USBCSW_STATUS_FAILED UINT8_C(1)
97#define USBCSW_STATUS_PHASE_ERROR UINT8_C(2)
98 uint8_t bCSWStatus;
99} USBCSW;
100#pragma pack()
101AssertCompileSize(USBCSW, 13);
102/** Pointer to a Command Status Wrapper. */
103typedef USBCSW *PUSBCSW;
104/** Pointer to a const Command Status Wrapper. */
105typedef const USBCSW *PCUSBCSW;
106
107
108/**
109 * The USB MSD request state.
110 */
111typedef enum USBMSDREQSTATE
112{
113 /** Invalid status. */
114 USBMSDREQSTATE_INVALID = 0,
115 /** Ready to receive a new SCSI command. */
116 USBMSDREQSTATE_READY,
117 /** Waiting for the host to supply data. */
118 USBMSDREQSTATE_DATA_FROM_HOST,
119 /** The SCSI request is being executed by the driver. */
120 USBMSDREQSTATE_EXECUTING,
121 /** Have (more) data for the host. */
122 USBMSDREQSTATE_DATA_TO_HOST,
123 /** Waiting to supply status information to the host. */
124 USBMSDREQSTATE_STATUS,
125 /** Destroy the request upon completion.
126 * This is set when the SCSI request doesn't complete before for the device or
127 * mass storage reset operation times out. USBMSD::pReq will be set to NULL
128 * and the only reference to this request will be with DrvSCSI. */
129 USBMSDREQSTATE_DESTROY_ON_COMPLETION,
130 /** The end of the valid states. */
131 USBMSDREQSTATE_END,
132 /** 32bit blow up hack. */
133 USBMSDREQSTATE_32BIT_HACK = 0x7fffffff
134} USBMSDREQSTATE;
135
136
137/**
138 * A pending USB MSD request.
139 */
140typedef struct USBMSDREQ
141{
142 /** The state of the request. */
143 USBMSDREQSTATE enmState;
144 /** The size of the data buffer. */
145 uint32_t cbBuf;
146 /** Pointer to the data buffer. */
147 uint8_t *pbBuf;
148 /** Current buffer offset. */
149 uint32_t offBuf;
150 /** The current Cbw when we're in the pending state. */
151 USBCBW Cbw;
152 /** The current SCSI request. */
153 PDMSCSIREQUEST ScsiReq;
154 /** The scatter-gather segment used by ScsiReq for describing pbBuf. */
155 RTSGSEG ScsiReqSeg;
156 /** The sense buffer for the current SCSI request. */
157 uint8_t ScsiReqSense[64];
158 /** The status of a completed SCSI request. */
159 int iScsiReqStatus;
160 /** Set if the request structure must be destroyed when the SCSI driver
161 * completes it. This is used to deal with requests that runs while the
162 * device is being reset. */
163 bool fDestoryOnCompletion;
164 /** Pointer to the USB device instance owning it. */
165 PPDMUSBINS pUsbIns;
166} USBMSDREQ;
167/** Pointer to a USB MSD request. */
168typedef USBMSDREQ *PUSBMSDREQ;
169
170
171/**
172 * Endpoint status data.
173 */
174typedef struct USBMSDEP
175{
176 bool fHalted;
177} USBMSDEP;
178/** Pointer to the endpoint status. */
179typedef USBMSDEP *PUSBMSDEP;
180
181
182/**
183 * A URB queue.
184 */
185typedef struct USBMSDURBQUEUE
186{
187 /** The head pointer. */
188 PVUSBURB pHead;
189 /** Where to insert the next entry. */
190 PVUSBURB *ppTail;
191} USBMSDURBQUEUE;
192/** Pointer to a URB queue. */
193typedef USBMSDURBQUEUE *PUSBMSDURBQUEUE;
194/** Pointer to a const URB queue. */
195typedef USBMSDURBQUEUE const *PCUSBMSDURBQUEUE;
196
197
198/**
199 * The USB MSD instance data.
200 */
201typedef struct USBMSD
202{
203 /** Pointer back to the PDM USB Device instance structure. */
204 PPDMUSBINS pUsbIns;
205 /** Critical section protecting the device state. */
206 RTCRITSECT CritSect;
207
208 /** The current configuration.
209 * (0 - default, 1 - the only, i.e configured.) */
210 uint8_t bConfigurationValue;
211#if 0
212 /** The state of the MSD (state machine).*/
213 USBMSDSTATE enmState;
214#endif
215 /** Endpoint 0 is the default control pipe, 1 is the host->dev bulk pipe and 2
216 * is the dev->host one. */
217 USBMSDEP aEps[3];
218 /** The current request. */
219 PUSBMSDREQ pReq;
220
221 /** Pending to-host queue.
222 * The URBs waiting here are pending the completion of the current request and
223 * data or status to become available.
224 */
225 USBMSDURBQUEUE ToHostQueue;
226
227 /** Done queue
228 * The URBs stashed here are waiting to be reaped. */
229 USBMSDURBQUEUE DoneQueue;
230 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
231 * is set. */
232 RTSEMEVENT hEvtDoneQueue;
233 /** Someone is waiting on the done queue. */
234 bool fHaveDoneQueueWaiter;
235
236 /** Whether to signal the reset semaphore when the current request completes. */
237 bool fSignalResetSem;
238 /** Semaphore usbMsdUsbReset waits on when a request is executing at reset
239 * time. Only signalled when fSignalResetSem is set. */
240 RTSEMEVENTMULTI hEvtReset;
241 /** The reset URB.
242 * This is waiting for SCSI request completion before finishing the reset. */
243 PVUSBURB pResetUrb;
244 /** Indicates that PDMUsbHlpAsyncNotificationCompleted should be called when
245 * the MSD is entering the idle state. */
246 volatile bool fSignalIdle;
247
248 /**
249 * LUN\#0 data.
250 */
251 struct
252 {
253 /** The base interface for LUN\#0. */
254 PDMIBASE IBase;
255 /** The SCSI port interface for LUN\#0 */
256 PDMISCSIPORT IScsiPort;
257
258 /** The base interface for the SCSI driver connected to LUN\#0. */
259 PPDMIBASE pIBase;
260 /** The SCSI connector interface for the SCSI driver connected to LUN\#0. */
261 PPDMISCSICONNECTOR pIScsiConnector;
262 } Lun0;
263
264} USBMSD;
265/** Pointer to the USB MSD instance data. */
266typedef USBMSD *PUSBMSD;
267
268
269/*******************************************************************************
270* Global Variables *
271*******************************************************************************/
272static const PDMUSBDESCCACHESTRING g_aUsbMsdStrings_en_US[] =
273{
274 { USBMSD_STR_ID_MANUFACTURER, "VirtualBox" },
275 { USBMSD_STR_ID_PRODUCT_HD, "USB Harddisk" },
276 { USBMSD_STR_ID_PRODUCT_CDROM, "USB CD-ROM" }
277};
278
279static const PDMUSBDESCCACHELANG g_aUsbMsdLanguages[] =
280{
281 { 0x0409, RT_ELEMENTS(g_aUsbMsdStrings_en_US), g_aUsbMsdStrings_en_US }
282};
283
284static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsFS[2] =
285{
286 {
287 {
288 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
289 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
290 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
291 /* .bmAttributes = */ 2 /* bulk */,
292 /* .wMaxPacketSize = */ 64 /* maximum possible */,
293 /* .bInterval = */ 0 /* not applicable for bulk EP */
294 },
295 /* .pvMore = */ NULL,
296 /* .pvClass = */ NULL,
297 /* .cbClass = */ 0
298 },
299 {
300 {
301 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
302 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
303 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
304 /* .bmAttributes = */ 2 /* bulk */,
305 /* .wMaxPacketSize = */ 64 /* maximum possible */,
306 /* .bInterval = */ 0 /* not applicable for bulk EP */
307 },
308 /* .pvMore = */ NULL,
309 /* .pvClass = */ NULL,
310 /* .cbClass = */ 0
311 }
312};
313
314static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsHS[2] =
315{
316 {
317 {
318 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
319 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
320 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
321 /* .bmAttributes = */ 2 /* bulk */,
322 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
323 /* .bInterval = */ 0 /* no NAKs */
324 },
325 /* .pvMore = */ NULL,
326 /* .pvClass = */ NULL,
327 /* .cbClass = */ 0
328 },
329 {
330 {
331 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
332 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
333 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
334 /* .bmAttributes = */ 2 /* bulk */,
335 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
336 /* .bInterval = */ 0 /* no NAKs */
337 },
338 /* .pvMore = */ NULL,
339 /* .pvClass = */ NULL,
340 /* .cbClass = */ 0
341 }
342};
343
344static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsSS[2] =
345{
346 {
347 {
348 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
349 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
350 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
351 /* .bmAttributes = */ 2 /* bulk */,
352 /* .wMaxPacketSize = */ 1024 /* SS bulk packet size */,
353 /* .bInterval = */ 0 /* no NAKs */
354 },
355 /* .pvMore = */ NULL,
356 /* .pvClass = */ NULL,
357 /* .cbClass = */ 0
358 },
359 {
360 {
361 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
362 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
363 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
364 /* .bmAttributes = */ 2 /* bulk */,
365 /* .wMaxPacketSize = */ 1024 /* SS bulk packet size */,
366 /* .bInterval = */ 0 /* no NAKs */
367 },
368 /* .pvMore = */ NULL,
369 /* .pvClass = */ NULL,
370 /* .cbClass = */ 0
371 }
372};
373
374static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescFS =
375{
376 {
377 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
378 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
379 /* .bInterfaceNumber = */ 0,
380 /* .bAlternateSetting = */ 0,
381 /* .bNumEndpoints = */ 2,
382 /* .bInterfaceClass = */ 8 /* Mass Storage */,
383 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
384 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
385 /* .iInterface = */ 0
386 },
387 /* .pvMore = */ NULL,
388 /* .pvClass = */ NULL,
389 /* .cbClass = */ 0,
390 &g_aUsbMsdEndpointDescsFS[0],
391 /* .pIAD = */ NULL,
392 /* .cbIAD = */ 0
393};
394
395static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescHS =
396{
397 {
398 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
399 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
400 /* .bInterfaceNumber = */ 0,
401 /* .bAlternateSetting = */ 0,
402 /* .bNumEndpoints = */ 2,
403 /* .bInterfaceClass = */ 8 /* Mass Storage */,
404 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
405 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
406 /* .iInterface = */ 0
407 },
408 /* .pvMore = */ NULL,
409 /* .pvClass = */ NULL,
410 /* .cbClass = */ 0,
411 &g_aUsbMsdEndpointDescsHS[0],
412 /* .pIAD = */ NULL,
413 /* .cbIAD = */ 0
414};
415
416static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescSS =
417{
418 {
419 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
420 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
421 /* .bInterfaceNumber = */ 0,
422 /* .bAlternateSetting = */ 0,
423 /* .bNumEndpoints = */ 2,
424 /* .bInterfaceClass = */ 8 /* Mass Storage */,
425 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
426 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
427 /* .iInterface = */ 0
428 },
429 /* .pvMore = */ NULL,
430 /* .pvClass = */ NULL,
431 /* .cbClass = */ 0,
432 &g_aUsbMsdEndpointDescsSS[0],
433 /* .pIAD = */ NULL,
434 /* .cbIAD = */ 0
435};
436
437static const VUSBINTERFACE g_aUsbMsdInterfacesFS[] =
438{
439 { &g_UsbMsdInterfaceDescFS, /* .cSettings = */ 1 },
440};
441
442static const VUSBINTERFACE g_aUsbMsdInterfacesHS[] =
443{
444 { &g_UsbMsdInterfaceDescHS, /* .cSettings = */ 1 },
445};
446
447static const VUSBINTERFACE g_aUsbMsdInterfacesSS[] =
448{
449 { &g_UsbMsdInterfaceDescSS, /* .cSettings = */ 1 },
450};
451
452static const VUSBDESCCONFIGEX g_UsbMsdConfigDescFS =
453{
454 {
455 /* .bLength = */ sizeof(VUSBDESCCONFIG),
456 /* .bDescriptorType = */ VUSB_DT_CONFIG,
457 /* .wTotalLength = */ 0 /* recalculated on read */,
458 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesFS),
459 /* .bConfigurationValue =*/ 1,
460 /* .iConfiguration = */ 0,
461 /* .bmAttributes = */ RT_BIT(7),
462 /* .MaxPower = */ 50 /* 100mA */
463 },
464 NULL, /* pvMore */
465 &g_aUsbMsdInterfacesFS[0],
466 NULL /* pvOriginal */
467};
468
469static const VUSBDESCCONFIGEX g_UsbMsdConfigDescHS =
470{
471 {
472 /* .bLength = */ sizeof(VUSBDESCCONFIG),
473 /* .bDescriptorType = */ VUSB_DT_CONFIG,
474 /* .wTotalLength = */ 0 /* recalculated on read */,
475 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesHS),
476 /* .bConfigurationValue =*/ 1,
477 /* .iConfiguration = */ 0,
478 /* .bmAttributes = */ RT_BIT(7),
479 /* .MaxPower = */ 50 /* 100mA */
480 },
481 NULL, /* pvMore */
482 &g_aUsbMsdInterfacesHS[0],
483 NULL /* pvOriginal */
484};
485
486static const VUSBDESCCONFIGEX g_UsbMsdConfigDescSS =
487{
488 {
489 /* .bLength = */ sizeof(VUSBDESCCONFIG),
490 /* .bDescriptorType = */ VUSB_DT_CONFIG,
491 /* .wTotalLength = */ 0 /* recalculated on read */,
492 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesSS),
493 /* .bConfigurationValue =*/ 1,
494 /* .iConfiguration = */ 0,
495 /* .bmAttributes = */ RT_BIT(7),
496 /* .MaxPower = */ 50 /* 100mA */
497 },
498 NULL, /* pvMore */
499 &g_aUsbMsdInterfacesSS[0],
500 NULL /* pvOriginal */
501};
502
503static const VUSBDESCDEVICE g_UsbMsdDeviceDesc20 =
504{
505 /* .bLength = */ sizeof(g_UsbMsdDeviceDesc20),
506 /* .bDescriptorType = */ VUSB_DT_DEVICE,
507 /* .bcdUsb = */ 0x200, /* USB 2.0 */
508 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
509 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
510 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
511 /* .bMaxPacketSize0 = */ 64,
512 /* .idVendor = */ VBOX_USB_VENDOR,
513 /* .idProduct = */ USBMSD_PID_HD,
514 /* .bcdDevice = */ 0x0100, /* 1.0 */
515 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
516 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
517 /* .iSerialNumber = */ 0,
518 /* .bNumConfigurations = */ 1
519};
520
521static const VUSBDESCDEVICE g_UsbMsdDeviceDesc30 =
522{
523 /* .bLength = */ sizeof(g_UsbMsdDeviceDesc30),
524 /* .bDescriptorType = */ VUSB_DT_DEVICE,
525 /* .bcdUsb = */ 0x300, /* USB 2.0 */
526 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
527 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
528 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
529 /* .bMaxPacketSize0 = */ 9 /* 512, the only option for USB3. */,
530 /* .idVendor = */ VBOX_USB_VENDOR,
531 /* .idProduct = */ USBMSD_PID_HD,
532 /* .bcdDevice = */ 0x0110, /* 1.10 */
533 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
534 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
535 /* .iSerialNumber = */ 0,
536 /* .bNumConfigurations = */ 1
537};
538
539static const VUSBDEVICEQUALIFIER g_UsbMsdDeviceQualifier =
540{
541 /* .bLength = */ sizeof(g_UsbMsdDeviceQualifier),
542 /* .bDescriptorType = */ VUSB_DT_DEVICE_QUALIFIER,
543 /* .bcdUsb = */ 0x200, /* USB 2.0 */
544 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
545 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
546 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
547 /* .bMaxPacketSize0 = */ 64,
548 /* .bNumConfigurations = */ 1,
549 /* .bReserved = */ 0
550};
551
552static const PDMUSBDESCCACHE g_UsbMsdDescCacheFS =
553{
554 /* .pDevice = */ &g_UsbMsdDeviceDesc20,
555 /* .paConfigs = */ &g_UsbMsdConfigDescFS,
556 /* .paLanguages = */ g_aUsbMsdLanguages,
557 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
558 /* .fUseCachedDescriptors = */ true,
559 /* .fUseCachedStringsDescriptors = */ true
560};
561
562static const PDMUSBDESCCACHE g_UsbMsdDescCacheHS =
563{
564 /* .pDevice = */ &g_UsbMsdDeviceDesc20,
565 /* .paConfigs = */ &g_UsbMsdConfigDescHS,
566 /* .paLanguages = */ g_aUsbMsdLanguages,
567 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
568 /* .fUseCachedDescriptors = */ true,
569 /* .fUseCachedStringsDescriptors = */ true
570};
571
572static const PDMUSBDESCCACHE g_UsbMsdDescCacheSS =
573{
574 /* .pDevice = */ &g_UsbMsdDeviceDesc30,
575 /* .paConfigs = */ &g_UsbMsdConfigDescSS,
576 /* .paLanguages = */ g_aUsbMsdLanguages,
577 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
578 /* .fUseCachedDescriptors = */ true,
579 /* .fUseCachedStringsDescriptors = */ true
580};
581
582/*******************************************************************************
583* Internal Functions *
584*******************************************************************************/
585static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb);
586
587
588/**
589 * Initializes an URB queue.
590 *
591 * @param pQueue The URB queue.
592 */
593static void usbMsdQueueInit(PUSBMSDURBQUEUE pQueue)
594{
595 pQueue->pHead = NULL;
596 pQueue->ppTail = &pQueue->pHead;
597}
598
599
600
601/**
602 * Inserts an URB at the end of the queue.
603 *
604 * @param pQueue The URB queue.
605 * @param pUrb The URB to insert.
606 */
607DECLINLINE(void) usbMsdQueueAddTail(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
608{
609 pUrb->Dev.pNext = NULL;
610 *pQueue->ppTail = pUrb;
611 pQueue->ppTail = &pUrb->Dev.pNext;
612}
613
614
615/**
616 * Unlinks the head of the queue and returns it.
617 *
618 * @returns The head entry.
619 * @param pQueue The URB queue.
620 */
621DECLINLINE(PVUSBURB) usbMsdQueueRemoveHead(PUSBMSDURBQUEUE pQueue)
622{
623 PVUSBURB pUrb = pQueue->pHead;
624 if (pUrb)
625 {
626 PVUSBURB pNext = pUrb->Dev.pNext;
627 pQueue->pHead = pNext;
628 if (!pNext)
629 pQueue->ppTail = &pQueue->pHead;
630 else
631 pUrb->Dev.pNext = NULL;
632 }
633 return pUrb;
634}
635
636
637/**
638 * Removes an URB from anywhere in the queue.
639 *
640 * @returns true if found, false if not.
641 * @param pQueue The URB queue.
642 * @param pUrb The URB to remove.
643 */
644DECLINLINE(bool) usbMsdQueueRemove(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
645{
646 PVUSBURB pCur = pQueue->pHead;
647 if (pCur == pUrb)
648 pQueue->pHead = pUrb->Dev.pNext;
649 else
650 {
651 while (pCur)
652 {
653 if (pCur->Dev.pNext == pUrb)
654 {
655 pCur->Dev.pNext = pUrb->Dev.pNext;
656 break;
657 }
658 pCur = pCur->Dev.pNext;
659 }
660 if (!pCur)
661 return false;
662 }
663 if (!pUrb->Dev.pNext)
664 pQueue->ppTail = &pQueue->pHead;
665 return true;
666}
667
668
669/**
670 * Checks if the queue is empty or not.
671 *
672 * @returns true if it is, false if it isn't.
673 * @param pQueue The URB queue.
674 */
675DECLINLINE(bool) usbMsdQueueIsEmpty(PCUSBMSDURBQUEUE pQueue)
676{
677 return pQueue->pHead == NULL;
678}
679
680
681/**
682 * Links an URB into the done queue.
683 *
684 * @param pThis The MSD instance.
685 * @param pUrb The URB.
686 */
687static void usbMsdLinkDone(PUSBMSD pThis, PVUSBURB pUrb)
688{
689 usbMsdQueueAddTail(&pThis->DoneQueue, pUrb);
690
691 if (pThis->fHaveDoneQueueWaiter)
692 {
693 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
694 AssertRC(rc);
695 }
696}
697
698
699
700
701/**
702 * Allocates a new request and does basic init.
703 *
704 * @returns Pointer to the new request. NULL if we're out of memory.
705 * @param pUsbIns The instance allocating it.
706 */
707static PUSBMSDREQ usbMsdReqAlloc(PPDMUSBINS pUsbIns)
708{
709 PUSBMSDREQ pReq = (PUSBMSDREQ)PDMUsbHlpMMHeapAllocZ(pUsbIns, sizeof(*pReq));
710 if (pReq)
711 {
712 pReq->enmState = USBMSDREQSTATE_READY;
713 pReq->iScsiReqStatus = -1;
714 pReq->pUsbIns = pUsbIns;
715 }
716 else
717 LogRel(("usbMsdReqAlloc: Out of memory\n"));
718 return pReq;
719}
720
721
722/**
723 * Frees a request.
724 *
725 * @param pReq The request.
726 */
727static void usbMsdReqFree(PUSBMSDREQ pReq)
728{
729 /*
730 * Check the input.
731 */
732 AssertReturnVoid( pReq->enmState > USBMSDREQSTATE_INVALID
733 && pReq->enmState != USBMSDREQSTATE_EXECUTING
734 && pReq->enmState < USBMSDREQSTATE_END);
735 PPDMUSBINS pUsbIns = pReq->pUsbIns;
736 AssertPtrReturnVoid(pUsbIns);
737 AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
738
739 /*
740 * Invalidate it and free the associated resources.
741 */
742 pReq->enmState = USBMSDREQSTATE_INVALID;
743 pReq->cbBuf = 0;
744 pReq->offBuf = 0;
745 pReq->ScsiReq.pbCDB = NULL;
746 pReq->ScsiReq.paScatterGatherHead = NULL;
747 pReq->ScsiReq.pbSenseBuffer = NULL;
748 pReq->ScsiReq.pvUser = NULL;
749 pReq->ScsiReqSeg.cbSeg = 0;
750 pReq->ScsiReqSeg.pvSeg = NULL;
751
752 if (pReq->pbBuf)
753 {
754 PDMUsbHlpMMHeapFree(pUsbIns, pReq->pbBuf);
755 pReq->pbBuf = NULL;
756 }
757
758 PDMUsbHlpMMHeapFree(pUsbIns, pReq);
759}
760
761
762/**
763 * Prepares a request for execution or data buffering.
764 *
765 * @param pReq The request.
766 * @param pCbw The SCSI command block wrapper.
767 */
768static void usbMsdReqPrepare(PUSBMSDREQ pReq, PCUSBCBW pCbw)
769{
770 /* Copy the CBW */
771 size_t cbCopy = RT_OFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]);
772 memcpy(&pReq->Cbw, pCbw, cbCopy);
773 memset((uint8_t *)&pReq->Cbw + cbCopy, 0, sizeof(pReq->Cbw) - cbCopy);
774
775 /* Setup the SCSI request. */
776 pReq->ScsiReq.uLogicalUnit = pReq->Cbw.bCBWLun;
777 pReq->ScsiReq.uDataDirection = (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
778 ? PDMSCSIREQUESTTXDIR_TO_DEVICE
779 : PDMSCSIREQUESTTXDIR_FROM_DEVICE;
780 pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
781
782 pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
783 pReq->offBuf = 0;
784 pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
785 pReq->ScsiReqSeg.cbSeg = pReq->Cbw.dCBWDataTransferLength;
786 pReq->ScsiReq.cbScatterGather = pReq->Cbw.dCBWDataTransferLength;
787 pReq->ScsiReq.cScatterGatherEntries = 1;
788 pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
789 pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
790 pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
791 pReq->ScsiReq.pvUser = NULL;
792 RT_ZERO(pReq->ScsiReqSense);
793 pReq->iScsiReqStatus = -1;
794}
795
796
797/**
798 * Makes sure that there is sufficient buffer space available.
799 *
800 * @returns Success indicator (true/false)
801 * @param pReq
802 * @param cbBuf The required buffer space.
803 */
804static int usbMsdReqEnsureBuffer(PUSBMSDREQ pReq, uint32_t cbBuf)
805{
806 if (RT_LIKELY(pReq->cbBuf >= cbBuf))
807 RT_BZERO(pReq->pbBuf, cbBuf);
808 else
809 {
810 PDMUsbHlpMMHeapFree(pReq->pUsbIns, pReq->pbBuf);
811 pReq->cbBuf = 0;
812
813 cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
814 pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pReq->pUsbIns, cbBuf);
815 if (!pReq->pbBuf)
816 return false;
817
818 pReq->cbBuf = cbBuf;
819 }
820 return true;
821}
822
823
824/**
825 * Completes the URB with a stalled state, halting the pipe.
826 */
827static int usbMsdCompleteStall(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb, const char *pszWhy)
828{
829 Log(("usbMsdCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
830
831 pUrb->enmStatus = VUSBSTATUS_STALL;
832
833 /** @todo figure out if the stall is global or pipe-specific or both. */
834 if (pEp)
835 pEp->fHalted = true;
836 else
837 {
838 pThis->aEps[1].fHalted = true;
839 pThis->aEps[2].fHalted = true;
840 }
841
842 usbMsdLinkDone(pThis, pUrb);
843 return VINF_SUCCESS;
844}
845
846
847/**
848 * Completes the URB with a OK state.
849 */
850static int usbMsdCompleteOk(PUSBMSD pThis, PVUSBURB pUrb, size_t cbData)
851{
852 Log(("usbMsdCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
853
854 pUrb->enmStatus = VUSBSTATUS_OK;
855 pUrb->cbData = (uint32_t)cbData;
856
857 usbMsdLinkDone(pThis, pUrb);
858 return VINF_SUCCESS;
859}
860
861
862/**
863 * Reset worker for usbMsdUsbReset, usbMsdUsbSetConfiguration and
864 * usbMsdUrbHandleDefaultPipe.
865 *
866 * @returns VBox status code.
867 * @param pThis The MSD instance.
868 * @param pUrb Set when usbMsdUrbHandleDefaultPipe is the
869 * caller.
870 * @param fSetConfig Set when usbMsdUsbSetConfiguration is the
871 * caller.
872 */
873static int usbMsdResetWorker(PUSBMSD pThis, PVUSBURB pUrb, bool fSetConfig)
874{
875 /*
876 * Wait for the any command currently executing to complete before
877 * resetting. (We cannot cancel its execution.) How we do this depends
878 * on the reset method.
879 */
880 PUSBMSDREQ pReq = pThis->pReq;
881 if ( pReq
882 && pReq->enmState == USBMSDREQSTATE_EXECUTING)
883 {
884 /* Don't try to deal with the set config variant nor multiple build-only
885 mass storage resets. */
886 if (pThis->pResetUrb && (pUrb || fSetConfig))
887 {
888 Log(("usbMsdResetWorker: pResetUrb is already %p:%s - stalling\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
889 return usbMsdCompleteStall(pThis, NULL, pUrb, "pResetUrb");
890 }
891
892 /* Bulk-Only Mass Storage Reset: Complete the reset on request completion. */
893 if (pUrb)
894 {
895 pThis->pResetUrb = pUrb;
896 Log(("usbMsdResetWorker: Setting pResetUrb to %p:%s\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
897 return VINF_SUCCESS;
898 }
899
900 /* Device reset: Wait for up to 10 ms. If it doesn't work, ditch
901 whoe the request structure. We'll allocate a new one when needed. */
902 Log(("usbMsdResetWorker: Waiting for completion...\n"));
903 Assert(!pThis->fSignalResetSem);
904 pThis->fSignalResetSem = true;
905 RTSemEventMultiReset(pThis->hEvtReset);
906 RTCritSectLeave(&pThis->CritSect);
907
908 int rc = RTSemEventMultiWait(pThis->hEvtReset, 10 /*ms*/);
909
910 RTCritSectEnter(&pThis->CritSect);
911 pThis->fSignalResetSem = false;
912 if ( RT_FAILURE(rc)
913 || pReq->enmState == USBMSDREQSTATE_EXECUTING)
914 {
915 Log(("usbMsdResetWorker: Didn't complete, ditching the current request (%p)!\n", pReq));
916 Assert(pReq == pThis->pReq);
917 pReq->enmState = USBMSDREQSTATE_DESTROY_ON_COMPLETION;
918 pThis->pReq = NULL;
919 pReq = NULL;
920 }
921 }
922
923 /*
924 * Reset the request and device state.
925 */
926 if (pReq)
927 {
928 pReq->enmState = USBMSDREQSTATE_READY;
929 pReq->iScsiReqStatus = -1;
930 }
931
932 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
933 pThis->aEps[i].fHalted = false;
934
935 if (!pUrb && !fSetConfig) /* (only device reset) */
936 pThis->bConfigurationValue = 0; /* default */
937
938 /*
939 * Ditch all pending URBs.
940 */
941 PVUSBURB pCurUrb;
942 while ((pCurUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
943 {
944 pCurUrb->enmStatus = VUSBSTATUS_CRC;
945 usbMsdLinkDone(pThis, pCurUrb);
946 }
947
948 pCurUrb = pThis->pResetUrb;
949 if (pCurUrb)
950 {
951 pThis->pResetUrb = NULL;
952 pCurUrb->enmStatus = VUSBSTATUS_CRC;
953 usbMsdLinkDone(pThis, pCurUrb);
954 }
955
956 if (pUrb)
957 return usbMsdCompleteOk(pThis, pUrb, 0);
958 return VINF_SUCCESS;
959}
960
961
962/**
963 * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted}
964 */
965static DECLCALLBACK(int) usbMsdLun0ScsiRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
966 int rcCompletion, bool fRedo, int rcReq)
967{
968 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
969 PUSBMSDREQ pReq = RT_FROM_MEMBER(pSCSIRequest, USBMSDREQ, ScsiReq);
970
971 Log(("usbMsdLun0ScsiRequestCompleted: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, rcCompletion));
972 RTCritSectEnter(&pThis->CritSect);
973
974 if (pReq->enmState != USBMSDREQSTATE_DESTROY_ON_COMPLETION)
975 {
976 Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
977 Assert(pThis->pReq == pReq);
978 pReq->iScsiReqStatus = rcCompletion;
979
980 /*
981 * Advance the state machine. The state machine is not affected by
982 * SCSI errors.
983 */
984 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
985 {
986 pReq->enmState = USBMSDREQSTATE_STATUS;
987 Log(("usbMsdLun0ScsiRequestCompleted: Entering STATUS\n"));
988 }
989 else
990 {
991 pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
992 Log(("usbMsdLun0ScsiRequestCompleted: Entering DATA_TO_HOST\n"));
993 }
994
995 /*
996 * Deal with pending to-host URBs.
997 */
998 for (;;)
999 {
1000 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue);
1001 if (!pUrb)
1002 break;
1003
1004 /* Process it the normal way. */
1005 usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1006 }
1007 }
1008 else
1009 {
1010 Log(("usbMsdLun0ScsiRequestCompleted: freeing %p\n", pReq));
1011 usbMsdReqFree(pReq);
1012 }
1013
1014 if (pThis->fSignalResetSem)
1015 RTSemEventMultiSignal(pThis->hEvtReset);
1016
1017 if (pThis->pResetUrb)
1018 {
1019 pThis->pResetUrb = NULL;
1020 usbMsdResetWorker(pThis, pThis->pResetUrb, false /*fSetConfig*/);
1021 }
1022
1023 RTCritSectLeave(&pThis->CritSect);
1024 return VINF_SUCCESS;
1025}
1026
1027
1028/**
1029 * @interface_method_impl{PDMISCSIPORT,pfnQueryDeviceLocation}
1030 */
1031static DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController,
1032 uint32_t *piInstance, uint32_t *piLUN)
1033{
1034 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
1035 PPDMUSBINS pUsbIns = pThis->pUsbIns;
1036
1037 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
1038 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
1039 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
1040
1041 *ppcszController = pUsbIns->pReg->szName;
1042 *piInstance = pUsbIns->iInstance;
1043 *piLUN = 0;
1044
1045 return VINF_SUCCESS;
1046}
1047
1048
1049/**
1050 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1051 */
1052static DECLCALLBACK(void *) usbMsdLun0QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1053{
1054 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
1055 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1056 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pThis->Lun0.IScsiPort);
1057 return NULL;
1058}
1059
1060
1061/**
1062 * Checks if all asynchronous I/O is finished.
1063 *
1064 * Used by usbMsdVMReset, usbMsdVMSuspend and usbMsdVMPowerOff.
1065 *
1066 * @returns true if quiesced, false if busy.
1067 * @param pUsbIns The USB device instance.
1068 */
1069static bool usbMsdAllAsyncIOIsFinished(PPDMUSBINS pUsbIns)
1070{
1071 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1072
1073 if ( VALID_PTR(pThis->pReq)
1074 && pThis->pReq->enmState == USBMSDREQSTATE_EXECUTING)
1075 return false;
1076
1077 return true;
1078}
1079
1080/**
1081 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
1082 * Callback employed by usbMsdVMSuspend and usbMsdVMPowerOff.}
1083 */
1084static DECLCALLBACK(bool) usbMsdIsAsyncSuspendOrPowerOffDone(PPDMUSBINS pUsbIns)
1085{
1086 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1087 return false;
1088
1089 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1090 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1091 return true;
1092}
1093
1094/**
1095 * Common worker for usbMsdVMSuspend and usbMsdVMPowerOff.
1096 */
1097static void usbMsdSuspendOrPowerOff(PPDMUSBINS pUsbIns)
1098{
1099 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1100
1101 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
1102 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1103 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncSuspendOrPowerOffDone);
1104 else
1105 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1106}
1107
1108
1109/* -=-=-=-=- Saved State -=-=-=-=- */
1110
1111/**
1112 * @copydoc FNUSBSSMSAVEPREP
1113 */
1114static DECLCALLBACK(int) usbMsdSavePrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1115{
1116 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1117
1118 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1119 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1120 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1121 return VINF_SUCCESS;
1122}
1123
1124/**
1125 * @copydoc FNUSBSSMLOADPREP
1126 */
1127static DECLCALLBACK(int) usbMsdLoadPrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1128{
1129 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1130
1131 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1132 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1133 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1134 return VINF_SUCCESS;
1135}
1136
1137/**
1138 * @copydoc FNUSBSSMLIVEEXEC
1139 */
1140static DECLCALLBACK(int) usbMsdLiveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)
1141{
1142 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1143
1144 /* config. */
1145 SSMR3PutBool(pSSM, pThis->Lun0.pIBase != NULL);
1146 return VINF_SSM_DONT_CALL_AGAIN;
1147}
1148
1149/**
1150 * @copydoc FNUSBSSMSAVEEXEC
1151 */
1152static DECLCALLBACK(int) usbMsdSaveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1153{
1154 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1155 int rc;
1156
1157 /* The config */
1158 rc = usbMsdLiveExec(pUsbIns, pSSM, SSM_PASS_FINAL);
1159 AssertRCReturn(rc, rc);
1160
1161 SSMR3PutU8(pSSM, pThis->bConfigurationValue);
1162 SSMR3PutBool(pSSM, pThis->aEps[0].fHalted);
1163 SSMR3PutBool(pSSM, pThis->aEps[1].fHalted);
1164 SSMR3PutBool(pSSM, pThis->aEps[2].fHalted);
1165 SSMR3PutBool(pSSM, pThis->pReq != NULL);
1166
1167 if (pThis->pReq)
1168 {
1169 PUSBMSDREQ pReq = pThis->pReq;
1170
1171 SSMR3PutU32(pSSM, pReq->enmState);
1172 SSMR3PutU32(pSSM, pReq->cbBuf);
1173 if (pReq->cbBuf)
1174 {
1175 AssertPtr(pReq->pbBuf);
1176 SSMR3PutMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1177 }
1178
1179 SSMR3PutU32(pSSM, pReq->offBuf);
1180 SSMR3PutMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1181 SSMR3PutU32(pSSM, pReq->ScsiReq.uLogicalUnit);
1182 SSMR3PutU32(pSSM, pReq->ScsiReq.uDataDirection);
1183 SSMR3PutU32(pSSM, pReq->ScsiReq.cbCDB);
1184 SSMR3PutU32(pSSM, pReq->ScsiReq.cbScatterGather);
1185 SSMR3PutMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
1186 SSMR3PutS32(pSSM, pReq->iScsiReqStatus);
1187 }
1188
1189 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1190}
1191
1192/**
1193 * @copydoc FNUSBSSMLOADEXEC
1194 */
1195static DECLCALLBACK(int) usbMsdLoadExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1196{
1197 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1198 uint32_t u32;
1199 int rc;
1200
1201 if (uVersion > USB_MSD_SAVED_STATE_VERSION)
1202 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1203
1204 /* Verify config. */
1205 bool fInUse;
1206 rc = SSMR3GetBool(pSSM, &fInUse);
1207 AssertRCReturn(rc, rc);
1208 if (fInUse != (pThis->Lun0.pIBase != NULL))
1209 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1210 N_("The %s VM is missing a USB mass storage device. Please make sure the source and target VMs have compatible storage configurations"),
1211 fInUse ? "target" : "source");
1212
1213 if (uPass == SSM_PASS_FINAL)
1214 {
1215 /* Restore data. */
1216 bool fReqAlloc = false;
1217
1218 Assert(!pThis->pReq);
1219
1220 SSMR3GetU8(pSSM, &pThis->bConfigurationValue);
1221 SSMR3GetBool(pSSM, &pThis->aEps[0].fHalted);
1222 SSMR3GetBool(pSSM, &pThis->aEps[1].fHalted);
1223 SSMR3GetBool(pSSM, &pThis->aEps[2].fHalted);
1224 SSMR3GetBool(pSSM, &fReqAlloc);
1225
1226 if (fReqAlloc)
1227 {
1228 PUSBMSDREQ pReq = usbMsdReqAlloc(pUsbIns);
1229
1230 if (pReq)
1231 {
1232 uint32_t cbBuf = 0;
1233
1234 pThis->pReq = pReq;
1235
1236 SSMR3GetU32(pSSM, (uint32_t *)&pReq->enmState);
1237 SSMR3GetU32(pSSM, &cbBuf);
1238 if (cbBuf)
1239 {
1240 if (usbMsdReqEnsureBuffer(pReq, cbBuf))
1241 {
1242 AssertPtr(pReq->pbBuf);
1243 Assert(cbBuf == pReq->cbBuf);
1244 SSMR3GetMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1245 }
1246 else
1247 rc = VERR_NO_MEMORY;
1248 }
1249
1250 if (RT_SUCCESS(rc))
1251 {
1252 SSMR3GetU32(pSSM, &pReq->offBuf);
1253 SSMR3GetMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1254 SSMR3GetU32(pSSM, &pReq->ScsiReq.uLogicalUnit);
1255 SSMR3GetU32(pSSM, (uint32_t *)&pReq->ScsiReq.uDataDirection);
1256 SSMR3GetU32(pSSM, &pReq->ScsiReq.cbCDB);
1257 SSMR3GetU32(pSSM, &pReq->ScsiReq.cbScatterGather);
1258 SSMR3GetMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
1259 SSMR3GetS32(pSSM, &pReq->iScsiReqStatus);
1260
1261 /* Setup the rest of the SCSI request. */
1262 pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
1263 pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
1264 pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
1265 pReq->ScsiReqSeg.cbSeg = pReq->ScsiReq.cbScatterGather;
1266 pReq->ScsiReq.cScatterGatherEntries = 1;
1267 pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
1268 pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
1269 pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
1270 pReq->ScsiReq.pvUser = NULL;
1271 }
1272 }
1273 else
1274 rc = VERR_NO_MEMORY;
1275 }
1276
1277 if (RT_SUCCESS(rc))
1278 rc = SSMR3GetU32(pSSM, &u32);
1279
1280 if (RT_FAILURE(rc))
1281 return rc;
1282 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1283 }
1284
1285 return VINF_SUCCESS;
1286}
1287
1288
1289/**
1290 * @copydoc PDMUSBREG::pfnUrbReap
1291 */
1292static DECLCALLBACK(PVUSBURB) usbMsdUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1293{
1294 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1295 LogFlow(("usbMsdUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1296
1297 RTCritSectEnter(&pThis->CritSect);
1298
1299 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1300 if (!pUrb && cMillies)
1301 {
1302 /* Wait */
1303 pThis->fHaveDoneQueueWaiter = true;
1304 RTCritSectLeave(&pThis->CritSect);
1305
1306 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1307
1308 RTCritSectEnter(&pThis->CritSect);
1309 pThis->fHaveDoneQueueWaiter = false;
1310
1311 pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1312 }
1313
1314 RTCritSectLeave(&pThis->CritSect);
1315
1316 if (pUrb)
1317 Log(("usbMsdUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1318 return pUrb;
1319}
1320
1321
1322/**
1323 * @copydoc PDMUSBREG::pfnWakeup
1324 */
1325static DECLCALLBACK(int) usbMsdWakeup(PPDMUSBINS pUsbIns)
1326{
1327 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1328 LogFlow(("usbMsdUrbReap/#%u:\n", pUsbIns->iInstance));
1329
1330 return RTSemEventSignal(pThis->hEvtDoneQueue);
1331}
1332
1333
1334/**
1335 * @copydoc PDMUSBREG::pfnUrbCancel
1336 */
1337static DECLCALLBACK(int) usbMsdUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1338{
1339 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1340 LogFlow(("usbMsdUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1341 RTCritSectEnter(&pThis->CritSect);
1342
1343 /*
1344 * Remove the URB from the to-host queue and move it onto the done queue.
1345 */
1346 if (usbMsdQueueRemove(&pThis->ToHostQueue, pUrb))
1347 usbMsdLinkDone(pThis, pUrb);
1348
1349 RTCritSectLeave(&pThis->CritSect);
1350 return VINF_SUCCESS;
1351}
1352
1353
1354/**
1355 * Fails an illegal SCSI request.
1356 *
1357 * @returns VBox status code.
1358 * @param pThis The MSD instance data.
1359 * @param pReq The MSD request.
1360 * @param bAsc The ASC for the SCSI_SENSE_ILLEGAL_REQUEST.
1361 * @param bAscq The ASC qualifier.
1362 * @param pszWhy For logging why.
1363 */
1364static int usbMsdScsiIllegalRequest(PUSBMSD pThis, PUSBMSDREQ pReq, uint8_t bAsc, uint8_t bAscq, const char *pszWhy)
1365{
1366 Log(("usbMsdScsiIllegalRequest: bAsc=%#x bAscq=%#x %s\n", bAsc, bAscq, pszWhy));
1367
1368 RT_ZERO(pReq->ScsiReqSense);
1369 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1370 pReq->ScsiReqSense[2] = SCSI_SENSE_ILLEGAL_REQUEST;
1371 pReq->ScsiReqSense[7] = 10;
1372 pReq->ScsiReqSense[12] = SCSI_ASC_INVALID_MESSAGE;
1373 pReq->ScsiReqSense[13] = 0; /* Should be ASCQ but it has the same value for success. */
1374
1375 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
1376 return VINF_SUCCESS;
1377}
1378
1379
1380/**
1381 * The SCSI driver doesn't handle SCSI_REQUEST_SENSE but instead
1382 * returns the sense info with the request.
1383 *
1384 */
1385static int usbMsdHandleScsiReqestSense(PUSBMSD pThis, PUSBMSDREQ pReq, PCUSBCBW pCbw)
1386{
1387 Log(("usbMsdHandleScsiReqestSense: Entering EXECUTING (dCBWTag=%#x).\n", pReq->Cbw.dCBWTag));
1388 Assert(pReq == pThis->pReq);
1389 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1390
1391 /* validation */
1392 if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
1393 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
1394 if (pCbw->bCBWCBLength < 6)
1395 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
1396 if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
1397 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "lun");
1398 if (pCbw->bCBWLun != 0)
1399 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
1400 if (pCbw->CBWCB[4] < 6)
1401 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
1402
1403 /* If the previous command succeeded successfully, whip up some sense data. */
1404 if ( pReq->iScsiReqStatus == SCSI_STATUS_OK
1405 && pReq->ScsiReqSense[0] == 0)
1406 {
1407 RT_ZERO(pReq->ScsiReqSense);
1408#if 0 /** @todo something upsets linux about this stuff. Needs investigation. */
1409 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1410 pReq->ScsiReqSense[0] = SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1411 pReq->ScsiReqSense[2] = SCSI_SENSE_NONE;
1412 pReq->ScsiReqSense[7] = 10;
1413 pReq->ScsiReqSense[12] = SCSI_ASC_NONE;
1414 pReq->ScsiReqSense[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
1415#endif
1416 }
1417
1418 /* Copy the data into the result buffer. */
1419 size_t cbCopy = RT_MIN(pCbw->dCBWDataTransferLength, sizeof(pReq->ScsiReqSense));
1420 Log(("usbMsd: SCSI_REQUEST_SENSE - CBWCB[4]=%#x iOldState=%d, %u bytes, raw: %.*Rhxs\n",
1421 pCbw->CBWCB[4], pReq->iScsiReqStatus, pCbw->dCBWDataTransferLength, RT_MAX(1, cbCopy), pReq->ScsiReqSense));
1422 memcpy(pReq->pbBuf, &pReq->ScsiReqSense[0], cbCopy);
1423
1424 usbMsdReqPrepare(pReq, pCbw);
1425
1426 /* Do normal completion. */
1427 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1428 return VINF_SUCCESS;
1429}
1430
1431
1432/**
1433 * Wrapper around PDMISCSICONNECTOR::pfnSCSIRequestSend that deals with
1434 * SCSI_REQUEST_SENSE.
1435 *
1436 * @returns VBox status code.
1437 * @param pThis The MSD instance data.
1438 * @param pReq The MSD request.
1439 * @param pszCaller Where we're called from.
1440 */
1441static int usbMsdSubmitScsiCommand(PUSBMSD pThis, PUSBMSDREQ pReq, const char *pszCaller)
1442{
1443 Log(("%s: Entering EXECUTING (dCBWTag=%#x).\n", pszCaller, pReq->Cbw.dCBWTag));
1444 Assert(pReq == pThis->pReq);
1445 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1446
1447 switch (pReq->ScsiReq.pbCDB[0])
1448 {
1449 case SCSI_REQUEST_SENSE:
1450 {
1451 }
1452
1453 default:
1454 return pThis->Lun0.pIScsiConnector->pfnSCSIRequestSend(pThis->Lun0.pIScsiConnector, &pReq->ScsiReq);
1455 }
1456}
1457
1458/**
1459 * Validates a SCSI request before passing it down to the SCSI driver.
1460 *
1461 * @returns true / false. The request will be completed on failure.
1462 * @param pThis The MSD instance data.
1463 * @param pCbw The USB command block wrapper.
1464 * @param pUrb The URB.
1465 */
1466static bool usbMsdIsValidCommand(PUSBMSD pThis, PCUSBCBW pCbw, PVUSBURB pUrb)
1467{
1468 switch (pCbw->CBWCB[0])
1469 {
1470 case SCSI_REQUEST_SENSE:
1471 /** @todo validate this. */
1472 return true;
1473
1474 default:
1475 return true;
1476 }
1477}
1478
1479
1480/**
1481 * Handle requests sent to the outbound (to device) bulk pipe.
1482 */
1483static int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1484{
1485 /*
1486 * Stall the request if the pipe is halted.
1487 */
1488 if (RT_UNLIKELY(pEp->fHalted))
1489 return usbMsdCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1490
1491 /*
1492 * Deal with the URB according to the current state.
1493 */
1494 PUSBMSDREQ pReq = pThis->pReq;
1495 USBMSDREQSTATE enmState = pReq ? pReq->enmState : USBMSDREQSTATE_READY;
1496 switch (enmState)
1497 {
1498 case USBMSDREQSTATE_STATUS:
1499 LogFlow(("usbMsdHandleBulkHostToDev: Skipping pending status.\n"));
1500 pReq->enmState = USBMSDREQSTATE_READY;
1501 /* fall thru */
1502
1503 /*
1504 * We're ready to receive a command. Start off by validating the
1505 * incoming request.
1506 */
1507 case USBMSDREQSTATE_READY:
1508 {
1509 PCUSBCBW pCbw = (PUSBCBW)&pUrb->abData[0];
1510 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[1]))
1511 {
1512 Log(("usbMsd: Bad CBW: cbData=%#x < min=%#x\n", pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[1]) ));
1513 return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
1514 }
1515 if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
1516 {
1517 Log(("usbMsd: CBW: Invalid dCBWSignature value: %#x\n", pCbw->dCBWSignature));
1518 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1519 }
1520 Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x cbData=%#x fShortNotOk=%RTbool\n",
1521 pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
1522 if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
1523 {
1524 Log(("usbMsd: CBW: Bad bmCBWFlags value: %#x\n", pCbw->bmCBWFlags));
1525 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1526
1527 }
1528 if (pCbw->bCBWLun != 0)
1529 {
1530 Log(("usbMsd: CBW: Bad bCBWLun value: %#x\n", pCbw->bCBWLun));
1531 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1532 }
1533 if (pCbw->bCBWCBLength == 0)
1534 {
1535 Log(("usbMsd: CBW: Bad bCBWCBLength value: %#x\n", pCbw->bCBWCBLength));
1536 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1537 }
1538 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]))
1539 {
1540 Log(("usbMsd: CBW: Mismatching cbData and bCBWCBLength values: %#x vs. %#x (%#x)\n",
1541 pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]), pCbw->bCBWCBLength));
1542 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1543 }
1544 if (pCbw->dCBWDataTransferLength > _1M)
1545 {
1546 Log(("usbMsd: CBW: dCBWDataTransferLength is too large: %#x (%u)\n",
1547 pCbw->dCBWDataTransferLength, pCbw->dCBWDataTransferLength));
1548 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too big transfer");
1549 }
1550
1551 if (!usbMsdIsValidCommand(pThis, pCbw, pUrb))
1552 return VINF_SUCCESS;
1553
1554 /*
1555 * Make sure we've got a request and a sufficient buffer space.
1556 *
1557 * Note! This will make sure the buffer is ZERO as well, thus
1558 * saving us the trouble of clearing the output buffer on
1559 * failure later.
1560 */
1561 if (!pReq)
1562 {
1563 pReq = usbMsdReqAlloc(pThis->pUsbIns);
1564 if (!pReq)
1565 return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
1566 pThis->pReq = pReq;
1567 }
1568 if (!usbMsdReqEnsureBuffer(pReq, pCbw->dCBWDataTransferLength))
1569 return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
1570
1571 /*
1572 * Special case REQUEST SENSE requests, usbMsdReqPrepare will
1573 * trash the sense data otherwise.
1574 */
1575 if (pCbw->CBWCB[0] == SCSI_REQUEST_SENSE)
1576 usbMsdHandleScsiReqestSense(pThis, pReq, pCbw);
1577 else
1578 {
1579 /*
1580 * Prepare the request. Kick it off right away if possible.
1581 */
1582 usbMsdReqPrepare(pReq, pCbw);
1583
1584 if ( pReq->Cbw.dCBWDataTransferLength == 0
1585 || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
1586 {
1587 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1588 if (RT_FAILURE(rc))
1589 {
1590 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1591 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
1592 }
1593 }
1594 else
1595 {
1596 Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
1597 pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
1598 }
1599 }
1600
1601 return usbMsdCompleteOk(pThis, pUrb, pUrb->cbData);
1602 }
1603
1604 /*
1605 * Stuff the data into the buffer.
1606 */
1607 case USBMSDREQSTATE_DATA_FROM_HOST:
1608 {
1609 uint32_t cbData = pUrb->cbData;
1610 uint32_t cbLeft = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1611 if (cbData > cbLeft)
1612 {
1613 Log(("usbMsd: Too much data: cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1614 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbLeft));
1615 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too much data");
1616 }
1617 memcpy(&pReq->pbBuf[pReq->offBuf], &pUrb->abData[0], cbData);
1618 pReq->offBuf += cbData;
1619
1620 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1621 {
1622 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1623 if (RT_FAILURE(rc))
1624 {
1625 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1626 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #2");
1627 }
1628 }
1629 return usbMsdCompleteOk(pThis, pUrb, cbData);
1630 }
1631
1632 /*
1633 * Bad state, stall.
1634 */
1635 case USBMSDREQSTATE_DATA_TO_HOST:
1636 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: DATA_TO_HOST");
1637
1638 case USBMSDREQSTATE_EXECUTING:
1639 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: EXECUTING");
1640
1641 default:
1642 AssertMsgFailed(("enmState=%d\n", enmState));
1643 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state (H2D)");
1644 }
1645}
1646
1647
1648/**
1649 * Handle requests sent to the inbound (to host) bulk pipe.
1650 */
1651static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1652{
1653 /*
1654 * Stall the request if the pipe is halted OR if there is no
1655 * pending request yet.
1656 */
1657 PUSBMSDREQ pReq = pThis->pReq;
1658 if (RT_UNLIKELY(pEp->fHalted || !pReq))
1659 return usbMsdCompleteStall(pThis, NULL, pUrb, pEp->fHalted ? "Halted pipe" : "No request");
1660
1661 /*
1662 * Deal with the URB according to the state.
1663 */
1664 switch (pReq->enmState)
1665 {
1666 /*
1667 * We've data left to transfer to the host.
1668 */
1669 case USBMSDREQSTATE_DATA_TO_HOST:
1670 {
1671 uint32_t cbData = pUrb->cbData;
1672 uint32_t cbCopy = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1673 if (cbData <= cbCopy)
1674 cbCopy = cbData;
1675 else if (pUrb->fShortNotOk)
1676 {
1677 Log(("usbMsd: Requested more data that we've got; cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1678 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbCopy));
1679 return usbMsdCompleteStall(pThis, NULL, pUrb, "Data underrun");
1680 }
1681 memcpy(&pUrb->abData[0], &pReq->pbBuf[pReq->offBuf], cbCopy);
1682 pReq->offBuf += cbCopy;
1683
1684 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1685 {
1686 Log(("usbMsdHandleBulkDevToHost: Entering STATUS\n"));
1687 pReq->enmState = USBMSDREQSTATE_STATUS;
1688 }
1689 return usbMsdCompleteOk(pThis, pUrb, cbCopy);
1690 }
1691
1692 /*
1693 * Status transfer.
1694 */
1695 case USBMSDREQSTATE_STATUS:
1696 {
1697 if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
1698 {
1699 Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
1700 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1701 }
1702
1703 /* Enter a CSW into the URB data buffer. */
1704 PUSBCSW pCsw = (PUSBCSW)&pUrb->abData[0];
1705 pCsw->dCSWSignature = USBCSW_SIGNATURE;
1706 pCsw->dCSWTag = pReq->Cbw.dCBWTag;
1707 pCsw->bCSWStatus = pReq->iScsiReqStatus == SCSI_STATUS_OK
1708 ? USBCSW_STATUS_OK
1709 : pReq->iScsiReqStatus >= 0
1710 ? USBCSW_STATUS_FAILED
1711 : USBCSW_STATUS_PHASE_ERROR;
1712 /** @todo the following is not always accurate; VSCSI needs
1713 * to implement residual counts properly! */
1714 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1715 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1716 ? pReq->Cbw.dCBWDataTransferLength - pReq->ScsiReq.cbScatterGather
1717 : pReq->Cbw.dCBWDataTransferLength;
1718 else
1719 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1720 ? 0
1721 : pReq->ScsiReq.cbScatterGather;
1722 Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
1723 pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
1724
1725 Log(("usbMsdHandleBulkDevToHost: Entering READY\n"));
1726 pReq->enmState = USBMSDREQSTATE_READY;
1727 return usbMsdCompleteOk(pThis, pUrb, sizeof(*pCsw));
1728 }
1729
1730 /*
1731 * Status request before we've received all (or even any) data.
1732 * Linux 2.4.31 does this sometimes. The recommended behavior is to
1733 * to accept the current data amount and execute the request. (The
1734 * alternative behavior is to stall.)
1735 */
1736 case USBMSDREQSTATE_DATA_FROM_HOST:
1737 {
1738 if (pUrb->cbData != sizeof(USBCSW))
1739 {
1740 Log(("usbMsdHandleBulkDevToHost: DATA_FROM_HOST; cbData=%#x -> stall\n", pUrb->cbData));
1741 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1742 }
1743
1744 /* Adjust the request and kick it off. Special case the no-data
1745 case since the SCSI driver doesn't like that. */
1746 pReq->ScsiReq.cbScatterGather = pReq->offBuf;
1747 pReq->ScsiReqSeg.cbSeg = pReq->offBuf;
1748 if (!pReq->offBuf)
1749 {
1750 Log(("usbMsdHandleBulkDevToHost: Entering EXECUTING (offBuf=0x0).\n"));
1751 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1752
1753 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1754 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1755
1756 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1757 return VINF_SUCCESS;
1758 }
1759
1760 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
1761 if (RT_FAILURE(rc))
1762 {
1763 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1764 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #3");
1765 }
1766
1767 /* fall thru */
1768 }
1769
1770 /*
1771 * The SCSI command is still pending, queue the URB awaiting its
1772 * completion.
1773 */
1774 case USBMSDREQSTATE_EXECUTING:
1775 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1776 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1777 return VINF_SUCCESS;
1778
1779 /*
1780 * Bad states, stall.
1781 */
1782 case USBMSDREQSTATE_READY:
1783 Log(("usbMsdHandleBulkDevToHost: enmState=READ (cbData=%#x)\n", pReq->enmState, pUrb->cbData));
1784 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state D2H: READY");
1785
1786 default:
1787 Log(("usbMsdHandleBulkDevToHost: enmState=%d cbData=%#x\n", pReq->enmState, pUrb->cbData));
1788 return usbMsdCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1789 }
1790}
1791
1792
1793/**
1794 * Handles request send to the default control pipe.
1795 */
1796static int usbMsdHandleDefaultPipe(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1797{
1798 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1799 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1800
1801 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1802 {
1803 switch (pSetup->bRequest)
1804 {
1805 case VUSB_REQ_GET_DESCRIPTOR:
1806 {
1807 if (pSetup->bmRequestType != (VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST))
1808 {
1809 Log(("usbMsd: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
1810 return usbMsdCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1811 }
1812
1813 switch (pSetup->wValue >> 8)
1814 {
1815 uint32_t cbCopy;
1816
1817 case VUSB_DT_STRING:
1818 Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1819 break;
1820 case VUSB_DT_DEVICE_QUALIFIER:
1821 Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1822 /* Returned data is written after the setup message. */
1823 cbCopy = pUrb->cbData - sizeof(*pSetup);
1824 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
1825 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
1826 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1827 default:
1828 Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1829 break;
1830 }
1831 break;
1832 }
1833
1834 case VUSB_REQ_CLEAR_FEATURE:
1835 break;
1836 }
1837
1838 /** @todo implement this. */
1839 Log(("usbMsd: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1840 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1841
1842 usbMsdCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1843 }
1844 /* 3.1 Bulk-Only Mass Storage Reset */
1845 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1846 && pSetup->bRequest == 0xff
1847 && !pSetup->wValue
1848 && !pSetup->wLength
1849 && pSetup->wIndex == 0)
1850 {
1851 Log(("usbMsdHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1852 return usbMsdResetWorker(pThis, pUrb, false /*fSetConfig*/);
1853 }
1854 /* 3.2 Get Max LUN, may stall if we like (but we don't). */
1855 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE | VUSB_DIR_TO_HOST)
1856 && pSetup->bRequest == 0xfe
1857 && !pSetup->wValue
1858 && pSetup->wLength == 1
1859 && pSetup->wIndex == 0)
1860 {
1861 *(uint8_t *)(pSetup + 1) = 0; /* max lun is 0 */
1862 usbMsdCompleteOk(pThis, pUrb, 1);
1863 }
1864 else
1865 {
1866 Log(("usbMsd: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1867 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1868 return usbMsdCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1869 }
1870
1871 return VINF_SUCCESS;
1872}
1873
1874
1875/**
1876 * @copydoc PDMUSBREG::pfnQueue
1877 */
1878static DECLCALLBACK(int) usbMsdQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1879{
1880 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1881 LogFlow(("usbMsdQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
1882 RTCritSectEnter(&pThis->CritSect);
1883
1884 /*
1885 * Parse on a per end-point basis.
1886 */
1887 int rc;
1888 switch (pUrb->EndPt)
1889 {
1890 case 0:
1891 rc = usbMsdHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1892 break;
1893
1894 case 0x81:
1895 AssertFailed();
1896 case 0x01:
1897 rc = usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1898 break;
1899
1900 case 0x02:
1901 rc = usbMsdHandleBulkHostToDev(pThis, &pThis->aEps[2], pUrb);
1902 break;
1903
1904 default:
1905 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1906 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1907 break;
1908 }
1909
1910 RTCritSectLeave(&pThis->CritSect);
1911 return rc;
1912}
1913
1914
1915/**
1916 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1917 */
1918static DECLCALLBACK(int) usbMsdUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1919{
1920 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1921 LogFlow(("usbMsdUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
1922
1923 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1924 {
1925 RTCritSectEnter(&pThis->CritSect);
1926 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1927 RTCritSectLeave(&pThis->CritSect);
1928 }
1929
1930 return VINF_SUCCESS;
1931}
1932
1933
1934/**
1935 * @copydoc PDMUSBREG::pfnUsbSetInterface
1936 */
1937static DECLCALLBACK(int) usbMsdUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1938{
1939 LogFlow(("usbMsdUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1940 Assert(bAlternateSetting == 0);
1941 return VINF_SUCCESS;
1942}
1943
1944
1945/**
1946 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1947 */
1948static DECLCALLBACK(int) usbMsdUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1949 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1950{
1951 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1952 LogFlow(("usbMsdUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
1953 Assert(bConfigurationValue == 1);
1954 RTCritSectEnter(&pThis->CritSect);
1955
1956 /*
1957 * If the same config is applied more than once, it's a kind of reset.
1958 */
1959 if (pThis->bConfigurationValue == bConfigurationValue)
1960 usbMsdResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1961 pThis->bConfigurationValue = bConfigurationValue;
1962
1963 RTCritSectLeave(&pThis->CritSect);
1964 return VINF_SUCCESS;
1965}
1966
1967
1968/**
1969 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1970 */
1971static DECLCALLBACK(PCPDMUSBDESCCACHE) usbMsdUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1972{
1973 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1974 LogFlow(("usbMsdUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1975 if (pThis->pUsbIns->iUsbHubVersion & VUSB_STDVER_30)
1976 return &g_UsbMsdDescCacheSS;
1977 else if (pThis->pUsbIns->iUsbHubVersion & VUSB_STDVER_20)
1978 return &g_UsbMsdDescCacheHS;
1979 else
1980 return &g_UsbMsdDescCacheFS;
1981}
1982
1983
1984/**
1985 * @copydoc PDMUSBREG::pfnUsbReset
1986 */
1987static DECLCALLBACK(int) usbMsdUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1988{
1989 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1990 LogFlow(("usbMsdUsbReset/#%u:\n", pUsbIns->iInstance));
1991 RTCritSectEnter(&pThis->CritSect);
1992
1993 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
1994
1995 RTCritSectLeave(&pThis->CritSect);
1996 return rc;
1997}
1998
1999
2000/**
2001 * @copydoc PDMUSBREG::pfnVMSuspend
2002 */
2003static DECLCALLBACK(void) usbMsdVMSuspend(PPDMUSBINS pUsbIns)
2004{
2005 LogFlow(("usbMsdVMSuspend/#%u:\n", pUsbIns->iInstance));
2006 usbMsdSuspendOrPowerOff(pUsbIns);
2007}
2008
2009
2010/**
2011 * @copydoc PDMUSBREG::pfnVMSuspend
2012 */
2013static DECLCALLBACK(void) usbMsdVMPowerOff(PPDMUSBINS pUsbIns)
2014{
2015 LogFlow(("usbMsdVMPowerOff/#%u:\n", pUsbIns->iInstance));
2016 usbMsdSuspendOrPowerOff(pUsbIns);
2017}
2018
2019
2020/**
2021 * @copydoc PDMUSBREG::pfnDriverAttach
2022 */
2023static DECLCALLBACK(int) usbMsdDriverAttach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2024{
2025 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2026 int rc;
2027
2028 LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
2029
2030 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2031 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2032 ("UsbMsd: Device does not support hotplugging\n"));
2033
2034 /* the usual paranoia */
2035 AssertRelease(!pThis->Lun0.pIBase);
2036 AssertRelease(!pThis->Lun0.pIScsiConnector);
2037
2038 /*
2039 * Try attach the block device and get the interfaces,
2040 * required as well as optional.
2041 */
2042 rc = PDMUsbHlpDriverAttach(pUsbIns, iLUN, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, NULL);
2043 if (RT_SUCCESS(rc))
2044 {
2045 /* Get SCSI connector interface. */
2046 pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
2047 AssertMsgReturn(pThis->Lun0.pIScsiConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
2048 }
2049 else
2050 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", iLUN, rc));
2051
2052 if (RT_FAILURE(rc))
2053 {
2054 pThis->Lun0.pIBase = NULL;
2055 pThis->Lun0.pIScsiConnector = NULL;
2056 }
2057 return rc;
2058}
2059
2060
2061/**
2062 * @copydoc PDMUSBREG::pfnDriverDetach
2063 */
2064static DECLCALLBACK(void) usbMsdDriverDetach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2065{
2066 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2067
2068 LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
2069
2070 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2071 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2072 ("UsbMsd: Device does not support hotplugging\n"));
2073
2074 /*
2075 * Zero some important members.
2076 */
2077 pThis->Lun0.pIBase = NULL;
2078 pThis->Lun0.pIScsiConnector = NULL;
2079}
2080
2081
2082/**
2083 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
2084 * Callback employed by usbMsdVMReset.}
2085 */
2086static DECLCALLBACK(bool) usbMsdIsAsyncResetDone(PPDMUSBINS pUsbIns)
2087{
2088 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2089
2090 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2091 return false;
2092 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2093
2094 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2095 AssertRC(rc);
2096 return true;
2097}
2098
2099/**
2100 * @interface_method_impl{PDMDEVREG,pfnReset}
2101 */
2102static DECLCALLBACK(void) usbMsdVMReset(PPDMUSBINS pUsbIns)
2103{
2104 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2105
2106 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
2107 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2108 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncResetDone);
2109 else
2110 {
2111 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2112 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2113 AssertRC(rc);
2114 }
2115}
2116
2117
2118/**
2119 * @copydoc PDMUSBREG::pfnDestruct
2120 */
2121static void usbMsdDestruct(PPDMUSBINS pUsbIns)
2122{
2123 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2124 LogFlow(("usbMsdDestruct/#%u:\n", pUsbIns->iInstance));
2125
2126 if (RTCritSectIsInitialized(&pThis->CritSect))
2127 {
2128 RTCritSectEnter(&pThis->CritSect);
2129 RTCritSectLeave(&pThis->CritSect);
2130 RTCritSectDelete(&pThis->CritSect);
2131 }
2132
2133 if (pThis->pReq)
2134 {
2135 usbMsdReqFree(pThis->pReq);
2136 pThis->pReq = NULL;
2137 }
2138
2139 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2140 {
2141 RTSemEventDestroy(pThis->hEvtDoneQueue);
2142 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2143 }
2144
2145 if (pThis->hEvtReset != NIL_RTSEMEVENTMULTI)
2146 {
2147 RTSemEventMultiDestroy(pThis->hEvtReset);
2148 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2149 }
2150}
2151
2152
2153/**
2154 * @copydoc PDMUSBREG::pfnConstruct
2155 */
2156static DECLCALLBACK(int) usbMsdConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2157{
2158 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2159 Log(("usbMsdConstruct/#%u:\n", iInstance));
2160
2161 /*
2162 * Perform the basic structure initialization first so the destructor
2163 * will not misbehave.
2164 */
2165 pThis->pUsbIns = pUsbIns;
2166 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2167 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2168 pThis->Lun0.IBase.pfnQueryInterface = usbMsdLun0QueryInterface;
2169 pThis->Lun0.IScsiPort.pfnSCSIRequestCompleted = usbMsdLun0ScsiRequestCompleted;
2170 pThis->Lun0.IScsiPort.pfnQueryDeviceLocation = usbMsdLun0QueryDeviceLocation;
2171 usbMsdQueueInit(&pThis->ToHostQueue);
2172 usbMsdQueueInit(&pThis->DoneQueue);
2173
2174 int rc = RTCritSectInit(&pThis->CritSect);
2175 AssertRCReturn(rc, rc);
2176
2177 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2178 AssertRCReturn(rc, rc);
2179
2180 rc = RTSemEventMultiCreate(&pThis->hEvtReset);
2181 AssertRCReturn(rc, rc);
2182
2183 /*
2184 * Validate and read the configuration.
2185 */
2186 rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbMsd", iInstance);
2187 if (RT_FAILURE(rc))
2188 return rc;
2189
2190 /*
2191 * Attach the SCSI driver.
2192 */
2193 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, "SCSI Port");
2194 if (RT_FAILURE(rc))
2195 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
2196 pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
2197 if (!pThis->Lun0.pIScsiConnector)
2198 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
2199 N_("MSD failed to query the PDMISCSICONNECTOR from the driver below it"));
2200
2201 /*
2202 * Register the saved state data unit.
2203 */
2204 rc = PDMUsbHlpSSMRegister(pUsbIns, USB_MSD_SAVED_STATE_VERSION, sizeof(*pThis),
2205 NULL, usbMsdLiveExec, NULL,
2206 usbMsdSavePrep, usbMsdSaveExec, NULL,
2207 usbMsdLoadPrep, usbMsdLoadExec, NULL);
2208 if (RT_FAILURE(rc))
2209 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2210 N_("MSD failed to register SSM save state handlers"));
2211
2212 return VINF_SUCCESS;
2213}
2214
2215
2216/**
2217 * The USB Mass Storage Device (MSD) registration record.
2218 */
2219const PDMUSBREG g_UsbMsd =
2220{
2221 /* u32Version */
2222 PDM_USBREG_VERSION,
2223 /* szName */
2224 "Msd",
2225 /* pszDescription */
2226 "USB Mass Storage Device, one LUN.",
2227 /* fFlags */
2228 PDM_USBREG_HIGHSPEED_CAPABLE | PDM_USBREG_SUPERSPEED_CAPABLE | PDM_USBREG_EMULATED_DEVICE,
2229 /* cMaxInstances */
2230 ~0U,
2231 /* cbInstance */
2232 sizeof(USBMSD),
2233 /* pfnConstruct */
2234 usbMsdConstruct,
2235 /* pfnDestruct */
2236 usbMsdDestruct,
2237 /* pfnVMInitComplete */
2238 NULL,
2239 /* pfnVMPowerOn */
2240 NULL,
2241 /* pfnVMReset */
2242 usbMsdVMReset,
2243 /* pfnVMSuspend */
2244 usbMsdVMSuspend,
2245 /* pfnVMResume */
2246 NULL,
2247 /* pfnVMPowerOff */
2248 usbMsdVMPowerOff,
2249 /* pfnHotPlugged */
2250 NULL,
2251 /* pfnHotUnplugged */
2252 NULL,
2253 /* pfnDriverAttach */
2254 usbMsdDriverAttach,
2255 /* pfnDriverDetach */
2256 usbMsdDriverDetach,
2257 /* pfnQueryInterface */
2258 NULL,
2259 /* pfnUsbReset */
2260 usbMsdUsbReset,
2261 /* pfnUsbGetCachedDescriptors */
2262 usbMsdUsbGetDescriptorCache,
2263 /* pfnUsbSetConfiguration */
2264 usbMsdUsbSetConfiguration,
2265 /* pfnUsbSetInterface */
2266 usbMsdUsbSetInterface,
2267 /* pfnUsbClearHaltedEndpoint */
2268 usbMsdUsbClearHaltedEndpoint,
2269 /* pfnUrbNew */
2270 NULL/*usbMsdUrbNew*/,
2271 /* pfnQueue */
2272 usbMsdQueue,
2273 /* pfnUrbCancel */
2274 usbMsdUrbCancel,
2275 /* pfnUrbReap */
2276 usbMsdUrbReap,
2277 /* pfnWakeup */
2278 usbMsdWakeup,
2279 /* u32TheEnd */
2280 PDM_USBREG_VERSION
2281};
2282
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