VirtualBox

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

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

USB: Added required SS descriptors to emulated MSD.

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