VirtualBox

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

Last change on this file since 57444 was 57393, checked in by vboxsync, 9 years ago

DECLCALLBACK

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