VirtualBox

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

Last change on this file since 49016 was 48981, checked in by vboxsync, 11 years ago

Devices/UsbMsd: Updates

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