VirtualBox

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

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

VUSB: interface association descriptor for emulated devices.

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