VirtualBox

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

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

VUSB: Added separate SS EP companion descriptor to VUSBDESCENDPOINTEX since it is mandatory for USB3 and not class specific.

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