VirtualBox

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

Last change on this file since 28065 was 28065, checked in by vboxsync, 15 years ago

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

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