VirtualBox

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

Last change on this file since 62956 was 62954, checked in by vboxsync, 8 years ago

usbMsdLoadExec: Should never act on restored data (like allocate memory using a restored size) without first checking the SSM return code! Return immediately on failure, MSC variable initialization tracking doesn't follow flat 'if (RT_SUCCESS(rc))' structure and gets things wrong. Warnings.

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