VirtualBox

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

Last change on this file since 38791 was 37795, checked in by vboxsync, 13 years ago

Devices: use helpers

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