VirtualBox

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

Last change on this file since 43815 was 43815, checked in by vboxsync, 12 years ago

UsbMsd: Present proper high- vs. full-speed descriptors to guest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.1 KB
Line 
1/* $Id: UsbMsd.cpp 43815 2012-11-06 17:00:49Z vboxsync $ */
2/** @file
3 * UsbMSD - USB Mass Storage Device Emulation.
4 */
5
6/*
7 * Copyright (C) 2007-2010 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/*******************************************************************************
53* Structures and Typedefs *
54*******************************************************************************/
55
56/**
57 * USB MSD Command Block Wrapper or CBW. The command block
58 * itself (CBWCB) contains protocol-specific data (here SCSI).
59 */
60#pragma pack(1)
61typedef struct USBCBW
62{
63 uint32_t dCBWSignature;
64#define USBCBW_SIGNATURE UINT32_C(0x43425355)
65 uint32_t dCBWTag;
66 uint32_t dCBWDataTransferLength;
67 uint8_t bmCBWFlags;
68#define USBCBW_DIR_MASK RT_BIT(7)
69#define USBCBW_DIR_OUT 0
70#define USBCBW_DIR_IN RT_BIT(7)
71 uint8_t bCBWLun;
72 uint8_t bCBWCBLength;
73 uint8_t CBWCB[16];
74} USBCBW;
75#pragma pack()
76AssertCompileSize(USBCBW, 31);
77/** Pointer to a Command Block Wrapper. */
78typedef USBCBW *PUSBCBW;
79/** Pointer to a const Command Block Wrapper. */
80typedef const USBCBW *PCUSBCBW;
81
82/**
83 * USB MSD Command Status Wrapper or CSW.
84 */
85#pragma pack(1)
86typedef struct USBCSW
87{
88 uint32_t dCSWSignature;
89#define USBCSW_SIGNATURE UINT32_C(0x53425355)
90 uint32_t dCSWTag;
91 uint32_t dCSWDataResidue;
92#define USBCSW_STATUS_OK UINT8_C(0)
93#define USBCSW_STATUS_FAILED UINT8_C(1)
94#define USBCSW_STATUS_PHASE_ERROR UINT8_C(2)
95 uint8_t bCSWStatus;
96} USBCSW;
97#pragma pack()
98AssertCompileSize(USBCSW, 13);
99/** Pointer to a Command Status Wrapper. */
100typedef USBCSW *PUSBCSW;
101/** Pointer to a const Command Status Wrapper. */
102typedef const USBCSW *PCUSBCSW;
103
104
105/**
106 * The USB MSD request state.
107 */
108typedef enum USBMSDREQSTATE
109{
110 /** Invalid status. */
111 USBMSDREQSTATE_INVALID = 0,
112 /** Ready to receive a new SCSI command. */
113 USBMSDREQSTATE_READY,
114 /** Waiting for the host to supply data. */
115 USBMSDREQSTATE_DATA_FROM_HOST,
116 /** The SCSI request is being executed by the driver. */
117 USBMSDREQSTATE_EXECUTING,
118 /** Have (more) data for the host. */
119 USBMSDREQSTATE_DATA_TO_HOST,
120 /** Waiting to supply status information to the host. */
121 USBMSDREQSTATE_STATUS,
122 /** Destroy the request upon completion.
123 * This is set when the SCSI request doesn't complete before for the device or
124 * mass storage reset operation times out. USBMSD::pReq will be set to NULL
125 * and the only reference to this request will be with DrvSCSI. */
126 USBMSDREQSTATE_DESTROY_ON_COMPLETION,
127 /** The end of the valid states. */
128 USBMSDREQSTATE_END
129} USBMSDREQSTATE;
130
131
132/**
133 * A pending USB MSD request.
134 */
135typedef struct USBMSDREQ
136{
137 /** The state of the request. */
138 USBMSDREQSTATE enmState;
139 /** The size of the data buffer. */
140 size_t cbBuf;
141 /** Pointer to the data buffer. */
142 uint8_t *pbBuf;
143 /** Current buffer offset. */
144 uint32_t offBuf;
145 /** The current Cbw when we're in the pending state. */
146 USBCBW Cbw;
147 /** The current SCSI request. */
148 PDMSCSIREQUEST ScsiReq;
149 /** The scatter-gather segment used by ScsiReq for describing pbBuf. */
150 RTSGSEG ScsiReqSeg;
151 /** The sense buffer for the current SCSI request. */
152 uint8_t ScsiReqSense[64];
153 /** The status of a completed SCSI request. */
154 int iScsiReqStatus;
155 /** Set if the request structure must be destroyed when the SCSI driver
156 * completes it. This is used to deal with requests that runs while the
157 * device is being reset. */
158 bool fDestoryOnCompletion;
159 /** Pointer to the USB device instance owning it. */
160 PPDMUSBINS pUsbIns;
161} USBMSDREQ;
162/** Pointer to a USB MSD request. */
163typedef USBMSDREQ *PUSBMSDREQ;
164
165
166/**
167 * Endpoint status data.
168 */
169typedef struct USBMSDEP
170{
171 bool fHalted;
172} USBMSDEP;
173/** Pointer to the endpoint status. */
174typedef USBMSDEP *PUSBMSDEP;
175
176
177/**
178 * A URB queue.
179 */
180typedef struct USBMSDURBQUEUE
181{
182 /** The head pointer. */
183 PVUSBURB pHead;
184 /** Where to insert the next entry. */
185 PVUSBURB *ppTail;
186} USBMSDURBQUEUE;
187/** Pointer to a URB queue. */
188typedef USBMSDURBQUEUE *PUSBMSDURBQUEUE;
189/** Pointer to a const URB queue. */
190typedef USBMSDURBQUEUE const *PCUSBMSDURBQUEUE;
191
192
193/**
194 * The USB MSD instance data.
195 */
196typedef struct USBMSD
197{
198 /** Pointer back to the PDM USB Device instance structure. */
199 PPDMUSBINS pUsbIns;
200 /** Critical section protecting the device state. */
201 RTCRITSECT CritSect;
202
203 /** The current configuration.
204 * (0 - default, 1 - the only, i.e configured.) */
205 uint8_t bConfigurationValue;
206#if 0
207 /** The state of the MSD (state machine).*/
208 USBMSDSTATE enmState;
209#endif
210 /** Endpoint 0 is the default control pipe, 1 is the host->dev bulk pipe and 2
211 * is the dev->host one. */
212 USBMSDEP aEps[3];
213 /** The current request. */
214 PUSBMSDREQ pReq;
215
216 /** Pending to-host queue.
217 * The URBs waiting here are pending the completion of the current request and
218 * data or status to become available.
219 */
220 USBMSDURBQUEUE ToHostQueue;
221
222 /** Done queue
223 * The URBs stashed here are waiting to be reaped. */
224 USBMSDURBQUEUE DoneQueue;
225 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
226 * is set. */
227 RTSEMEVENT hEvtDoneQueue;
228 /** Someone is waiting on the done queue. */
229 bool fHaveDoneQueueWaiter;
230
231 /** Whether to signal the reset semaphore when the current request completes. */
232 bool fSignalResetSem;
233 /** Semaphore usbMsdUsbReset waits on when a request is executing at reset
234 * time. Only signalled when fSignalResetSem is set. */
235 RTSEMEVENTMULTI hEvtReset;
236 /** The reset URB.
237 * This is waiting for SCSI request completion before finishing the reset. */
238 PVUSBURB pResetUrb;
239
240 /**
241 * LUN\#0 data.
242 */
243 struct
244 {
245 /** The base interface for LUN\#0. */
246 PDMIBASE IBase;
247 /** The SCSI port interface for LUN\#0 */
248 PDMISCSIPORT IScsiPort;
249
250 /** The base interface for the SCSI driver connected to LUN\#0. */
251 PPDMIBASE pIBase;
252 /** The SCSI connector interface for the SCSI driver connected to LUN\#0. */
253 PPDMISCSICONNECTOR pIScsiConnector;
254 } Lun0;
255
256} USBMSD;
257/** Pointer to the USB MSD instance data. */
258typedef USBMSD *PUSBMSD;
259
260
261/*******************************************************************************
262* Global Variables *
263*******************************************************************************/
264static const PDMUSBDESCCACHESTRING g_aUsbMsdStrings_en_US[] =
265{
266 { USBMSD_STR_ID_MANUFACTURER, "VirtualBox" },
267 { USBMSD_STR_ID_PRODUCT_HD, "USB Harddisk" },
268 { USBMSD_STR_ID_PRODUCT_CDROM, "USB CD-ROM" }
269};
270
271static const PDMUSBDESCCACHELANG g_aUsbMsdLanguages[] =
272{
273 { 0x0409, RT_ELEMENTS(g_aUsbMsdStrings_en_US), g_aUsbMsdStrings_en_US }
274};
275
276static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsFS[2] =
277{
278 {
279 {
280 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
281 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
282 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
283 /* .bmAttributes = */ 2 /* bulk */,
284 /* .wMaxPacketSize = */ 64 /* maximum possible */,
285 /* .bInterval = */ 0 /* not applicable for bulk EP */
286 },
287 /* .pvMore = */ NULL,
288 /* .pvClass = */ NULL,
289 /* .cbClass = */ 0
290 },
291 {
292 {
293 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
294 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
295 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
296 /* .bmAttributes = */ 2 /* bulk */,
297 /* .wMaxPacketSize = */ 64 /* maximum possible */,
298 /* .bInterval = */ 0 /* not applicable for bulk EP */
299 },
300 /* .pvMore = */ NULL,
301 /* .pvClass = */ NULL,
302 /* .cbClass = */ 0
303 }
304};
305
306static const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsHS[2] =
307{
308 {
309 {
310 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
311 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
312 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
313 /* .bmAttributes = */ 2 /* bulk */,
314 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
315 /* .bInterval = */ 0 /* no NAKs */
316 },
317 /* .pvMore = */ NULL,
318 /* .pvClass = */ NULL,
319 /* .cbClass = */ 0
320 },
321 {
322 {
323 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
324 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
325 /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
326 /* .bmAttributes = */ 2 /* bulk */,
327 /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
328 /* .bInterval = */ 0 /* no NAKs */
329 },
330 /* .pvMore = */ NULL,
331 /* .pvClass = */ NULL,
332 /* .cbClass = */ 0
333 }
334};
335
336static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescFS =
337{
338 {
339 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
340 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
341 /* .bInterfaceNumber = */ 0,
342 /* .bAlternateSetting = */ 0,
343 /* .bNumEndpoints = */ 2,
344 /* .bInterfaceClass = */ 8 /* Mass Storage */,
345 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
346 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
347 /* .iInterface = */ 0
348 },
349 /* .pvMore = */ NULL,
350 /* .pvClass = */ NULL,
351 /* .cbClass = */ 0,
352 &g_aUsbMsdEndpointDescsFS[0]
353};
354
355static const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescHS =
356{
357 {
358 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
359 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
360 /* .bInterfaceNumber = */ 0,
361 /* .bAlternateSetting = */ 0,
362 /* .bNumEndpoints = */ 2,
363 /* .bInterfaceClass = */ 8 /* Mass Storage */,
364 /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
365 /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
366 /* .iInterface = */ 0
367 },
368 /* .pvMore = */ NULL,
369 /* .pvClass = */ NULL,
370 /* .cbClass = */ 0,
371 &g_aUsbMsdEndpointDescsHS[0]
372};
373
374static const VUSBINTERFACE g_aUsbMsdInterfacesFS[] =
375{
376 { &g_UsbMsdInterfaceDescFS, /* .cSettings = */ 1 },
377};
378
379static const VUSBINTERFACE g_aUsbMsdInterfacesHS[] =
380{
381 { &g_UsbMsdInterfaceDescHS, /* .cSettings = */ 1 },
382};
383
384static const VUSBDESCCONFIGEX g_UsbMsdConfigDescFS =
385{
386 {
387 /* .bLength = */ sizeof(VUSBDESCCONFIG),
388 /* .bDescriptorType = */ VUSB_DT_CONFIG,
389 /* .wTotalLength = */ 0 /* recalculated on read */,
390 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesFS),
391 /* .bConfigurationValue =*/ 1,
392 /* .iConfiguration = */ 0,
393 /* .bmAttributes = */ RT_BIT(7),
394 /* .MaxPower = */ 50 /* 100mA */
395 },
396 NULL, /* pvMore */
397 &g_aUsbMsdInterfacesFS[0],
398 NULL /* pvOriginal */
399};
400
401static const VUSBDESCCONFIGEX g_UsbMsdConfigDescHS =
402{
403 {
404 /* .bLength = */ sizeof(VUSBDESCCONFIG),
405 /* .bDescriptorType = */ VUSB_DT_CONFIG,
406 /* .wTotalLength = */ 0 /* recalculated on read */,
407 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesHS),
408 /* .bConfigurationValue =*/ 1,
409 /* .iConfiguration = */ 0,
410 /* .bmAttributes = */ RT_BIT(7),
411 /* .MaxPower = */ 50 /* 100mA */
412 },
413 NULL, /* pvMore */
414 &g_aUsbMsdInterfacesHS[0],
415 NULL /* pvOriginal */
416};
417
418static const VUSBDESCDEVICE g_UsbMsdDeviceDesc =
419{
420 /* .bLength = */ sizeof(g_UsbMsdDeviceDesc),
421 /* .bDescriptorType = */ VUSB_DT_DEVICE,
422 /* .bcdUsb = */ 0x200, /* USB 2.0 */
423 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
424 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
425 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
426 /* .bMaxPacketSize0 = */ 64,
427 /* .idVendor = */ VBOX_USB_VENDOR,
428 /* .idProduct = */ USBMSD_PID_HD,
429 /* .bcdDevice = */ 0x0100, /* 1.0 */
430 /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
431 /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
432 /* .iSerialNumber = */ 0,
433 /* .bNumConfigurations = */ 1
434};
435
436static const VUSBDEVICEQUALIFIER g_UsbMsdDeviceQualifier =
437{
438 /* .bLength = */ sizeof(g_UsbMsdDeviceQualifier),
439 /* .bDescriptorType = */ VUSB_DT_DEVICE_QUALIFIER,
440 /* .bcdUsb = */ 0x200, /* USB 2.0 */
441 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
442 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
443 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
444 /* .bMaxPacketSize0 = */ 64,
445 /* .bNumConfigurations = */ 1,
446 /* .bReserved = */ 0
447};
448
449static const PDMUSBDESCCACHE g_UsbMsdDescCacheFS =
450{
451 /* .pDevice = */ &g_UsbMsdDeviceDesc,
452 /* .paConfigs = */ &g_UsbMsdConfigDescFS,
453 /* .paLanguages = */ g_aUsbMsdLanguages,
454 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
455 /* .fUseCachedDescriptors = */ true,
456 /* .fUseCachedStringsDescriptors = */ true
457};
458
459static const PDMUSBDESCCACHE g_UsbMsdDescCacheHS =
460{
461 /* .pDevice = */ &g_UsbMsdDeviceDesc,
462 /* .paConfigs = */ &g_UsbMsdConfigDescHS,
463 /* .paLanguages = */ g_aUsbMsdLanguages,
464 /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
465 /* .fUseCachedDescriptors = */ true,
466 /* .fUseCachedStringsDescriptors = */ true
467};
468
469
470/*******************************************************************************
471* Internal Functions *
472*******************************************************************************/
473static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb);
474
475
476/**
477 * Initializes an URB queue.
478 *
479 * @param pQueue The URB queue.
480 */
481static void usbMsdQueueInit(PUSBMSDURBQUEUE pQueue)
482{
483 pQueue->pHead = NULL;
484 pQueue->ppTail = &pQueue->pHead;
485}
486
487
488
489/**
490 * Inserts an URB at the end of the queue.
491 *
492 * @param pQueue The URB queue.
493 * @param pUrb The URB to insert.
494 */
495DECLINLINE(void) usbMsdQueueAddTail(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
496{
497 pUrb->Dev.pNext = NULL;
498 *pQueue->ppTail = pUrb;
499 pQueue->ppTail = &pUrb->Dev.pNext;
500}
501
502
503/**
504 * Unlinks the head of the queue and returns it.
505 *
506 * @returns The head entry.
507 * @param pQueue The URB queue.
508 */
509DECLINLINE(PVUSBURB) usbMsdQueueRemoveHead(PUSBMSDURBQUEUE pQueue)
510{
511 PVUSBURB pUrb = pQueue->pHead;
512 if (pUrb)
513 {
514 PVUSBURB pNext = pUrb->Dev.pNext;
515 pQueue->pHead = pNext;
516 if (!pNext)
517 pQueue->ppTail = &pQueue->pHead;
518 else
519 pUrb->Dev.pNext = NULL;
520 }
521 return pUrb;
522}
523
524
525/**
526 * Removes an URB from anywhere in the queue.
527 *
528 * @returns true if found, false if not.
529 * @param pQueue The URB queue.
530 * @param pUrb The URB to remove.
531 */
532DECLINLINE(bool) usbMsdQueueRemove(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
533{
534 PVUSBURB pCur = pQueue->pHead;
535 if (pCur == pUrb)
536 pQueue->pHead = pUrb->Dev.pNext;
537 else
538 {
539 while (pCur)
540 {
541 if (pCur->Dev.pNext == pUrb)
542 {
543 pCur->Dev.pNext = pUrb->Dev.pNext;
544 break;
545 }
546 pCur = pCur->Dev.pNext;
547 }
548 if (!pCur)
549 return false;
550 }
551 if (!pUrb->Dev.pNext)
552 pQueue->ppTail = &pQueue->pHead;
553 return true;
554}
555
556
557/**
558 * Checks if the queue is empty or not.
559 *
560 * @returns true if it is, false if it isn't.
561 * @param pQueue The URB queue.
562 */
563DECLINLINE(bool) usbMsdQueueIsEmpty(PCUSBMSDURBQUEUE pQueue)
564{
565 return pQueue->pHead == NULL;
566}
567
568
569/**
570 * Links an URB into the done queue.
571 *
572 * @param pThis The MSD instance.
573 * @param pUrb The URB.
574 */
575static void usbMsdLinkDone(PUSBMSD pThis, PVUSBURB pUrb)
576{
577 usbMsdQueueAddTail(&pThis->DoneQueue, pUrb);
578
579 if (pThis->fHaveDoneQueueWaiter)
580 {
581 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
582 AssertRC(rc);
583 }
584}
585
586
587
588
589/**
590 * Allocates a new request and does basic init.
591 *
592 * @returns Pointer to the new request. NULL if we're out of memory.
593 * @param pUsbIns The instance allocating it.
594 */
595static PUSBMSDREQ usbMsdReqAlloc(PPDMUSBINS pUsbIns)
596{
597 PUSBMSDREQ pReq = (PUSBMSDREQ)PDMUsbHlpMMHeapAllocZ(pUsbIns, sizeof(*pReq));
598 if (pReq)
599 {
600 pReq->enmState = USBMSDREQSTATE_READY;
601 pReq->iScsiReqStatus = -1;
602 pReq->pUsbIns = pUsbIns;
603 }
604 else
605 LogRel(("usbMsdReqAlloc: Out of memory\n"));
606 return pReq;
607}
608
609
610/**
611 * Frees a request.
612 *
613 * @param pReq The request.
614 */
615static void usbMsdReqFree(PUSBMSDREQ pReq)
616{
617 /*
618 * Check the input.
619 */
620 AssertReturnVoid( pReq->enmState > USBMSDREQSTATE_INVALID
621 && pReq->enmState != USBMSDREQSTATE_EXECUTING
622 && pReq->enmState < USBMSDREQSTATE_END);
623 PPDMUSBINS pUsbIns = pReq->pUsbIns;
624 AssertPtrReturnVoid(pUsbIns);
625 AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
626
627 /*
628 * Invalidate it and free the associated resources.
629 */
630 pReq->enmState = USBMSDREQSTATE_INVALID;
631 pReq->cbBuf = 0;
632 pReq->offBuf = 0;
633 pReq->ScsiReq.pbCDB = NULL;
634 pReq->ScsiReq.paScatterGatherHead = NULL;
635 pReq->ScsiReq.pbSenseBuffer = NULL;
636 pReq->ScsiReq.pvUser = NULL;
637 pReq->ScsiReqSeg.cbSeg = 0;
638 pReq->ScsiReqSeg.pvSeg = NULL;
639
640 if (pReq->pbBuf)
641 {
642 PDMUsbHlpMMHeapFree(pUsbIns, pReq->pbBuf);
643 pReq->pbBuf = NULL;
644 }
645
646 PDMUsbHlpMMHeapFree(pUsbIns, pReq);
647}
648
649
650/**
651 * Prepares a request for execution or data buffering.
652 *
653 * @param pReq The request.
654 * @param pCbw The SCSI command block wrapper.
655 */
656static void usbMsdReqPrepare(PUSBMSDREQ pReq, PCUSBCBW pCbw)
657{
658 /* Copy the CBW */
659 size_t cbCopy = RT_OFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]);
660 memcpy(&pReq->Cbw, pCbw, cbCopy);
661 memset((uint8_t *)&pReq->Cbw + cbCopy, 0, sizeof(pReq->Cbw) - cbCopy);
662
663 /* Setup the SCSI request. */
664 pReq->ScsiReq.uLogicalUnit = pReq->Cbw.bCBWLun;
665 pReq->ScsiReq.uDataDirection = (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
666 ? PDMSCSIREQUESTTXDIR_TO_DEVICE
667 : PDMSCSIREQUESTTXDIR_FROM_DEVICE;
668 pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
669
670 pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
671 pReq->offBuf = 0;
672 pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
673 pReq->ScsiReqSeg.cbSeg = pReq->Cbw.dCBWDataTransferLength;
674 pReq->ScsiReq.cbScatterGather = pReq->Cbw.dCBWDataTransferLength;
675 pReq->ScsiReq.cScatterGatherEntries = 1;
676 pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
677 pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
678 pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
679 pReq->ScsiReq.pvUser = NULL;
680 RT_ZERO(pReq->ScsiReqSense);
681 pReq->iScsiReqStatus = -1;
682}
683
684
685/**
686 * Makes sure that there is sufficient buffer space available.
687 *
688 * @returns Success indicator (true/false)
689 * @param pReq
690 * @param cbBuf The required buffer space.
691 */
692static int usbMsdReqEnsureBuffer(PUSBMSDREQ pReq, size_t cbBuf)
693{
694 if (RT_LIKELY(pReq->cbBuf >= cbBuf))
695 RT_BZERO(pReq->pbBuf, cbBuf);
696 else
697 {
698 PDMUsbHlpMMHeapFree(pReq->pUsbIns, pReq->pbBuf);
699 pReq->cbBuf = 0;
700
701 cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
702 pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pReq->pUsbIns, cbBuf);
703 if (!pReq->pbBuf)
704 return false;
705
706 pReq->cbBuf = cbBuf;
707 }
708 return true;
709}
710
711
712/**
713 * Completes the URB with a stalled state, halting the pipe.
714 */
715static int usbMsdCompleteStall(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb, const char *pszWhy)
716{
717 Log(("usbMsdCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
718
719 pUrb->enmStatus = VUSBSTATUS_STALL;
720
721 /** @todo figure out if the stall is global or pipe-specific or both. */
722 if (pEp)
723 pEp->fHalted = true;
724 else
725 {
726 pThis->aEps[1].fHalted = true;
727 pThis->aEps[2].fHalted = true;
728 }
729
730 usbMsdLinkDone(pThis, pUrb);
731 return VINF_SUCCESS;
732}
733
734
735/**
736 * Completes the URB with a OK state.
737 */
738static int usbMsdCompleteOk(PUSBMSD pThis, PVUSBURB pUrb, size_t cbData)
739{
740 Log(("usbMsdCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
741
742 pUrb->enmStatus = VUSBSTATUS_OK;
743 pUrb->cbData = (uint32_t)cbData;
744
745 usbMsdLinkDone(pThis, pUrb);
746 return VINF_SUCCESS;
747}
748
749
750/**
751 * Reset worker for usbMsdUsbReset, usbMsdUsbSetConfiguration and
752 * usbMsdUrbHandleDefaultPipe.
753 *
754 * @returns VBox status code.
755 * @param pThis The MSD instance.
756 * @param pUrb Set when usbMsdUrbHandleDefaultPipe is the
757 * caller.
758 * @param fSetConfig Set when usbMsdUsbSetConfiguration is the
759 * caller.
760 */
761static int usbMsdResetWorker(PUSBMSD pThis, PVUSBURB pUrb, bool fSetConfig)
762{
763 /*
764 * Wait for the any command currently executing to complete before
765 * resetting. (We cannot cancel its execution.) How we do this depends
766 * on the reset method.
767 */
768 PUSBMSDREQ pReq = pThis->pReq;
769 if ( pReq
770 && pReq->enmState == USBMSDREQSTATE_EXECUTING)
771 {
772 /* Don't try to deal with the set config variant nor multiple build-only
773 mass storage resets. */
774 if (pThis->pResetUrb && (pUrb || fSetConfig))
775 {
776 Log(("usbMsdResetWorker: pResetUrb is already %p:%s - stalling\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
777 return usbMsdCompleteStall(pThis, NULL, pUrb, "pResetUrb");
778 }
779
780 /* Bulk-Only Mass Storage Reset: Complete the reset on request completion. */
781 if (pUrb)
782 {
783 pThis->pResetUrb = pUrb;
784 Log(("usbMsdResetWorker: Setting pResetUrb to %p:%s\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
785 return VINF_SUCCESS;
786 }
787
788 /* Device reset: Wait for up to 10 ms. If it doesn't work, ditch
789 whoe the request structure. We'll allocate a new one when needed. */
790 Log(("usbMsdResetWorker: Waiting for completion...\n"));
791 Assert(!pThis->fSignalResetSem);
792 pThis->fSignalResetSem = true;
793 RTSemEventMultiReset(pThis->hEvtReset);
794 RTCritSectLeave(&pThis->CritSect);
795
796 int rc = RTSemEventMultiWait(pThis->hEvtReset, 10 /*ms*/);
797
798 RTCritSectEnter(&pThis->CritSect);
799 pThis->fSignalResetSem = false;
800 if ( RT_FAILURE(rc)
801 || pReq->enmState == USBMSDREQSTATE_EXECUTING)
802 {
803 Log(("usbMsdResetWorker: Didn't complete, ditching the current request (%p)!\n", pReq));
804 Assert(pReq == pThis->pReq);
805 pReq->enmState = USBMSDREQSTATE_DESTROY_ON_COMPLETION;
806 pThis->pReq = NULL;
807 pReq = NULL;
808 }
809 }
810
811 /*
812 * Reset the request and device state.
813 */
814 if (pReq)
815 {
816 pReq->enmState = USBMSDREQSTATE_READY;
817 pReq->iScsiReqStatus = -1;
818 }
819
820 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
821 pThis->aEps[i].fHalted = false;
822
823 if (!pUrb && !fSetConfig) /* (only device reset) */
824 pThis->bConfigurationValue = 0; /* default */
825
826 /*
827 * Ditch all pending URBs.
828 */
829 PVUSBURB pCurUrb;
830 while ((pCurUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
831 {
832 pCurUrb->enmStatus = VUSBSTATUS_CRC;
833 usbMsdLinkDone(pThis, pCurUrb);
834 }
835
836 pCurUrb = pThis->pResetUrb;
837 if (pCurUrb)
838 {
839 pThis->pResetUrb = NULL;
840 pCurUrb->enmStatus = VUSBSTATUS_CRC;
841 usbMsdLinkDone(pThis, pCurUrb);
842 }
843
844 if (pUrb)
845 return usbMsdCompleteOk(pThis, pUrb, 0);
846 return VINF_SUCCESS;
847}
848
849
850/**
851 * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted}
852 */
853static DECLCALLBACK(int) usbMsdLun0ScsiRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
854 int rcCompletion, bool fRedo, int rcReq)
855{
856 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
857 PUSBMSDREQ pReq = RT_FROM_MEMBER(pSCSIRequest, USBMSDREQ, ScsiReq);
858
859 Log(("usbMsdLun0ScsiRequestCompleted: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, rcCompletion));
860 RTCritSectEnter(&pThis->CritSect);
861
862 if (pReq->enmState != USBMSDREQSTATE_DESTROY_ON_COMPLETION)
863 {
864 Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
865 Assert(pThis->pReq == pReq);
866 pReq->iScsiReqStatus = rcCompletion;
867
868 /*
869 * Advance the state machine. The state machine is not affected by
870 * SCSI errors.
871 */
872 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
873 {
874 pReq->enmState = USBMSDREQSTATE_STATUS;
875 Log(("usbMsdLun0ScsiRequestCompleted: Entering STATUS\n"));
876 }
877 else
878 {
879 pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
880 Log(("usbMsdLun0ScsiRequestCompleted: Entering DATA_TO_HOST\n"));
881 }
882
883 /*
884 * Deal with pending to-host URBs.
885 */
886 for (;;)
887 {
888 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue);
889 if (!pUrb)
890 break;
891
892 /* Process it the normal way. */
893 usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
894 }
895 }
896 else
897 {
898 Log(("usbMsdLun0ScsiRequestCompleted: freeing %p\n", pReq));
899 usbMsdReqFree(pReq);
900 }
901
902 if (pThis->fSignalResetSem)
903 RTSemEventMultiSignal(pThis->hEvtReset);
904
905 if (pThis->pResetUrb)
906 {
907 pThis->pResetUrb = NULL;
908 usbMsdResetWorker(pThis, pThis->pResetUrb, false /*fSetConfig*/);
909 }
910
911 RTCritSectLeave(&pThis->CritSect);
912 return VINF_SUCCESS;
913}
914
915
916/**
917 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
918 */
919static DECLCALLBACK(void *) usbMsdLun0QueryInterface(PPDMIBASE pInterface, const char *pszIID)
920{
921 PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
922 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
923 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pThis->Lun0.IScsiPort);
924 return NULL;
925}
926
927
928/**
929 * @copydoc PDMUSBREG::pfnUrbReap
930 */
931static DECLCALLBACK(PVUSBURB) usbMsdUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
932{
933 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
934 LogFlow(("usbMsdUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
935
936 RTCritSectEnter(&pThis->CritSect);
937
938 PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
939 if (!pUrb && cMillies)
940 {
941 /* Wait */
942 pThis->fHaveDoneQueueWaiter = true;
943 RTCritSectLeave(&pThis->CritSect);
944
945 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
946
947 RTCritSectEnter(&pThis->CritSect);
948 pThis->fHaveDoneQueueWaiter = false;
949
950 pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
951 }
952
953 RTCritSectLeave(&pThis->CritSect);
954
955 if (pUrb)
956 Log(("usbMsdUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
957 return pUrb;
958}
959
960
961/**
962 * @copydoc PDMUSBREG::pfnUrbCancel
963 */
964static DECLCALLBACK(int) usbMsdUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
965{
966 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
967 LogFlow(("usbMsdUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
968 RTCritSectEnter(&pThis->CritSect);
969
970 /*
971 * Remove the URB from the to-host queue and move it onto the done queue.
972 */
973 if (usbMsdQueueRemove(&pThis->ToHostQueue, pUrb))
974 usbMsdLinkDone(pThis, pUrb);
975
976 RTCritSectLeave(&pThis->CritSect);
977 return VINF_SUCCESS;
978}
979
980
981/**
982 * Fails an illegal SCSI request.
983 *
984 * @returns VBox status code.
985 * @param pThis The MSD instance data.
986 * @param pReq The MSD request.
987 * @param bAsc The ASC for the SCSI_SENSE_ILLEGAL_REQUEST.
988 * @param bAscq The ASC qualifier.
989 * @param pszWhy For logging why.
990 */
991static int usbMsdScsiIllegalRequest(PUSBMSD pThis, PUSBMSDREQ pReq, uint8_t bAsc, uint8_t bAscq, const char *pszWhy)
992{
993 Log(("usbMsdScsiIllegalRequest: bAsc=%#x bAscq=%#x %s\n", bAsc, bAscq, pszWhy));
994
995 RT_ZERO(pReq->ScsiReqSense);
996 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
997 pReq->ScsiReqSense[2] = SCSI_SENSE_ILLEGAL_REQUEST;
998 pReq->ScsiReqSense[7] = 10;
999 pReq->ScsiReqSense[12] = SCSI_ASC_INVALID_MESSAGE;
1000 pReq->ScsiReqSense[13] = 0; /* Should be ASCQ but it has the same value for success. */
1001
1002 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
1003 return VINF_SUCCESS;
1004}
1005
1006
1007/**
1008 * The SCSI driver doesn't handle SCSI_REQUEST_SENSE but instead
1009 * returns the sense info with the request.
1010 *
1011 */
1012static int usbMsdHandleScsiReqestSense(PUSBMSD pThis, PUSBMSDREQ pReq, PCUSBCBW pCbw)
1013{
1014 Log(("usbMsdHandleScsiReqestSense: Entering EXECUTING (dCBWTag=%#x).\n", pReq->Cbw.dCBWTag));
1015 Assert(pReq == pThis->pReq);
1016 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1017
1018 /* validation */
1019 if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
1020 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
1021 if (pCbw->bCBWCBLength < 6)
1022 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
1023 if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
1024 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "lun");
1025 if (pCbw->bCBWLun != 0)
1026 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
1027 if (pCbw->CBWCB[4] < 6)
1028 return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
1029
1030 /* If the previous command succeeded successfully, whip up some sense data. */
1031 if ( pReq->iScsiReqStatus == SCSI_STATUS_OK
1032 && pReq->ScsiReqSense[0] == 0)
1033 {
1034 RT_ZERO(pReq->ScsiReqSense);
1035#if 0 /** @todo something upsets linux about this stuff. Needs investigation. */
1036 pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1037 pReq->ScsiReqSense[0] = SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
1038 pReq->ScsiReqSense[2] = SCSI_SENSE_NONE;
1039 pReq->ScsiReqSense[7] = 10;
1040 pReq->ScsiReqSense[12] = SCSI_ASC_NONE;
1041 pReq->ScsiReqSense[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
1042#endif
1043 }
1044
1045 /* Copy the data into the result buffer. */
1046 size_t cbCopy = RT_MIN(pCbw->dCBWDataTransferLength, sizeof(pReq->ScsiReqSense));
1047 Log(("usbMsd: SCSI_REQUEST_SENSE - CBWCB[4]=%#x iOldState=%d, %u bytes, raw: %.*Rhxs\n",
1048 pCbw->CBWCB[4], pReq->iScsiReqStatus, pCbw->dCBWDataTransferLength, RT_MAX(1, cbCopy), pReq->ScsiReqSense));
1049 memcpy(pReq->pbBuf, &pReq->ScsiReqSense[0], cbCopy);
1050
1051 usbMsdReqPrepare(pReq, pCbw);
1052
1053 /* Do normal completion. */
1054 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1055 return VINF_SUCCESS;
1056}
1057
1058
1059/**
1060 * Wrapper around PDMISCSICONNECTOR::pfnSCSIRequestSend that deals with
1061 * SCSI_REQUEST_SENSE.
1062 *
1063 * @returns VBox status code.
1064 * @param pThis The MSD instance data.
1065 * @param pReq The MSD request.
1066 * @param pszCaller Where we're called from.
1067 */
1068static int usbMsdSubmitScsiCommand(PUSBMSD pThis, PUSBMSDREQ pReq, const char *pszCaller)
1069{
1070 Log(("%s: Entering EXECUTING (dCBWTag=%#x).\n", pszCaller, pReq->Cbw.dCBWTag));
1071 Assert(pReq == pThis->pReq);
1072 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1073
1074 switch (pReq->ScsiReq.pbCDB[0])
1075 {
1076 case SCSI_REQUEST_SENSE:
1077 {
1078 }
1079
1080 default:
1081 return pThis->Lun0.pIScsiConnector->pfnSCSIRequestSend(pThis->Lun0.pIScsiConnector, &pReq->ScsiReq);
1082 }
1083}
1084
1085/**
1086 * Validates a SCSI request before passing it down to the SCSI driver.
1087 *
1088 * @returns true / false. The request will be completed on failure.
1089 * @param pThis The MSD instance data.
1090 * @param pCbw The USB command block wrapper.
1091 * @param pUrb The URB.
1092 */
1093static bool usbMsdIsValidCommand(PUSBMSD pThis, PCUSBCBW pCbw, PVUSBURB pUrb)
1094{
1095 switch (pCbw->CBWCB[0])
1096 {
1097 case SCSI_REQUEST_SENSE:
1098 /** @todo validate this. */
1099 return true;
1100
1101 default:
1102 return true;
1103 }
1104}
1105
1106
1107/**
1108 * Handle requests sent to the outbound (to device) bulk pipe.
1109 */
1110static int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1111{
1112 /*
1113 * Stall the request if the pipe is halted.
1114 */
1115 if (RT_UNLIKELY(pEp->fHalted))
1116 return usbMsdCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1117
1118 /*
1119 * Deal with the URB according to the current state.
1120 */
1121 PUSBMSDREQ pReq = pThis->pReq;
1122 USBMSDREQSTATE enmState = pReq ? pReq->enmState : USBMSDREQSTATE_READY;
1123 switch (enmState)
1124 {
1125 case USBMSDREQSTATE_STATUS:
1126 LogFlow(("usbMsdHandleBulkHostToDev: Skipping pending status.\n"));
1127 pReq->enmState = USBMSDREQSTATE_READY;
1128 /* fall thru */
1129
1130 /*
1131 * We're ready to receive a command. Start off by validating the
1132 * incoming request.
1133 */
1134 case USBMSDREQSTATE_READY:
1135 {
1136 PCUSBCBW pCbw = (PUSBCBW)&pUrb->abData[0];
1137 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[1]))
1138 {
1139 Log(("usbMsd: Bad CBW: cbData=%#x < min=%#x\n", pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[1]) ));
1140 return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
1141 }
1142 if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
1143 {
1144 Log(("usbMsd: CBW: Invalid dCBWSignature value: %#x\n", pCbw->dCBWSignature));
1145 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1146 }
1147 Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x cbData=%#x fShortNotOk=%RTbool\n",
1148 pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
1149 if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
1150 {
1151 Log(("usbMsd: CBW: Bad bmCBWFlags value: %#x\n", pCbw->bmCBWFlags));
1152 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1153
1154 }
1155 if (pCbw->bCBWLun != 0)
1156 {
1157 Log(("usbMsd: CBW: Bad bCBWLun value: %#x\n", pCbw->bCBWLun));
1158 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1159 }
1160 if (pCbw->bCBWCBLength == 0)
1161 {
1162 Log(("usbMsd: CBW: Bad bCBWCBLength value: %#x\n", pCbw->bCBWCBLength));
1163 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1164 }
1165 if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]))
1166 {
1167 Log(("usbMsd: CBW: Mismatching cbData and bCBWCBLength values: %#x vs. %#x (%#x)\n",
1168 pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]), pCbw->bCBWCBLength));
1169 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
1170 }
1171 if (pCbw->dCBWDataTransferLength > _1M)
1172 {
1173 Log(("usbMsd: CBW: dCBWDataTransferLength is too large: %#x (%u)\n",
1174 pCbw->dCBWDataTransferLength, pCbw->dCBWDataTransferLength));
1175 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too big transfer");
1176 }
1177
1178 if (!usbMsdIsValidCommand(pThis, pCbw, pUrb))
1179 return VINF_SUCCESS;
1180
1181 /*
1182 * Make sure we've got a request and a sufficient buffer space.
1183 *
1184 * Note! This will make sure the buffer is ZERO as well, thus
1185 * saving us the trouble of clearing the output buffer on
1186 * failure later.
1187 */
1188 if (!pReq)
1189 {
1190 pReq = usbMsdReqAlloc(pThis->pUsbIns);
1191 if (!pReq)
1192 return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
1193 pThis->pReq = pReq;
1194 }
1195 if (!usbMsdReqEnsureBuffer(pReq, pCbw->dCBWDataTransferLength))
1196 return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
1197
1198 /*
1199 * Special case REQUEST SENSE requests, usbMsdReqPrepare will
1200 * trash the sense data otherwise.
1201 */
1202 if (pCbw->CBWCB[0] == SCSI_REQUEST_SENSE)
1203 usbMsdHandleScsiReqestSense(pThis, pReq, pCbw);
1204 else
1205 {
1206 /*
1207 * Prepare the request. Kick it off right away if possible.
1208 */
1209 usbMsdReqPrepare(pReq, pCbw);
1210
1211 if ( pReq->Cbw.dCBWDataTransferLength == 0
1212 || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
1213 {
1214 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1215 if (RT_FAILURE(rc))
1216 {
1217 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1218 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
1219 }
1220 }
1221 else
1222 {
1223 Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
1224 pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
1225 }
1226 }
1227
1228 return usbMsdCompleteOk(pThis, pUrb, pUrb->cbData);
1229 }
1230
1231 /*
1232 * Stuff the data into the buffer.
1233 */
1234 case USBMSDREQSTATE_DATA_FROM_HOST:
1235 {
1236 uint32_t cbData = pUrb->cbData;
1237 uint32_t cbLeft = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1238 if (cbData > cbLeft)
1239 {
1240 Log(("usbMsd: Too much data: cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1241 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbLeft));
1242 return usbMsdCompleteStall(pThis, NULL, pUrb, "Too much data");
1243 }
1244 memcpy(&pReq->pbBuf[pReq->offBuf], &pUrb->abData[0], cbData);
1245 pReq->offBuf += cbData;
1246
1247 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1248 {
1249 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
1250 if (RT_FAILURE(rc))
1251 {
1252 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1253 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #2");
1254 }
1255 }
1256LogRel(("DATA_FROM_HOST: %d bytes\n", cbData));
1257 return usbMsdCompleteOk(pThis, pUrb, cbData);
1258 }
1259
1260 /*
1261 * Bad state, stall.
1262 */
1263 case USBMSDREQSTATE_DATA_TO_HOST:
1264 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: DATA_TO_HOST");
1265
1266 case USBMSDREQSTATE_EXECUTING:
1267 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: EXECUTING");
1268
1269 default:
1270 AssertMsgFailed(("enmState=%d\n", enmState));
1271 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state (H2D)");
1272 }
1273}
1274
1275
1276/**
1277 * Handle requests sent to the inbound (to host) bulk pipe.
1278 */
1279static int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1280{
1281 /*
1282 * Stall the request if the pipe is halted OR if there is no
1283 * pending request yet.
1284 */
1285 PUSBMSDREQ pReq = pThis->pReq;
1286 if (RT_UNLIKELY(pEp->fHalted || !pReq))
1287 return usbMsdCompleteStall(pThis, NULL, pUrb, pEp->fHalted ? "Halted pipe" : "No request");
1288
1289 /*
1290 * Deal with the URB according to the state.
1291 */
1292 switch (pReq->enmState)
1293 {
1294 /*
1295 * We've data left to transfer to the host.
1296 */
1297 case USBMSDREQSTATE_DATA_TO_HOST:
1298 {
1299 uint32_t cbData = pUrb->cbData;
1300 uint32_t cbCopy = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
1301 if (cbData <= cbCopy)
1302 cbCopy = cbData;
1303 else if (pUrb->fShortNotOk)
1304 {
1305 Log(("usbMsd: Requested more data that we've got; cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
1306 cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbCopy));
1307 return usbMsdCompleteStall(pThis, NULL, pUrb, "Data underrun");
1308 }
1309 memcpy(&pUrb->abData[0], &pReq->pbBuf[pReq->offBuf], cbCopy);
1310 pReq->offBuf += cbCopy;
1311
1312 if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
1313 {
1314 Log(("usbMsdHandleBulkDevToHost: Entering STATUS\n"));
1315 pReq->enmState = USBMSDREQSTATE_STATUS;
1316 }
1317LogRel(("DATA_TO_HOST: %d bytes\n", cbCopy));
1318 return usbMsdCompleteOk(pThis, pUrb, cbCopy);
1319 }
1320
1321 /*
1322 * Status transfer.
1323 */
1324 case USBMSDREQSTATE_STATUS:
1325 {
1326 if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
1327 {
1328 Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
1329 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1330 }
1331
1332 /* Enter a CSW into the URB data buffer. */
1333 PUSBCSW pCsw = (PUSBCSW)&pUrb->abData[0];
1334 pCsw->dCSWSignature = USBCSW_SIGNATURE;
1335 pCsw->dCSWTag = pReq->Cbw.dCBWTag;
1336 pCsw->bCSWStatus = pReq->iScsiReqStatus == SCSI_STATUS_OK
1337 ? USBCSW_STATUS_OK
1338 : pReq->iScsiReqStatus >= 0
1339 ? USBCSW_STATUS_FAILED
1340 : USBCSW_STATUS_PHASE_ERROR;
1341 /** @todo the following is not always accurate; VSCSI needs
1342 * to implement residual counts properly! */
1343 if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
1344 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1345 ? pReq->Cbw.dCBWDataTransferLength - pReq->ScsiReq.cbScatterGather
1346 : pReq->Cbw.dCBWDataTransferLength;
1347 else
1348 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
1349 ? 0
1350 : pReq->ScsiReq.cbScatterGather;
1351 Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
1352 pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
1353
1354 Log(("usbMsdHandleBulkDevToHost: Entering READY\n"));
1355 pReq->enmState = USBMSDREQSTATE_READY;
1356 return usbMsdCompleteOk(pThis, pUrb, sizeof(*pCsw));
1357 }
1358
1359 /*
1360 * Status request before we've received all (or even any) data.
1361 * Linux 2.4.31 does this sometimes. The recommended behavior is to
1362 * to accept the current data amount and execute the request. (The
1363 * alternative behavior is to stall.)
1364 */
1365 case USBMSDREQSTATE_DATA_FROM_HOST:
1366 {
1367 if (pUrb->cbData != sizeof(USBCSW))
1368 {
1369 Log(("usbMsdHandleBulkDevToHost: DATA_FROM_HOST; cbData=%#x -> stall\n", pUrb->cbData));
1370 return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
1371 }
1372
1373 /* Adjust the request and kick it off. Special case the no-data
1374 case since the SCSI driver doesn't like that. */
1375 pReq->ScsiReq.cbScatterGather = pReq->offBuf;
1376 pReq->ScsiReqSeg.cbSeg = pReq->offBuf;
1377 if (!pReq->offBuf)
1378 {
1379 Log(("usbMsdHandleBulkDevToHost: Entering EXECUTING (offBuf=0x0).\n"));
1380 pReq->enmState = USBMSDREQSTATE_EXECUTING;
1381
1382 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1383 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1384
1385 usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
1386 return VINF_SUCCESS;
1387 }
1388
1389 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
1390 if (RT_FAILURE(rc))
1391 {
1392 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
1393 return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #3");
1394 }
1395
1396 /* fall thru */
1397 }
1398
1399 /*
1400 * The SCSI command is still pending, queue the URB awaiting its
1401 * completion.
1402 */
1403 case USBMSDREQSTATE_EXECUTING:
1404 usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
1405 LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
1406 return VINF_SUCCESS;
1407
1408 /*
1409 * Bad states, stall.
1410 */
1411 case USBMSDREQSTATE_READY:
1412 Log(("usbMsdHandleBulkDevToHost: enmState=READ (cbData=%#x)\n", pReq->enmState, pUrb->cbData));
1413 return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state D2H: READY");
1414
1415 default:
1416 Log(("usbMsdHandleBulkDevToHost: enmState=%d cbData=%#x\n", pReq->enmState, pUrb->cbData));
1417 return usbMsdCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1418 }
1419}
1420
1421
1422/**
1423 * Handles request send to the default control pipe.
1424 */
1425static int usbMsdHandleDefaultPipe(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
1426{
1427 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1428 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1429
1430 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1431 {
1432 switch (pSetup->bRequest)
1433 {
1434 case VUSB_REQ_GET_DESCRIPTOR:
1435 {
1436 if (pSetup->bmRequestType != (VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST))
1437 {
1438 Log(("usbMsd: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
1439 return usbMsdCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1440 }
1441
1442 switch (pSetup->wValue >> 8)
1443 {
1444 uint32_t cbCopy;
1445
1446 case VUSB_DT_STRING:
1447 Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1448 break;
1449 case VUSB_DT_DEVICE_QUALIFIER:
1450 Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1451 /* Returned data is written after the setup message. */
1452 cbCopy = pUrb->cbData - sizeof(*pSetup);
1453 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
1454 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
1455 return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1456 default:
1457 Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1458 break;
1459 }
1460 break;
1461 }
1462
1463 case VUSB_REQ_CLEAR_FEATURE:
1464 break;
1465 }
1466
1467 /** @todo implement this. */
1468 Log(("usbMsd: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1469 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1470
1471 usbMsdCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1472 }
1473 /* 3.1 Bulk-Only Mass Storage Reset */
1474 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1475 && pSetup->bRequest == 0xff
1476 && !pSetup->wValue
1477 && !pSetup->wLength
1478 && pSetup->wIndex == 0)
1479 {
1480 Log(("usbMsdHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1481 return usbMsdResetWorker(pThis, pUrb, false /*fSetConfig*/);
1482 }
1483 /* 3.2 Get Max LUN, may stall if we like (but we don't). */
1484 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE | VUSB_DIR_TO_HOST)
1485 && pSetup->bRequest == 0xfe
1486 && !pSetup->wValue
1487 && pSetup->wLength == 1
1488 && pSetup->wIndex == 0)
1489 {
1490 *(uint8_t *)(pSetup + 1) = 0; /* max lun is 0 */
1491 usbMsdCompleteOk(pThis, pUrb, 1);
1492 }
1493 else
1494 {
1495 Log(("usbMsd: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1496 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1497 return usbMsdCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1498 }
1499
1500 return VINF_SUCCESS;
1501}
1502
1503
1504/**
1505 * @copydoc PDMUSBREG::pfnQueue
1506 */
1507static DECLCALLBACK(int) usbMsdQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1508{
1509 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1510 LogFlow(("usbMsdQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
1511 RTCritSectEnter(&pThis->CritSect);
1512
1513 /*
1514 * Parse on a per end-point basis.
1515 */
1516 int rc;
1517 switch (pUrb->EndPt)
1518 {
1519 case 0:
1520 rc = usbMsdHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1521 break;
1522
1523 case 0x81:
1524 AssertFailed();
1525 case 0x01:
1526 rc = usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
1527 break;
1528
1529 case 0x02:
1530 rc = usbMsdHandleBulkHostToDev(pThis, &pThis->aEps[2], pUrb);
1531 break;
1532
1533 default:
1534 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1535 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1536 break;
1537 }
1538
1539 RTCritSectLeave(&pThis->CritSect);
1540 return rc;
1541}
1542
1543
1544/**
1545 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1546 */
1547static DECLCALLBACK(int) usbMsdUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1548{
1549 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1550 LogFlow(("usbMsdUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
1551
1552 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1553 {
1554 RTCritSectEnter(&pThis->CritSect);
1555 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1556 RTCritSectLeave(&pThis->CritSect);
1557 }
1558
1559 return VINF_SUCCESS;
1560}
1561
1562
1563/**
1564 * @copydoc PDMUSBREG::pfnUsbSetInterface
1565 */
1566static DECLCALLBACK(int) usbMsdUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1567{
1568 LogFlow(("usbMsdUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1569 Assert(bAlternateSetting == 0);
1570 return VINF_SUCCESS;
1571}
1572
1573
1574/**
1575 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1576 */
1577static DECLCALLBACK(int) usbMsdUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1578 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1579{
1580 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1581 LogFlow(("usbMsdUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
1582 Assert(bConfigurationValue == 1);
1583 RTCritSectEnter(&pThis->CritSect);
1584
1585 /*
1586 * If the same config is applied more than once, it's a kind of reset.
1587 */
1588 if (pThis->bConfigurationValue == bConfigurationValue)
1589 usbMsdResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1590 pThis->bConfigurationValue = bConfigurationValue;
1591
1592 RTCritSectLeave(&pThis->CritSect);
1593 return VINF_SUCCESS;
1594}
1595
1596
1597/**
1598 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1599 */
1600static DECLCALLBACK(PCPDMUSBDESCCACHE) usbMsdUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1601{
1602 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1603 LogFlow(("usbMsdUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1604 if (pThis->pUsbIns->iUsbHubVersion & VUSB_STDVER_20)
1605 return &g_UsbMsdDescCacheHS;
1606 else
1607 return &g_UsbMsdDescCacheFS;
1608}
1609
1610
1611/**
1612 * @copydoc PDMUSBREG::pfnUsbReset
1613 */
1614static DECLCALLBACK(int) usbMsdUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1615{
1616 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1617 LogFlow(("usbMsdUsbReset/#%u:\n", pUsbIns->iInstance));
1618 RTCritSectEnter(&pThis->CritSect);
1619
1620 int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
1621
1622 RTCritSectLeave(&pThis->CritSect);
1623 return rc;
1624}
1625
1626
1627/**
1628 * @copydoc PDMUSBREG::pfnDestruct
1629 */
1630static void usbMsdDestruct(PPDMUSBINS pUsbIns)
1631{
1632 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1633 LogFlow(("usbMsdDestruct/#%u:\n", pUsbIns->iInstance));
1634
1635 if (RTCritSectIsInitialized(&pThis->CritSect))
1636 {
1637 RTCritSectEnter(&pThis->CritSect);
1638 RTCritSectLeave(&pThis->CritSect);
1639 RTCritSectDelete(&pThis->CritSect);
1640 }
1641
1642 if (pThis->pReq)
1643 {
1644 usbMsdReqFree(pThis->pReq);
1645 pThis->pReq = NULL;
1646 }
1647
1648 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1649 {
1650 RTSemEventDestroy(pThis->hEvtDoneQueue);
1651 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1652 }
1653
1654 if (pThis->hEvtReset != NIL_RTSEMEVENTMULTI)
1655 {
1656 RTSemEventMultiDestroy(pThis->hEvtReset);
1657 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
1658 }
1659}
1660
1661
1662/**
1663 * @copydoc PDMUSBREG::pfnConstruct
1664 */
1665static DECLCALLBACK(int) usbMsdConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1666{
1667 PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
1668 Log(("usbMsdConstruct/#%u:\n", iInstance));
1669
1670 /*
1671 * Perform the basic structure initialization first so the destructor
1672 * will not misbehave.
1673 */
1674 pThis->pUsbIns = pUsbIns;
1675 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1676 pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
1677 pThis->Lun0.IBase.pfnQueryInterface = usbMsdLun0QueryInterface;
1678 pThis->Lun0.IScsiPort.pfnSCSIRequestCompleted = usbMsdLun0ScsiRequestCompleted;
1679 usbMsdQueueInit(&pThis->ToHostQueue);
1680 usbMsdQueueInit(&pThis->DoneQueue);
1681
1682 int rc = RTCritSectInit(&pThis->CritSect);
1683 AssertRCReturn(rc, rc);
1684
1685 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1686 AssertRCReturn(rc, rc);
1687
1688 rc = RTSemEventMultiCreate(&pThis->hEvtReset);
1689 AssertRCReturn(rc, rc);
1690
1691 /*
1692 * Validate and read the configuration.
1693 */
1694 rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbMsd", iInstance);
1695 if (RT_FAILURE(rc))
1696 return rc;
1697
1698 /*
1699 * Attach the SCSI driver.
1700 */
1701 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, "SCSI Port");
1702 if (RT_FAILURE(rc))
1703 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
1704 pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
1705 if (!pThis->Lun0.pIScsiConnector)
1706 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
1707 N_("MSD failed to query the PDMISCSICONNECTOR from the driver below it"));
1708
1709 return VINF_SUCCESS;
1710}
1711
1712
1713/**
1714 * The USB Mass Storage Device (MSD) registration record.
1715 */
1716const PDMUSBREG g_UsbMsd =
1717{
1718 /* u32Version */
1719 PDM_USBREG_VERSION,
1720 /* szName */
1721 "Msd",
1722 /* pszDescription */
1723 "USB Mass Storage Device, one LUN.",
1724 /* fFlags */
1725 PDM_USBREG_HIGHSPEED_CAPABLE,
1726 /* cMaxInstances */
1727 ~0U,
1728 /* cbInstance */
1729 sizeof(USBMSD),
1730 /* pfnConstruct */
1731 usbMsdConstruct,
1732 /* pfnDestruct */
1733 usbMsdDestruct,
1734 /* pfnVMInitComplete */
1735 NULL,
1736 /* pfnVMPowerOn */
1737 NULL,
1738 /* pfnVMReset */
1739 NULL,
1740 /* pfnVMSuspend */
1741 NULL,
1742 /* pfnVMResume */
1743 NULL,
1744 /* pfnVMPowerOff */
1745 NULL,
1746 /* pfnHotPlugged */
1747 NULL,
1748 /* pfnHotUnplugged */
1749 NULL,
1750 /* pfnDriverAttach */
1751 NULL,
1752 /* pfnDriverDetach */
1753 NULL,
1754 /* pfnQueryInterface */
1755 NULL,
1756 /* pfnUsbReset */
1757 usbMsdUsbReset,
1758 /* pfnUsbGetCachedDescriptors */
1759 usbMsdUsbGetDescriptorCache,
1760 /* pfnUsbSetConfiguration */
1761 usbMsdUsbSetConfiguration,
1762 /* pfnUsbSetInterface */
1763 usbMsdUsbSetInterface,
1764 /* pfnUsbClearHaltedEndpoint */
1765 usbMsdUsbClearHaltedEndpoint,
1766 /* pfnUrbNew */
1767 NULL/*usbMsdUrbNew*/,
1768 /* pfnQueue */
1769 usbMsdQueue,
1770 /* pfnUrbCancel */
1771 usbMsdUrbCancel,
1772 /* pfnUrbReap */
1773 usbMsdUrbReap,
1774 /* u32TheEnd */
1775 PDM_USBREG_VERSION
1776};
1777
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