VirtualBox

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

Last change on this file since 61541 was 59252, checked in by vboxsync, 9 years ago

pdmifs.h: Move the storage related interfaces (PDMIMEDIA, PDMIMOUNT, PDMISCSICONNECTOR, etc.) into a separate header to reduce the overall size of the header a bit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.3 KB
Line 
1/* $Id: UsbMsd.cpp 59252 2016-01-05 10:54:49Z vboxsync $ */
2/** @file
3 * UsbMSD - USB Mass Storage Device Emulation.
4 */
5
6/*
7 * Copyright (C) 2007-2015 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/**
783 * Checks if the queue is empty or not.
784 *
785 * @returns true if it is, false if it isn't.
786 * @param pQueue The URB queue.
787 */
788DECLINLINE(bool) usbMsdQueueIsEmpty(PCUSBMSDURBQUEUE pQueue)
789{
790 return pQueue->pHead == NULL;
791}
792
793
794/**
795 * Links an URB into the done queue.
796 *
797 * @param pThis The MSD instance.
798 * @param pUrb The URB.
799 */
800static void usbMsdLinkDone(PUSBMSD pThis, PVUSBURB pUrb)
801{
802 usbMsdQueueAddTail(&pThis->DoneQueue, pUrb);
803
804 if (pThis->fHaveDoneQueueWaiter)
805 {
806 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
807 AssertRC(rc);
808 }
809}
810
811
812
813
814/**
815 * Allocates a new request and does basic init.
816 *
817 * @returns Pointer to the new request. NULL if we're out of memory.
818 * @param pUsbIns The instance allocating it.
819 */
820static PUSBMSDREQ usbMsdReqAlloc(PPDMUSBINS pUsbIns)
821{
822 PUSBMSDREQ pReq = (PUSBMSDREQ)PDMUsbHlpMMHeapAllocZ(pUsbIns, sizeof(*pReq));
823 if (pReq)
824 {
825 pReq->enmState = USBMSDREQSTATE_READY;
826 pReq->iScsiReqStatus = -1;
827 pReq->pUsbIns = pUsbIns;
828 }
829 else
830 LogRel(("usbMsdReqAlloc: Out of memory\n"));
831 return pReq;
832}
833
834
835/**
836 * Frees a request.
837 *
838 * @param pReq The request.
839 */
840static void usbMsdReqFree(PUSBMSDREQ pReq)
841{
842 /*
843 * Check the input.
844 */
845 AssertReturnVoid( pReq->enmState > USBMSDREQSTATE_INVALID
846 && pReq->enmState != USBMSDREQSTATE_EXECUTING
847 && pReq->enmState < USBMSDREQSTATE_END);
848 PPDMUSBINS pUsbIns = pReq->pUsbIns;
849 AssertPtrReturnVoid(pUsbIns);
850 AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
851
852 /*
853 * Invalidate it and free the associated resources.
854 */
855 pReq->enmState = USBMSDREQSTATE_INVALID;
856 pReq->cbBuf = 0;
857 pReq->offBuf = 0;
858 pReq->ScsiReq.pbCDB = NULL;
859 pReq->ScsiReq.paScatterGatherHead = NULL;
860 pReq->ScsiReq.pbSenseBuffer = NULL;
861 pReq->ScsiReq.pvUser = NULL;
862 pReq->ScsiReqSeg.cbSeg = 0;
863 pReq->ScsiReqSeg.pvSeg = NULL;
864
865 if (pReq->pbBuf)
866 {
867 PDMUsbHlpMMHeapFree(pUsbIns, pReq->pbBuf);
868 pReq->pbBuf = NULL;
869 }
870
871 PDMUsbHlpMMHeapFree(pUsbIns, pReq);
872}
873
874
875/**
876 * Prepares a request for execution or data buffering.
877 *
878 * @param pReq The request.
879 * @param pCbw The SCSI command block wrapper.
880 */
881static void usbMsdReqPrepare(PUSBMSDREQ pReq, PCUSBCBW pCbw)
882{
883 /* Copy the CBW */
884 size_t cbCopy = RT_OFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]);
885 memcpy(&pReq->Cbw, pCbw, cbCopy);
886 memset((uint8_t *)&pReq->Cbw + cbCopy, 0, sizeof(pReq->Cbw) - cbCopy);
887
888 /* Setup the SCSI request. */
889 pReq->ScsiReq.uLogicalUnit = pReq->Cbw.bCBWLun;
890 pReq->ScsiReq.uDataDirection = (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
891 ? PDMSCSIREQUESTTXDIR_TO_DEVICE
892 : PDMSCSIREQUESTTXDIR_FROM_DEVICE;
893 pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
894
895 pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
896 pReq->offBuf = 0;
897 pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
898 pReq->ScsiReqSeg.cbSeg = pReq->Cbw.dCBWDataTransferLength;
899 pReq->ScsiReq.cbScatterGather = pReq->Cbw.dCBWDataTransferLength;
900 pReq->ScsiReq.cScatterGatherEntries = 1;
901 pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
902 pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
903 pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
904 pReq->ScsiReq.pvUser = NULL;
905 RT_ZERO(pReq->ScsiReqSense);
906 pReq->iScsiReqStatus = -1;
907}
908
909
910/**
911 * Makes sure that there is sufficient buffer space available.
912 *
913 * @returns Success indicator (true/false)
914 * @param pReq
915 * @param cbBuf The required buffer space.
916 */
917static int usbMsdReqEnsureBuffer(PUSBMSDREQ pReq, uint32_t cbBuf)
918{
919 if (RT_LIKELY(pReq->cbBuf >= cbBuf))
920 RT_BZERO(pReq->pbBuf, cbBuf);
921 else
922 {
923 PDMUsbHlpMMHeapFree(pReq->pUsbIns, pReq->pbBuf);
924 pReq->cbBuf = 0;
925
926 cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
927 pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pReq->pUsbIns, cbBuf);
928 if (!pReq->pbBuf)
929 return false;
930
931 pReq->cbBuf = cbBuf;
932 }
933 return true;
934}
935
936
937/**
938 * Completes the URB with a stalled state, halting the pipe.
939 */
940static int usbMsdCompleteStall(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb, const char *pszWhy)
941{
942 Log(("usbMsdCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
943
944 pUrb->enmStatus = VUSBSTATUS_STALL;
945
946 /** @todo figure out if the stall is global or pipe-specific or both. */
947 if (pEp)
948 pEp->fHalted = true;
949 else
950 {
951 pThis->aEps[1].fHalted = true;
952 pThis->aEps[2].fHalted = true;
953 }
954
955 usbMsdLinkDone(pThis, pUrb);
956 return VINF_SUCCESS;
957}
958
959
960/**
961 * Completes the URB with a OK state.
962 */
963static int usbMsdCompleteOk(PUSBMSD pThis, PVUSBURB pUrb, size_t cbData)
964{
965 Log(("usbMsdCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
966
967 pUrb->enmStatus = VUSBSTATUS_OK;
968 pUrb->cbData = (uint32_t)cbData;
969
970 usbMsdLinkDone(pThis, pUrb);
971 return VINF_SUCCESS;
972}
973
974
975/**
976 * Reset worker for usbMsdUsbReset, usbMsdUsbSetConfiguration and
977 * usbMsdUrbHandleDefaultPipe.
978 *
979 * @returns VBox status code.
980 * @param pThis The MSD instance.
981 * @param pUrb Set when usbMsdUrbHandleDefaultPipe is the
982 * caller.
983 * @param fSetConfig Set when usbMsdUsbSetConfiguration is the
984 * caller.
985 */
986static int usbMsdResetWorker(PUSBMSD pThis, PVUSBURB pUrb, bool fSetConfig)
987{
988 /*
989 * Wait for the any command currently executing to complete before
990 * resetting. (We cannot cancel its execution.) How we do this depends
991 * on the reset method.
992 */
993 PUSBMSDREQ pReq = pThis->pReq;
994 if ( pReq
995 && pReq->enmState == USBMSDREQSTATE_EXECUTING)
996 {
997 /* Don't try to deal with the set config variant nor multiple build-only
998 mass storage resets. */
999 if (pThis->pResetUrb && (pUrb || fSetConfig))
1000 {
1001 Log(("usbMsdResetWorker: pResetUrb is already %p:%s - stalling\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
1002 return usbMsdCompleteStall(pThis, NULL, pUrb, "pResetUrb");
1003 }
1004
1005 /* Bulk-Only Mass Storage Reset: Complete the reset on request completion. */
1006 if (pUrb)
1007 {
1008 pThis->pResetUrb = pUrb;
1009 Log(("usbMsdResetWorker: Setting pResetUrb to %p:%s\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
1010 return VINF_SUCCESS;
1011 }
1012
1013 /* Device reset: Wait for up to 10 ms. If it doesn't work, ditch
1014 whoe the request structure. We'll allocate a new one when needed. */
1015 Log(("usbMsdResetWorker: Waiting for completion...\n"));
1016 Assert(!pThis->fSignalResetSem);
1017 pThis->fSignalResetSem = true;
1018 RTSemEventMultiReset(pThis->hEvtReset);
1019 RTCritSectLeave(&pThis->CritSect);
1020
1021 int rc = RTSemEventMultiWait(pThis->hEvtReset, 10 /*ms*/);
1022
1023 RTCritSectEnter(&pThis->CritSect);
1024 pThis->fSignalResetSem = false;
1025 if ( RT_FAILURE(rc)
1026 || pReq->enmState == USBMSDREQSTATE_EXECUTING)
1027 {
1028 Log(("usbMsdResetWorker: Didn't complete, ditching the current request (%p)!\n", pReq));
1029 Assert(pReq == pThis->pReq);
1030 pReq->enmState = USBMSDREQSTATE_DESTROY_ON_COMPLETION;
1031 pThis->pReq = NULL;
1032 pReq = NULL;
1033 }
1034 }
1035
1036 /*
1037 * Reset the request and device state.
1038 */
1039 if (pReq)
1040 {
1041 pReq->enmState = USBMSDREQSTATE_READY;
1042 pReq->iScsiReqStatus = -1;
1043 }
1044
1045 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
1046 pThis->aEps[i].fHalted = false;
1047
1048 if (!pUrb && !fSetConfig) /* (only device reset) */
1049 pThis->bConfigurationValue = 0; /* default */
1050
1051 /*
1052 * Ditch all pending URBs.
1053 */
1054 PVUSBURB pCurUrb;
1055 while ((pCurUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
1056 {
1057 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1058 usbMsdLinkDone(pThis, pCurUrb);
1059 }
1060
1061 pCurUrb = pThis->pResetUrb;
1062 if (pCurUrb)
1063 {
1064 pThis->pResetUrb = NULL;
1065 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1066 usbMsdLinkDone(pThis, pCurUrb);
1067 }
1068
1069 if (pUrb)
1070 return usbMsdCompleteOk(pThis, pUrb, 0);
1071 return VINF_SUCCESS;
1072}
1073
1074
1075/**
1076 * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted}
1077 */
1078static DECLCALLBACK(int) usbMsdLun0ScsiRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
1079 int rcCompletion, bool fRedo, int rcReq)
1080{
1081 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
1082 PUSBMSDREQ pReq = RT_FROM_MEMBER(pSCSIRequest, USBMSDREQ, ScsiReq);
1083
1084 Log(("usbMsdLun0ScsiRequestCompleted: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, rcCompletion));
1085 RTCritSectEnter(&pThis->CritSect);
1086
1087 if (pReq->enmState != USBMSDREQSTATE_DESTROY_ON_COMPLETION)
1088 {
1089 Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
1090 Assert(pThis->pReq == pReq);
1091 pReq->iScsiReqStatus = rcCompletion;
1092
1093 /*
1094 * Advance the state machine. The state machine is not affected by
1095 * SCSI errors.
1096 */
1097 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1098 {
1099 pReq->enmState = USBMSDREQSTATE_STATUS;
1100 Log(("usbMsdLun0ScsiRequestCompleted: Entering STATUS\n"));
1101 }
1102 else
1103 {
1104 pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
1105 Log(("usbMsdLun0ScsiRequestCompleted: Entering DATA_TO_HOST\n"));
1106 }
1107
1108 /*
1109 * Deal with pending to-host URBs.
1110 */
1111 for (;;)
1112 {
1113 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue);
1114 if (!pUrb)
1115 break;
1116
1117 /* Process it the normal way. */
1118 usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1119 }
1120 }
1121 else
1122 {
1123 Log(("usbMsdLun0ScsiRequestCompleted: freeing %p\n", pReq));
1124 usbMsdReqFree(pReq);
1125 }
1126
1127 if (pThis->fSignalResetSem)
1128 RTSemEventMultiSignal(pThis->hEvtReset);
1129
1130 if (pThis->pResetUrb)
1131 {
1132 pThis->pResetUrb = NULL;
1133 usbMsdResetWorker(pThis, pThis->pResetUrb, false /*fSetConfig*/);
1134 }
1135
1136 RTCritSectLeave(&pThis->CritSect);
1137 return VINF_SUCCESS;
1138}
1139
1140
1141/**
1142 * @interface_method_impl{PDMISCSIPORT,pfnQueryDeviceLocation}
1143 */
1144static DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController,
1145 uint32_t *piInstance, uint32_t *piLUN)
1146{
1147 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
1148 PPDMUSBINS pUsbIns = pThis->pUsbIns;
1149
1150 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
1151 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
1152 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
1153
1154 *ppcszController = pUsbIns->pReg->szName;
1155 *piInstance = pUsbIns->iInstance;
1156 *piLUN = 0;
1157
1158 return VINF_SUCCESS;
1159}
1160
1161
1162/**
1163 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1164 */
1165static DECLCALLBACK(void *) usbMsdLun0QueryInterface(PPDMIBASE pInterface, const char *pszIID)
1166{
1167 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
1168 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1169 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pThis->Lun0.IScsiPort);
1170 return NULL;
1171}
1172
1173
1174/**
1175 * Checks if all asynchronous I/O is finished.
1176 *
1177 * Used by usbMsdVMReset, usbMsdVMSuspend and usbMsdVMPowerOff.
1178 *
1179 * @returns true if quiesced, false if busy.
1180 * @param pUsbIns The USB device instance.
1181 */
1182static bool usbMsdAllAsyncIOIsFinished(PPDMUSBINS pUsbIns)
1183{
1184 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1185
1186 if ( VALID_PTR(pThis->pReq)
1187 && pThis->pReq->enmState == USBMSDREQSTATE_EXECUTING)
1188 return false;
1189
1190 return true;
1191}
1192
1193/**
1194 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
1195 * Callback employed by usbMsdVMSuspend and usbMsdVMPowerOff.}
1196 */
1197static DECLCALLBACK(bool) usbMsdIsAsyncSuspendOrPowerOffDone(PPDMUSBINS pUsbIns)
1198{
1199 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1200 return false;
1201
1202 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1203 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1204 return true;
1205}
1206
1207/**
1208 * Common worker for usbMsdVMSuspend and usbMsdVMPowerOff.
1209 */
1210static void usbMsdSuspendOrPowerOff(PPDMUSBINS pUsbIns)
1211{
1212 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1213
1214 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
1215 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
1216 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncSuspendOrPowerOffDone);
1217 else
1218 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
1219}
1220
1221
1222/* -=-=-=-=- Saved State -=-=-=-=- */
1223
1224/**
1225 * @callback_method_impl{FNSSMUSBSAVEPREP}
1226 */
1227static DECLCALLBACK(int) usbMsdSavePrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1228{
1229 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1230
1231 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1232 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1233 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1234 return VINF_SUCCESS;
1235}
1236
1237/**
1238 * @callback_method_impl{FNSSMUSBLOADPREP}
1239 */
1240static DECLCALLBACK(int) usbMsdLoadPrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1241{
1242 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1243
1244 Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
1245 Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
1246 Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
1247 return VINF_SUCCESS;
1248}
1249
1250/**
1251 * @callback_method_impl{FNSSMUSBLIVEEXEC}
1252 */
1253static DECLCALLBACK(int) usbMsdLiveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)
1254{
1255 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1256
1257 /* config. */
1258 SSMR3PutBool(pSSM, pThis->Lun0.pIBase != NULL);
1259 return VINF_SSM_DONT_CALL_AGAIN;
1260}
1261
1262/**
1263 * @callback_method_impl{FNSSMUSBSAVEEXEC}
1264 */
1265static DECLCALLBACK(int) usbMsdSaveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
1266{
1267 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1268 int rc;
1269
1270 /* The config */
1271 rc = usbMsdLiveExec(pUsbIns, pSSM, SSM_PASS_FINAL);
1272 AssertRCReturn(rc, rc);
1273
1274 SSMR3PutU8(pSSM, pThis->bConfigurationValue);
1275 SSMR3PutBool(pSSM, pThis->aEps[0].fHalted);
1276 SSMR3PutBool(pSSM, pThis->aEps[1].fHalted);
1277 SSMR3PutBool(pSSM, pThis->aEps[2].fHalted);
1278 SSMR3PutBool(pSSM, pThis->pReq != NULL);
1279
1280 if (pThis->pReq)
1281 {
1282 PUSBMSDREQ pReq = pThis->pReq;
1283
1284 SSMR3PutU32(pSSM, pReq->enmState);
1285 SSMR3PutU32(pSSM, pReq->cbBuf);
1286 if (pReq->cbBuf)
1287 {
1288 AssertPtr(pReq->pbBuf);
1289 SSMR3PutMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1290 }
1291
1292 SSMR3PutU32(pSSM, pReq->offBuf);
1293 SSMR3PutMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1294 SSMR3PutU32(pSSM, pReq->ScsiReq.uLogicalUnit);
1295 SSMR3PutU32(pSSM, pReq->ScsiReq.uDataDirection);
1296 SSMR3PutU32(pSSM, pReq->ScsiReq.cbCDB);
1297 SSMR3PutU32(pSSM, pReq->ScsiReq.cbScatterGather);
1298 SSMR3PutMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
1299 SSMR3PutS32(pSSM, pReq->iScsiReqStatus);
1300 }
1301
1302 return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1303}
1304
1305/**
1306 * @callback_method_impl{FNSSMUSBLOADEXEC}
1307 */
1308static DECLCALLBACK(int) usbMsdLoadExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1309{
1310 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1311 uint32_t u32;
1312 int rc;
1313
1314 if (uVersion > USB_MSD_SAVED_STATE_VERSION)
1315 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1316
1317 /* Verify config. */
1318 bool fInUse;
1319 rc = SSMR3GetBool(pSSM, &fInUse);
1320 AssertRCReturn(rc, rc);
1321 if (fInUse != (pThis->Lun0.pIBase != NULL))
1322 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1323 N_("The %s VM is missing a USB mass storage device. Please make sure the source and target VMs have compatible storage configurations"),
1324 fInUse ? "target" : "source");
1325
1326 if (uPass == SSM_PASS_FINAL)
1327 {
1328 /* Restore data. */
1329 bool fReqAlloc = false;
1330
1331 Assert(!pThis->pReq);
1332
1333 SSMR3GetU8(pSSM, &pThis->bConfigurationValue);
1334 SSMR3GetBool(pSSM, &pThis->aEps[0].fHalted);
1335 SSMR3GetBool(pSSM, &pThis->aEps[1].fHalted);
1336 SSMR3GetBool(pSSM, &pThis->aEps[2].fHalted);
1337 SSMR3GetBool(pSSM, &fReqAlloc);
1338
1339 if (fReqAlloc)
1340 {
1341 PUSBMSDREQ pReq = usbMsdReqAlloc(pUsbIns);
1342
1343 if (pReq)
1344 {
1345 uint32_t cbBuf = 0;
1346
1347 pThis->pReq = pReq;
1348
1349 SSMR3GetU32(pSSM, (uint32_t *)&pReq->enmState);
1350 SSMR3GetU32(pSSM, &cbBuf);
1351 if (cbBuf)
1352 {
1353 if (usbMsdReqEnsureBuffer(pReq, cbBuf))
1354 {
1355 AssertPtr(pReq->pbBuf);
1356 Assert(cbBuf == pReq->cbBuf);
1357 SSMR3GetMem(pSSM, pReq->pbBuf, pReq->cbBuf);
1358 }
1359 else
1360 rc = VERR_NO_MEMORY;
1361 }
1362
1363 if (RT_SUCCESS(rc))
1364 {
1365 SSMR3GetU32(pSSM, &pReq->offBuf);
1366 SSMR3GetMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
1367 SSMR3GetU32(pSSM, &pReq->ScsiReq.uLogicalUnit);
1368 SSMR3GetU32(pSSM, (uint32_t *)&pReq->ScsiReq.uDataDirection);
1369 SSMR3GetU32(pSSM, &pReq->ScsiReq.cbCDB);
1370 SSMR3GetU32(pSSM, &pReq->ScsiReq.cbScatterGather);
1371 SSMR3GetMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
1372 SSMR3GetS32(pSSM, &pReq->iScsiReqStatus);
1373
1374 /* Setup the rest of the SCSI request. */
1375 pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
1376 pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
1377 pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
1378 pReq->ScsiReqSeg.cbSeg = pReq->ScsiReq.cbScatterGather;
1379 pReq->ScsiReq.cScatterGatherEntries = 1;
1380 pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
1381 pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
1382 pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
1383 pReq->ScsiReq.pvUser = NULL;
1384 }
1385 }
1386 else
1387 rc = VERR_NO_MEMORY;
1388 }
1389
1390 if (RT_SUCCESS(rc))
1391 rc = SSMR3GetU32(pSSM, &u32);
1392
1393 if (RT_FAILURE(rc))
1394 return rc;
1395 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1396 }
1397
1398 return VINF_SUCCESS;
1399}
1400
1401
1402/**
1403 * @interface_method_impl{PDMUSBREG,pfnUrbReap}
1404 */
1405static DECLCALLBACK(PVUSBURB) usbMsdUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1406{
1407 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1408 LogFlow(("usbMsdUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1409
1410 RTCritSectEnter(&pThis->CritSect);
1411
1412 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1413 if (!pUrb && cMillies)
1414 {
1415 /* Wait */
1416 pThis->fHaveDoneQueueWaiter = true;
1417 RTCritSectLeave(&pThis->CritSect);
1418
1419 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1420
1421 RTCritSectEnter(&pThis->CritSect);
1422 pThis->fHaveDoneQueueWaiter = false;
1423
1424 pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
1425 }
1426
1427 RTCritSectLeave(&pThis->CritSect);
1428
1429 if (pUrb)
1430 Log(("usbMsdUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1431 return pUrb;
1432}
1433
1434
1435/**
1436 * @interface_method_impl{PDMUSBREG,pfnWakeup}
1437 */
1438static DECLCALLBACK(int) usbMsdWakeup(PPDMUSBINS pUsbIns)
1439{
1440 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1441 LogFlow(("usbMsdUrbReap/#%u:\n", pUsbIns->iInstance));
1442
1443 return RTSemEventSignal(pThis->hEvtDoneQueue);
1444}
1445
1446
1447/**
1448 * @interface_method_impl{PDMUSBREG,pfnUrbCancel}
1449 */
1450static DECLCALLBACK(int) usbMsdUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1451{
1452 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1453 LogFlow(("usbMsdUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1454 RTCritSectEnter(&pThis->CritSect);
1455
1456 /*
1457 * Remove the URB from the to-host queue and move it onto the done queue.
1458 */
1459 if (usbMsdQueueRemove(&pThis->ToHostQueue, pUrb))
1460 usbMsdLinkDone(pThis, pUrb);
1461
1462 RTCritSectLeave(&pThis->CritSect);
1463 return VINF_SUCCESS;
1464}
1465
1466
1467/**
1468 * Fails an illegal SCSI request.
1469 *
1470 * @returns VBox status code.
1471 * @param pThis The MSD instance data.
1472 * @param pReq The MSD request.
1473 * @param bAsc The ASC for the SCSI_SENSE_ILLEGAL_REQUEST.
1474 * @param bAscq The ASC qualifier.
1475 * @param pszWhy For logging why.
1476 */
1477static int usbMsdScsiIllegalRequest(PUSBMSD pThis, PUSBMSDREQ pReq, uint8_t bAsc, uint8_t bAscq, const char *pszWhy)
1478{
1479 Log(("usbMsdScsiIllegalRequest: bAsc=%#x bAscq=%#x %s\n", bAsc, bAscq, pszWhy));
1480
1481 RT_ZERO(pReq->ScsiReqSense);
1482 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1483 pReq->ScsiReqSense[2] = SCSI_SENSE_ILLEGAL_REQUEST;
1484 pReq->ScsiReqSense[7] = 10;
1485 pReq->ScsiReqSense[12] = SCSI_ASC_INVALID_MESSAGE;
1486 pReq->ScsiReqSense[13] = 0; /* Should be ASCQ but it has the same value for success. */
1487
1488 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
1489 return VINF_SUCCESS;
1490}
1491
1492
1493/**
1494 * The SCSI driver doesn't handle SCSI_REQUEST_SENSE but instead
1495 * returns the sense info with the request.
1496 *
1497 */
1498static int usbMsdHandleScsiReqestSense(PUSBMSD pThis, PUSBMSDREQ pReq, PCUSBCBW pCbw)
1499{
1500 Log(("usbMsdHandleScsiReqestSense: Entering EXECUTING (dCBWTag=%#x).\n", pReq->Cbw.dCBWTag));
1501 Assert(pReq == pThis->pReq);
1502 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1503
1504 /* validation */
1505 if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
1506 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
1507 if (pCbw->bCBWCBLength < 6)
1508 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
1509 if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
1510 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "lun");
1511 if (pCbw->bCBWLun != 0)
1512 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
1513 if (pCbw->CBWCB[4] < 6)
1514 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
1515
1516 /* If the previous command succeeded successfully, whip up some sense data. */
1517 if ( pReq->iScsiReqStatus == SCSI_STATUS_OK
1518 && pReq->ScsiReqSense[0] == 0)
1519 {
1520 RT_ZERO(pReq->ScsiReqSense);
1521#if 0 /** @todo something upsets linux about this stuff. Needs investigation. */
1522 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1523 pReq->ScsiReqSense[0] = SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1524 pReq->ScsiReqSense[2] = SCSI_SENSE_NONE;
1525 pReq->ScsiReqSense[7] = 10;
1526 pReq->ScsiReqSense[12] = SCSI_ASC_NONE;
1527 pReq->ScsiReqSense[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
1528#endif
1529 }
1530
1531 /* Copy the data into the result buffer. */
1532 size_t cbCopy = RT_MIN(pCbw->dCBWDataTransferLength, sizeof(pReq->ScsiReqSense));
1533 Log(("usbMsd: SCSI_REQUEST_SENSE - CBWCB[4]=%#x iOldState=%d, %u bytes, raw: %.*Rhxs\n",
1534 pCbw->CBWCB[4], pReq->iScsiReqStatus, pCbw->dCBWDataTransferLength, RT_MAX(1, cbCopy), pReq->ScsiReqSense));
1535 memcpy(pReq->pbBuf, &pReq->ScsiReqSense[0], cbCopy);
1536
1537 usbMsdReqPrepare(pReq, pCbw);
1538
1539 /* Do normal completion. */
1540 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1541 return VINF_SUCCESS;
1542}
1543
1544
1545/**
1546 * Wrapper around PDMISCSICONNECTOR::pfnSCSIRequestSend that deals with
1547 * SCSI_REQUEST_SENSE.
1548 *
1549 * @returns VBox status code.
1550 * @param pThis The MSD instance data.
1551 * @param pReq The MSD request.
1552 * @param pszCaller Where we're called from.
1553 */
1554static int usbMsdSubmitScsiCommand(PUSBMSD pThis, PUSBMSDREQ pReq, const char *pszCaller)
1555{
1556 Log(("%s: Entering EXECUTING (dCBWTag=%#x).\n", pszCaller, pReq->Cbw.dCBWTag));
1557 Assert(pReq == pThis->pReq);
1558 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1559
1560 switch (pReq->ScsiReq.pbCDB[0])
1561 {
1562 case SCSI_REQUEST_SENSE:
1563 {
1564 }
1565
1566 default:
1567 return pThis->Lun0.pIScsiConnector->pfnSCSIRequestSend(pThis->Lun0.pIScsiConnector, &pReq->ScsiReq);
1568 }
1569}
1570
1571/**
1572 * Validates a SCSI request before passing it down to the SCSI driver.
1573 *
1574 * @returns true / false. The request will be completed on failure.
1575 * @param pThis The MSD instance data.
1576 * @param pCbw The USB command block wrapper.
1577 * @param pUrb The URB.
1578 */
1579static bool usbMsdIsValidCommand(PUSBMSD pThis, PCUSBCBW pCbw, PVUSBURB pUrb)
1580{
1581 switch (pCbw->CBWCB[0])
1582 {
1583 case SCSI_REQUEST_SENSE:
1584 /** @todo validate this. */
1585 return true;
1586
1587 default:
1588 return true;
1589 }
1590}
1591
1592
1593/**
1594 * Handle requests sent to the outbound (to device) bulk pipe.
1595 */
1596static int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1597{
1598 /*
1599 * Stall the request if the pipe is halted.
1600 */
1601 if (RT_UNLIKELY(pEp->fHalted))
1602 return usbMsdCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1603
1604 /*
1605 * Deal with the URB according to the current state.
1606 */
1607 PUSBMSDREQ pReq = pThis->pReq;
1608 USBMSDREQSTATE enmState = pReq ? pReq->enmState : USBMSDREQSTATE_READY;
1609 switch (enmState)
1610 {
1611 case USBMSDREQSTATE_STATUS:
1612 LogFlow(("usbMsdHandleBulkHostToDev: Skipping pending status.\n"));
1613 pReq->enmState = USBMSDREQSTATE_READY;
1614 /* fall thru */
1615
1616 /*
1617 * We're ready to receive a command. Start off by validating the
1618 * incoming request.
1619 */
1620 case USBMSDREQSTATE_READY:
1621 {
1622 PCUSBCBW pCbw = (PUSBCBW)&pUrb->abData[0];
1623 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[1]))
1624 {
1625 Log(("usbMsd: Bad CBW: cbData=%#x < min=%#x\n", pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[1]) ));
1626 return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
1627 }
1628 if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
1629 {
1630 Log(("usbMsd: CBW: Invalid dCBWSignature value: %#x\n", pCbw->dCBWSignature));
1631 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1632 }
1633 Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x cbData=%#x fShortNotOk=%RTbool\n",
1634 pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
1635 if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
1636 {
1637 Log(("usbMsd: CBW: Bad bmCBWFlags value: %#x\n", pCbw->bmCBWFlags));
1638 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1639
1640 }
1641 if (pCbw->bCBWLun != 0)
1642 {
1643 Log(("usbMsd: CBW: Bad bCBWLun value: %#x\n", pCbw->bCBWLun));
1644 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1645 }
1646 if (pCbw->bCBWCBLength == 0)
1647 {
1648 Log(("usbMsd: CBW: Bad bCBWCBLength value: %#x\n", pCbw->bCBWCBLength));
1649 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1650 }
1651 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]))
1652 {
1653 Log(("usbMsd: CBW: Mismatching cbData and bCBWCBLength values: %#x vs. %#x (%#x)\n",
1654 pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]), pCbw->bCBWCBLength));
1655 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1656 }
1657 if (pCbw->dCBWDataTransferLength > _1M)
1658 {
1659 Log(("usbMsd: CBW: dCBWDataTransferLength is too large: %#x (%u)\n",
1660 pCbw->dCBWDataTransferLength, pCbw->dCBWDataTransferLength));
1661 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too big transfer");
1662 }
1663
1664 if (!usbMsdIsValidCommand(pThis, pCbw, pUrb))
1665 return VINF_SUCCESS;
1666
1667 /*
1668 * Make sure we've got a request and a sufficient buffer space.
1669 *
1670 * Note! This will make sure the buffer is ZERO as well, thus
1671 * saving us the trouble of clearing the output buffer on
1672 * failure later.
1673 */
1674 if (!pReq)
1675 {
1676 pReq = usbMsdReqAlloc(pThis->pUsbIns);
1677 if (!pReq)
1678 return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
1679 pThis->pReq = pReq;
1680 }
1681 if (!usbMsdReqEnsureBuffer(pReq, pCbw->dCBWDataTransferLength))
1682 return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
1683
1684 /*
1685 * Special case REQUEST SENSE requests, usbMsdReqPrepare will
1686 * trash the sense data otherwise.
1687 */
1688 if (pCbw->CBWCB[0] == SCSI_REQUEST_SENSE)
1689 usbMsdHandleScsiReqestSense(pThis, pReq, pCbw);
1690 else
1691 {
1692 /*
1693 * Prepare the request. Kick it off right away if possible.
1694 */
1695 usbMsdReqPrepare(pReq, pCbw);
1696
1697 if ( pReq->Cbw.dCBWDataTransferLength == 0
1698 || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
1699 {
1700 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1701 if (RT_FAILURE(rc))
1702 {
1703 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1704 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
1705 }
1706 }
1707 else
1708 {
1709 Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
1710 pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
1711 }
1712 }
1713
1714 return usbMsdCompleteOk(pThis, pUrb, pUrb->cbData);
1715 }
1716
1717 /*
1718 * Stuff the data into the buffer.
1719 */
1720 case USBMSDREQSTATE_DATA_FROM_HOST:
1721 {
1722 uint32_t cbData = pUrb->cbData;
1723 uint32_t cbLeft = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1724 if (cbData > cbLeft)
1725 {
1726 Log(("usbMsd: Too much data: cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1727 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbLeft));
1728 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too much data");
1729 }
1730 memcpy(&pReq->pbBuf[pReq->offBuf], &pUrb->abData[0], cbData);
1731 pReq->offBuf += cbData;
1732
1733 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1734 {
1735 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1736 if (RT_FAILURE(rc))
1737 {
1738 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1739 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #2");
1740 }
1741 }
1742 return usbMsdCompleteOk(pThis, pUrb, cbData);
1743 }
1744
1745 /*
1746 * Bad state, stall.
1747 */
1748 case USBMSDREQSTATE_DATA_TO_HOST:
1749 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: DATA_TO_HOST");
1750
1751 case USBMSDREQSTATE_EXECUTING:
1752 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: EXECUTING");
1753
1754 default:
1755 AssertMsgFailed(("enmState=%d\n", enmState));
1756 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state (H2D)");
1757 }
1758}
1759
1760
1761/**
1762 * Handle requests sent to the inbound (to host) bulk pipe.
1763 */
1764static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1765{
1766 /*
1767 * Stall the request if the pipe is halted OR if there is no
1768 * pending request yet.
1769 */
1770 PUSBMSDREQ pReq = pThis->pReq;
1771 if (RT_UNLIKELY(pEp->fHalted || !pReq))
1772 return usbMsdCompleteStall(pThis, NULL, pUrb, pEp->fHalted ? "Halted pipe" : "No request");
1773
1774 /*
1775 * Deal with the URB according to the state.
1776 */
1777 switch (pReq->enmState)
1778 {
1779 /*
1780 * We've data left to transfer to the host.
1781 */
1782 case USBMSDREQSTATE_DATA_TO_HOST:
1783 {
1784 uint32_t cbData = pUrb->cbData;
1785 uint32_t cbCopy = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1786 if (cbData <= cbCopy)
1787 cbCopy = cbData;
1788 else if (pUrb->fShortNotOk)
1789 {
1790 Log(("usbMsd: Requested more data that we've got; cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1791 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbCopy));
1792 return usbMsdCompleteStall(pThis, NULL, pUrb, "Data underrun");
1793 }
1794 memcpy(&pUrb->abData[0], &pReq->pbBuf[pReq->offBuf], cbCopy);
1795 pReq->offBuf += cbCopy;
1796
1797 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1798 {
1799 Log(("usbMsdHandleBulkDevToHost: Entering STATUS\n"));
1800 pReq->enmState = USBMSDREQSTATE_STATUS;
1801 }
1802 return usbMsdCompleteOk(pThis, pUrb, cbCopy);
1803 }
1804
1805 /*
1806 * Status transfer.
1807 */
1808 case USBMSDREQSTATE_STATUS:
1809 {
1810 if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
1811 {
1812 Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
1813 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1814 }
1815
1816 /* Enter a CSW into the URB data buffer. */
1817 PUSBCSW pCsw = (PUSBCSW)&pUrb->abData[0];
1818 pCsw->dCSWSignature = USBCSW_SIGNATURE;
1819 pCsw->dCSWTag = pReq->Cbw.dCBWTag;
1820 pCsw->bCSWStatus = pReq->iScsiReqStatus == SCSI_STATUS_OK
1821 ? USBCSW_STATUS_OK
1822 : pReq->iScsiReqStatus >= 0
1823 ? USBCSW_STATUS_FAILED
1824 : USBCSW_STATUS_PHASE_ERROR;
1825 /** @todo the following is not always accurate; VSCSI needs
1826 * to implement residual counts properly! */
1827 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1828 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1829 ? pReq->Cbw.dCBWDataTransferLength - pReq->ScsiReq.cbScatterGather
1830 : pReq->Cbw.dCBWDataTransferLength;
1831 else
1832 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1833 ? 0
1834 : pReq->ScsiReq.cbScatterGather;
1835 Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
1836 pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
1837
1838 Log(("usbMsdHandleBulkDevToHost: Entering READY\n"));
1839 pReq->enmState = USBMSDREQSTATE_READY;
1840 return usbMsdCompleteOk(pThis, pUrb, sizeof(*pCsw));
1841 }
1842
1843 /*
1844 * Status request before we've received all (or even any) data.
1845 * Linux 2.4.31 does this sometimes. The recommended behavior is to
1846 * to accept the current data amount and execute the request. (The
1847 * alternative behavior is to stall.)
1848 */
1849 case USBMSDREQSTATE_DATA_FROM_HOST:
1850 {
1851 if (pUrb->cbData != sizeof(USBCSW))
1852 {
1853 Log(("usbMsdHandleBulkDevToHost: DATA_FROM_HOST; cbData=%#x -> stall\n", pUrb->cbData));
1854 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1855 }
1856
1857 /* Adjust the request and kick it off. Special case the no-data
1858 case since the SCSI driver doesn't like that. */
1859 pReq->ScsiReq.cbScatterGather = pReq->offBuf;
1860 pReq->ScsiReqSeg.cbSeg = pReq->offBuf;
1861 if (!pReq->offBuf)
1862 {
1863 Log(("usbMsdHandleBulkDevToHost: Entering EXECUTING (offBuf=0x0).\n"));
1864 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1865
1866 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1867 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1868
1869 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1870 return VINF_SUCCESS;
1871 }
1872
1873 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
1874 if (RT_FAILURE(rc))
1875 {
1876 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1877 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #3");
1878 }
1879
1880 /* fall thru */
1881 }
1882
1883 /*
1884 * The SCSI command is still pending, queue the URB awaiting its
1885 * completion.
1886 */
1887 case USBMSDREQSTATE_EXECUTING:
1888 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1889 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1890 return VINF_SUCCESS;
1891
1892 /*
1893 * Bad states, stall.
1894 */
1895 case USBMSDREQSTATE_READY:
1896 Log(("usbMsdHandleBulkDevToHost: enmState=READ(%d) (cbData=%#x)\n", pReq->enmState, pUrb->cbData));
1897 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state D2H: READY");
1898
1899 default:
1900 Log(("usbMsdHandleBulkDevToHost: enmState=%d cbData=%#x\n", pReq->enmState, pUrb->cbData));
1901 return usbMsdCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1902 }
1903}
1904
1905
1906/**
1907 * Handles request send to the default control pipe.
1908 */
1909static int usbMsdHandleDefaultPipe(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1910{
1911 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1912 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1913
1914 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1915 {
1916 switch (pSetup->bRequest)
1917 {
1918 case VUSB_REQ_GET_DESCRIPTOR:
1919 {
1920 if (pSetup->bmRequestType != (VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST))
1921 {
1922 Log(("usbMsd: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
1923 return usbMsdCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1924 }
1925
1926 switch (pSetup->wValue >> 8)
1927 {
1928 uint32_t cbCopy;
1929
1930 case VUSB_DT_STRING:
1931 Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1932 break;
1933 case VUSB_DT_DEVICE_QUALIFIER:
1934 Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1935 /* Returned data is written after the setup message. */
1936 cbCopy = pUrb->cbData - sizeof(*pSetup);
1937 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
1938 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
1939 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1940 case VUSB_DT_BOS:
1941 Log(("usbMsd: GET_DESCRIPTOR DT_BOS wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1942 /* Returned data is written after the setup message. */
1943 cbCopy = pUrb->cbData - sizeof(*pSetup);
1944 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdBOS));
1945 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdBOS, cbCopy);
1946 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1947 default:
1948 Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1949 break;
1950 }
1951 break;
1952 }
1953
1954 case VUSB_REQ_CLEAR_FEATURE:
1955 break;
1956 }
1957
1958 /** @todo implement this. */
1959 Log(("usbMsd: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1960 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1961
1962 usbMsdCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1963 }
1964 /* 3.1 Bulk-Only Mass Storage Reset */
1965 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1966 && pSetup->bRequest == 0xff
1967 && !pSetup->wValue
1968 && !pSetup->wLength
1969 && pSetup->wIndex == 0)
1970 {
1971 Log(("usbMsdHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1972 return usbMsdResetWorker(pThis, pUrb, false /*fSetConfig*/);
1973 }
1974 /* 3.2 Get Max LUN, may stall if we like (but we don't). */
1975 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE | VUSB_DIR_TO_HOST)
1976 && pSetup->bRequest == 0xfe
1977 && !pSetup->wValue
1978 && pSetup->wLength == 1
1979 && pSetup->wIndex == 0)
1980 {
1981 *(uint8_t *)(pSetup + 1) = 0; /* max lun is 0 */
1982 usbMsdCompleteOk(pThis, pUrb, 1);
1983 }
1984 else
1985 {
1986 Log(("usbMsd: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1987 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1988 return usbMsdCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1989 }
1990
1991 return VINF_SUCCESS;
1992}
1993
1994
1995/**
1996 * @interface_method_impl{PDMUSBREG,pfnQueue}
1997 */
1998static DECLCALLBACK(int) usbMsdQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1999{
2000 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2001 LogFlow(("usbMsdQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
2002 RTCritSectEnter(&pThis->CritSect);
2003
2004 /*
2005 * Parse on a per end-point basis.
2006 */
2007 int rc;
2008 switch (pUrb->EndPt)
2009 {
2010 case 0:
2011 rc = usbMsdHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
2012 break;
2013
2014 case 0x81:
2015 AssertFailed();
2016 case 0x01:
2017 rc = usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
2018 break;
2019
2020 case 0x02:
2021 rc = usbMsdHandleBulkHostToDev(pThis, &pThis->aEps[2], pUrb);
2022 break;
2023
2024 default:
2025 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
2026 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
2027 break;
2028 }
2029
2030 RTCritSectLeave(&pThis->CritSect);
2031 return rc;
2032}
2033
2034
2035/**
2036 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
2037 */
2038static DECLCALLBACK(int) usbMsdUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
2039{
2040 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2041 LogFlow(("usbMsdUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
2042
2043 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
2044 {
2045 RTCritSectEnter(&pThis->CritSect);
2046 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
2047 RTCritSectLeave(&pThis->CritSect);
2048 }
2049
2050 return VINF_SUCCESS;
2051}
2052
2053
2054/**
2055 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
2056 */
2057static DECLCALLBACK(int) usbMsdUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2058{
2059 LogFlow(("usbMsdUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2060 Assert(bAlternateSetting == 0);
2061 return VINF_SUCCESS;
2062}
2063
2064
2065/**
2066 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
2067 */
2068static DECLCALLBACK(int) usbMsdUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2069 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2070{
2071 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2072 LogFlow(("usbMsdUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
2073 Assert(bConfigurationValue == 1);
2074 RTCritSectEnter(&pThis->CritSect);
2075
2076 /*
2077 * If the same config is applied more than once, it's a kind of reset.
2078 */
2079 if (pThis->bConfigurationValue == bConfigurationValue)
2080 usbMsdResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2081 pThis->bConfigurationValue = bConfigurationValue;
2082
2083 RTCritSectLeave(&pThis->CritSect);
2084 return VINF_SUCCESS;
2085}
2086
2087
2088/**
2089 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
2090 */
2091static DECLCALLBACK(PCPDMUSBDESCCACHE) usbMsdUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2092{
2093 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2094 LogFlow(("usbMsdUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2095 if (pThis->pUsbIns->enmSpeed == VUSB_SPEED_SUPER)
2096 return pThis->fIsCdrom ? &g_UsbCdDescCacheSS : &g_UsbMsdDescCacheSS;
2097 else if (pThis->pUsbIns->enmSpeed == VUSB_SPEED_HIGH)
2098 return pThis->fIsCdrom ? &g_UsbCdDescCacheHS : &g_UsbMsdDescCacheHS;
2099 else
2100 return pThis->fIsCdrom ? &g_UsbCdDescCacheFS : &g_UsbMsdDescCacheFS;
2101}
2102
2103
2104/**
2105 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
2106 */
2107static DECLCALLBACK(int) usbMsdUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2108{
2109 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2110 LogFlow(("usbMsdUsbReset/#%u:\n", pUsbIns->iInstance));
2111 RTCritSectEnter(&pThis->CritSect);
2112
2113 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2114
2115 RTCritSectLeave(&pThis->CritSect);
2116 return rc;
2117}
2118
2119
2120/**
2121 * @interface_method_impl{PDMUSBREG,pfnVMSuspend}
2122 */
2123static DECLCALLBACK(void) usbMsdVMSuspend(PPDMUSBINS pUsbIns)
2124{
2125 LogFlow(("usbMsdVMSuspend/#%u:\n", pUsbIns->iInstance));
2126 usbMsdSuspendOrPowerOff(pUsbIns);
2127}
2128
2129
2130/**
2131 * @interface_method_impl{PDMUSBREG,pfnVMSuspend}
2132 */
2133static DECLCALLBACK(void) usbMsdVMPowerOff(PPDMUSBINS pUsbIns)
2134{
2135 LogFlow(("usbMsdVMPowerOff/#%u:\n", pUsbIns->iInstance));
2136 usbMsdSuspendOrPowerOff(pUsbIns);
2137}
2138
2139
2140/**
2141 * @interface_method_impl{PDMUSBREG,pfnDriverAttach}
2142 */
2143static DECLCALLBACK(int) usbMsdDriverAttach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2144{
2145 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2146 int rc;
2147
2148 LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
2149
2150 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2151 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2152 ("UsbMsd: Device does not support hotplugging\n"));
2153
2154 /* the usual paranoia */
2155 AssertRelease(!pThis->Lun0.pIBase);
2156 AssertRelease(!pThis->Lun0.pIScsiConnector);
2157
2158 /*
2159 * Try attach the block device and get the interfaces,
2160 * required as well as optional.
2161 */
2162 rc = PDMUsbHlpDriverAttach(pUsbIns, iLUN, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, NULL);
2163 if (RT_SUCCESS(rc))
2164 {
2165 /* Get SCSI connector interface. */
2166 pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
2167 AssertMsgReturn(pThis->Lun0.pIScsiConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
2168 }
2169 else
2170 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", iLUN, rc));
2171
2172 if (RT_FAILURE(rc))
2173 {
2174 pThis->Lun0.pIBase = NULL;
2175 pThis->Lun0.pIScsiConnector = NULL;
2176 }
2177
2178 /*
2179 * Find out what kind of device we are.
2180 */
2181 PDMSCSILUNTYPE enmLunType;
2182 pThis->fIsCdrom = false;
2183 rc = pThis->Lun0.pIScsiConnector->pfnQueryLUNType(pThis->Lun0.pIScsiConnector, 0 /*iLun*/, &enmLunType);
2184 if (RT_SUCCESS(rc))
2185 {
2186 /* Anything else will be reported as a hard disk. */
2187 if (enmLunType == PDMSCSILUNTYPE_MMC)
2188 pThis->fIsCdrom = true;
2189 }
2190
2191 return rc;
2192}
2193
2194
2195/**
2196 * @interface_method_impl{PDMUSBREG,pfnDriverDetach}
2197 */
2198static DECLCALLBACK(void) usbMsdDriverDetach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
2199{
2200 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2201
2202 LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
2203
2204 AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
2205 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2206 ("UsbMsd: Device does not support hotplugging\n"));
2207
2208 /*
2209 * Zero some important members.
2210 */
2211 pThis->Lun0.pIBase = NULL;
2212 pThis->Lun0.pIScsiConnector = NULL;
2213}
2214
2215
2216/**
2217 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
2218 * Callback employed by usbMsdVMReset.}
2219 */
2220static DECLCALLBACK(bool) usbMsdIsAsyncResetDone(PPDMUSBINS pUsbIns)
2221{
2222 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2223
2224 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2225 return false;
2226 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2227
2228 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2229 AssertRC(rc);
2230 return true;
2231}
2232
2233/**
2234 * @interface_method_impl{PDMDEVREG,pfnReset}
2235 */
2236static DECLCALLBACK(void) usbMsdVMReset(PPDMUSBINS pUsbIns)
2237{
2238 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2239
2240 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
2241 if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
2242 PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncResetDone);
2243 else
2244 {
2245 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2246 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
2247 AssertRC(rc);
2248 }
2249}
2250
2251
2252/**
2253 * @interface_method_impl{PDMUSBREG,pfnDestruct}
2254 */
2255static DECLCALLBACK(void) usbMsdDestruct(PPDMUSBINS pUsbIns)
2256{
2257 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2258 LogFlow(("usbMsdDestruct/#%u:\n", pUsbIns->iInstance));
2259
2260 if (RTCritSectIsInitialized(&pThis->CritSect))
2261 {
2262 RTCritSectEnter(&pThis->CritSect);
2263 RTCritSectLeave(&pThis->CritSect);
2264 RTCritSectDelete(&pThis->CritSect);
2265 }
2266
2267 if (pThis->pReq)
2268 {
2269 usbMsdReqFree(pThis->pReq);
2270 pThis->pReq = NULL;
2271 }
2272
2273 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2274 {
2275 RTSemEventDestroy(pThis->hEvtDoneQueue);
2276 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2277 }
2278
2279 if (pThis->hEvtReset != NIL_RTSEMEVENTMULTI)
2280 {
2281 RTSemEventMultiDestroy(pThis->hEvtReset);
2282 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2283 }
2284}
2285
2286
2287/**
2288 * @interface_method_impl{PDMUSBREG,pfnConstruct}
2289 */
2290static DECLCALLBACK(int) usbMsdConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2291{
2292 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
2293 Log(("usbMsdConstruct/#%u:\n", iInstance));
2294
2295 /*
2296 * Perform the basic structure initialization first so the destructor
2297 * will not misbehave.
2298 */
2299 pThis->pUsbIns = pUsbIns;
2300 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2301 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
2302 pThis->Lun0.IBase.pfnQueryInterface = usbMsdLun0QueryInterface;
2303 pThis->Lun0.IScsiPort.pfnSCSIRequestCompleted = usbMsdLun0ScsiRequestCompleted;
2304 pThis->Lun0.IScsiPort.pfnQueryDeviceLocation = usbMsdLun0QueryDeviceLocation;
2305 usbMsdQueueInit(&pThis->ToHostQueue);
2306 usbMsdQueueInit(&pThis->DoneQueue);
2307
2308 int rc = RTCritSectInit(&pThis->CritSect);
2309 AssertRCReturn(rc, rc);
2310
2311 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2312 AssertRCReturn(rc, rc);
2313
2314 rc = RTSemEventMultiCreate(&pThis->hEvtReset);
2315 AssertRCReturn(rc, rc);
2316
2317 /*
2318 * Validate and read the configuration.
2319 */
2320 rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbMsd", iInstance);
2321 if (RT_FAILURE(rc))
2322 return rc;
2323
2324 /*
2325 * Attach the SCSI driver.
2326 */
2327 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, "SCSI Port");
2328 if (RT_FAILURE(rc))
2329 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
2330 pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
2331 if (!pThis->Lun0.pIScsiConnector)
2332 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
2333 N_("MSD failed to query the PDMISCSICONNECTOR from the driver below it"));
2334
2335 /*
2336 * Find out what kind of device we are.
2337 */
2338 PDMSCSILUNTYPE enmLunType;
2339 pThis->fIsCdrom = false;
2340 rc = pThis->Lun0.pIScsiConnector->pfnQueryLUNType(pThis->Lun0.pIScsiConnector, 0 /*iLun*/, &enmLunType);
2341 if (RT_SUCCESS(rc))
2342 {
2343 /* Anything else will be reported as a hard disk. */
2344 if (enmLunType == PDMSCSILUNTYPE_MMC)
2345 pThis->fIsCdrom = true;
2346 }
2347
2348 /*
2349 * Register the saved state data unit.
2350 */
2351 rc = PDMUsbHlpSSMRegister(pUsbIns, USB_MSD_SAVED_STATE_VERSION, sizeof(*pThis),
2352 NULL, usbMsdLiveExec, NULL,
2353 usbMsdSavePrep, usbMsdSaveExec, NULL,
2354 usbMsdLoadPrep, usbMsdLoadExec, NULL);
2355 if (RT_FAILURE(rc))
2356 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2357 N_("MSD failed to register SSM save state handlers"));
2358
2359 return VINF_SUCCESS;
2360}
2361
2362
2363/**
2364 * The USB Mass Storage Device (MSD) registration record.
2365 */
2366const PDMUSBREG g_UsbMsd =
2367{
2368 /* u32Version */
2369 PDM_USBREG_VERSION,
2370 /* szName */
2371 "Msd",
2372 /* pszDescription */
2373 "USB Mass Storage Device, one LUN.",
2374 /* fFlags */
2375 PDM_USBREG_HIGHSPEED_CAPABLE | PDM_USBREG_SUPERSPEED_CAPABLE
2376 | PDM_USBREG_SAVED_STATE_SUPPORTED,
2377 /* cMaxInstances */
2378 ~0U,
2379 /* cbInstance */
2380 sizeof(USBMSD),
2381 /* pfnConstruct */
2382 usbMsdConstruct,
2383 /* pfnDestruct */
2384 usbMsdDestruct,
2385 /* pfnVMInitComplete */
2386 NULL,
2387 /* pfnVMPowerOn */
2388 NULL,
2389 /* pfnVMReset */
2390 usbMsdVMReset,
2391 /* pfnVMSuspend */
2392 usbMsdVMSuspend,
2393 /* pfnVMResume */
2394 NULL,
2395 /* pfnVMPowerOff */
2396 usbMsdVMPowerOff,
2397 /* pfnHotPlugged */
2398 NULL,
2399 /* pfnHotUnplugged */
2400 NULL,
2401 /* pfnDriverAttach */
2402 usbMsdDriverAttach,
2403 /* pfnDriverDetach */
2404 usbMsdDriverDetach,
2405 /* pfnQueryInterface */
2406 NULL,
2407 /* pfnUsbReset */
2408 usbMsdUsbReset,
2409 /* pfnUsbGetCachedDescriptors */
2410 usbMsdUsbGetDescriptorCache,
2411 /* pfnUsbSetConfiguration */
2412 usbMsdUsbSetConfiguration,
2413 /* pfnUsbSetInterface */
2414 usbMsdUsbSetInterface,
2415 /* pfnUsbClearHaltedEndpoint */
2416 usbMsdUsbClearHaltedEndpoint,
2417 /* pfnUrbNew */
2418 NULL/*usbMsdUrbNew*/,
2419 /* pfnQueue */
2420 usbMsdQueue,
2421 /* pfnUrbCancel */
2422 usbMsdUrbCancel,
2423 /* pfnUrbReap */
2424 usbMsdUrbReap,
2425 /* pfnWakeup */
2426 usbMsdWakeup,
2427 /* u32TheEnd */
2428 PDM_USBREG_VERSION
2429};
2430
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