VirtualBox

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

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

Removed unused/misspelled struct member.

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