VirtualBox

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

Last change on this file since 63942 was 63482, checked in by vboxsync, 8 years ago

Devices: warnings (clang)

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