UsbMsd.cpp revision 512ac71127c4fba43d0fd7ea838e96df5be2258b
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/* $Id$ */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** @file
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * UsbMSD - USB Mass Storage Device Emulation.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2007-2012 Oracle Corporation
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * available from http://www.virtualbox.org. This file is free software;
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * General Public License (GPL) as published by the Free Software
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*******************************************************************************
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync* Header Files *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync*******************************************************************************/
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define LOG_GROUP LOG_GROUP_USB_MSD
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmusb.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <VBox/log.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <VBox/err.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <VBox/scsi.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/assert.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/critsect.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/mem.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/semaphore.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/string.h>
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#include <iprt/uuid.h>
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include "VBoxDD.h"
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*******************************************************************************
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync* Defined Constants And Macros *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync*******************************************************************************/
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** @name USB MSD string IDs
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @{ */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBMSD_STR_ID_MANUFACTURER 1
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync#define USBMSD_STR_ID_PRODUCT_HD 2
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync#define USBMSD_STR_ID_PRODUCT_CDROM 3
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** @} */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync/** @name USB MSD vendor and product IDs
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * @{ */
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync#define VBOX_USB_VENDOR 0x80EE
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync#define USBMSD_PID_HD 0x0030
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync#define USBMSD_PID_CD 0x0031
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync/** @} */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/** Saved state version. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync#define USB_MSD_SAVED_STATE_VERSION 1
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*******************************************************************************
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync* Structures and Typedefs *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync*******************************************************************************/
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
1e9e76e4273dcc2e3d560a0f3605c46f0013eb7bvboxsync * USB MSD Command Block Wrapper or CBW. The command block
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * itself (CBWCB) contains protocol-specific data (here SCSI).
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#pragma pack(1)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBCBW
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCBWSignature;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCBW_SIGNATURE UINT32_C(0x43425355)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCBWTag;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCBWDataTransferLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t bmCBWFlags;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCBW_DIR_MASK RT_BIT(7)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCBW_DIR_OUT 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCBW_DIR_IN RT_BIT(7)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t bCBWLun;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t bCBWCBLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t CBWCB[16];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBCBW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#pragma pack()
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncAssertCompileSize(USBCBW, 31);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a Command Block Wrapper. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBCBW *PUSBCBW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a const Command Block Wrapper. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef const USBCBW *PCUSBCBW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * USB MSD Command Status Wrapper or CSW.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#pragma pack(1)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBCSW
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCSWSignature;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCSW_SIGNATURE UINT32_C(0x53425355)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCSWTag;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t dCSWDataResidue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCSW_STATUS_OK UINT8_C(0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCSW_STATUS_FAILED UINT8_C(1)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#define USBCSW_STATUS_PHASE_ERROR UINT8_C(2)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t bCSWStatus;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBCSW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#pragma pack()
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncAssertCompileSize(USBCSW, 13);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a Command Status Wrapper. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBCSW *PUSBCSW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a const Command Status Wrapper. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef const USBCSW *PCUSBCSW;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The USB MSD request state.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef enum USBMSDREQSTATE
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Invalid status. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_INVALID = 0,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Ready to receive a new SCSI command. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_READY,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Waiting for the host to supply data. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_DATA_FROM_HOST,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The SCSI request is being executed by the driver. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_EXECUTING,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Have (more) data for the host. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_DATA_TO_HOST,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Waiting to supply status information to the host. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_STATUS,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Destroy the request upon completion.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * This is set when the SCSI request doesn't complete before for the device or
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * mass storage reset operation times out. USBMSD::pReq will be set to NULL
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * and the only reference to this request will be with DrvSCSI. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE_DESTROY_ON_COMPLETION,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The end of the valid states. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync USBMSDREQSTATE_END,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /** 32bit blow up hack. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync USBMSDREQSTATE_32BIT_HACK = 0x7fffffff
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBMSDREQSTATE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * A pending USB MSD request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBMSDREQ
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The state of the request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE enmState;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The size of the data buffer. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync size_t cbBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Pointer to the data buffer. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t *pbBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Current buffer offset. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t offBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The current Cbw when we're in the pending state. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBCBW Cbw;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The current SCSI request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMSCSIREQUEST ScsiReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The scatter-gather segment used by ScsiReq for describing pbBuf. */
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync RTSGSEG ScsiReqSeg;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The sense buffer for the current SCSI request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t ScsiReqSense[64];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The status of a completed SCSI request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int iScsiReqStatus;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Set if the request structure must be destroyed when the SCSI driver
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * completes it. This is used to deal with requests that runs while the
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * device is being reset. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync bool fDestoryOnCompletion;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Pointer to the USB device instance owning it. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PPDMUSBINS pUsbIns;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBMSDREQ;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a USB MSD request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBMSDREQ *PUSBMSDREQ;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Endpoint status data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBMSDEP
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync bool fHalted;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBMSDEP;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to the endpoint status. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBMSDEP *PUSBMSDEP;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * A URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBMSDURBQUEUE
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The head pointer. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Where to insert the next entry. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB *ppTail;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBMSDURBQUEUE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a URB queue. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBMSDURBQUEUE *PUSBMSDURBQUEUE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to a const URB queue. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBMSDURBQUEUE const *PCUSBMSDURBQUEUE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The USB MSD instance data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef struct USBMSD
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Pointer back to the PDM USB Device instance structure. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PPDMUSBINS pUsbIns;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Critical section protecting the device state. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCRITSECT CritSect;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The current configuration.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * (0 - default, 1 - the only, i.e configured.) */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint8_t bConfigurationValue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#if 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The state of the MSD (state machine).*/
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDSTATE enmState;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#endif
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Endpoint 0 is the default control pipe, 1 is the host->dev bulk pipe and 2
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * is the dev->host one. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDEP aEps[3];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The current request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Pending to-host queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The URBs waiting here are pending the completion of the current request and
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * data or status to become available.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDURBQUEUE ToHostQueue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Done queue
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The URBs stashed here are waiting to be reaped. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDURBQUEUE DoneQueue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * is set. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSEMEVENT hEvtDoneQueue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Someone is waiting on the done queue. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync bool fHaveDoneQueueWaiter;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Whether to signal the reset semaphore when the current request completes. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync bool fSignalResetSem;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** Semaphore usbMsdUsbReset waits on when a request is executing at reset
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * time. Only signalled when fSignalResetSem is set. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSEMEVENTMULTI hEvtReset;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The reset URB.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * This is waiting for SCSI request completion before finishing the reset. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pResetUrb;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync /** Indicates that PDMUsbHlpAsyncNotificationCompleted should be called when
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * the MSD is entering the idle state. */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync volatile bool fSignalIdle;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * LUN\#0 data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync struct
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The base interface for LUN\#0. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMIBASE IBase;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The SCSI port interface for LUN\#0 */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMISCSIPORT IScsiPort;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The base interface for the SCSI driver connected to LUN\#0. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PPDMIBASE pIBase;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** The SCSI connector interface for the SCSI driver connected to LUN\#0. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PPDMISCSICONNECTOR pIScsiConnector;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync } Lun0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync} USBMSD;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/** Pointer to the USB MSD instance data. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsynctypedef USBMSD *PUSBMSD;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*******************************************************************************
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync* Global Variables *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync*******************************************************************************/
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic const PDMUSBDESCCACHESTRING g_aUsbMsdStrings_en_US[] =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync { USBMSD_STR_ID_MANUFACTURER, "VirtualBox" },
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync { USBMSD_STR_ID_PRODUCT_HD, "USB Harddisk" },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync { USBMSD_STR_ID_PRODUCT_CDROM, "USB CD-ROM" }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic const PDMUSBDESCCACHELANG g_aUsbMsdLanguages[] =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync { 0x0409, RT_ELEMENTS(g_aUsbMsdStrings_en_US), g_aUsbMsdStrings_en_US }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsFS[2] =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bLength = */ sizeof(VUSBDESCENDPOINT),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bmAttributes = */ 2 /* bulk */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .wMaxPacketSize = */ 64 /* maximum possible */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterval = */ 0 /* not applicable for bulk EP */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync },
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvMore = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvClass = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .cbClass = */ 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync },
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bLength = */ sizeof(VUSBDESCENDPOINT),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bmAttributes = */ 2 /* bulk */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .wMaxPacketSize = */ 64 /* maximum possible */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterval = */ 0 /* not applicable for bulk EP */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync },
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvMore = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvClass = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .cbClass = */ 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCENDPOINTEX g_aUsbMsdEndpointDescsHS[2] =
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bLength = */ sizeof(VUSBDESCENDPOINT),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bmAttributes = */ 2 /* bulk */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterval = */ 0 /* no NAKs */
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvMore = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvClass = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .cbClass = */ 0
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bLength = */ sizeof(VUSBDESCENDPOINT),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bEndpointAddress = */ 0x02 /* ep=2, out */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bmAttributes = */ 2 /* bulk */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .wMaxPacketSize = */ 512 /* HS bulk packet size */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterval = */ 0 /* no NAKs */
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvMore = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvClass = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .cbClass = */ 0
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync }
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync};
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescFS =
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bLength = */ sizeof(VUSBDESCINTERFACE),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bDescriptorType = */ VUSB_DT_INTERFACE,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterfaceNumber = */ 0,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bAlternateSetting = */ 0,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bNumEndpoints = */ 2,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterfaceClass = */ 8 /* Mass Storage */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .iInterface = */ 0
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvMore = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pvClass = */ NULL,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .cbClass = */ 0,
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync &g_aUsbMsdEndpointDescsFS[0],
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .pIAD = */ NULL,
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .cbIAD = */ 0
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync};
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCINTERFACEEX g_UsbMsdInterfaceDescHS =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bLength = */ sizeof(VUSBDESCINTERFACE),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDescriptorType = */ VUSB_DT_INTERFACE,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bInterfaceNumber = */ 0,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bAlternateSetting = */ 0,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bNumEndpoints = */ 2,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bInterfaceClass = */ 8 /* Mass Storage */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bInterfaceSubClass = */ 6 /* SCSI transparent command set */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bInterfaceProtocol = */ 0x50 /* Bulk-Only Transport */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .iInterface = */ 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync },
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvMore = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pvClass = */ NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .cbClass = */ 0,
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync &g_aUsbMsdEndpointDescsHS[0],
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .pIAD = */ NULL,
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .cbIAD = */ 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBINTERFACE g_aUsbMsdInterfacesFS[] =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync { &g_UsbMsdInterfaceDescFS, /* .cSettings = */ 1 },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync};
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBINTERFACE g_aUsbMsdInterfacesHS[] =
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync { &g_UsbMsdInterfaceDescHS, /* .cSettings = */ 1 },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync};
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCCONFIGEX g_UsbMsdConfigDescFS =
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync {
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bLength = */ sizeof(VUSBDESCCONFIG),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bDescriptorType = */ VUSB_DT_CONFIG,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .wTotalLength = */ 0 /* recalculated on read */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesFS),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bConfigurationValue =*/ 1,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .iConfiguration = */ 0,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bmAttributes = */ RT_BIT(7),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .MaxPower = */ 50 /* 100mA */
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync },
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync NULL, /* pvMore */
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync &g_aUsbMsdInterfacesFS[0],
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync NULL /* pvOriginal */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const VUSBDESCCONFIGEX g_UsbMsdConfigDescHS =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bLength = */ sizeof(VUSBDESCCONFIG),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDescriptorType = */ VUSB_DT_CONFIG,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .wTotalLength = */ 0 /* recalculated on read */,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbMsdInterfacesHS),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bConfigurationValue =*/ 1,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .iConfiguration = */ 0,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bmAttributes = */ RT_BIT(7),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .MaxPower = */ 50 /* 100mA */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync },
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync NULL, /* pvMore */
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync &g_aUsbMsdInterfacesHS[0],
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync NULL /* pvOriginal */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic const VUSBDESCDEVICE g_UsbMsdDeviceDesc =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bLength = */ sizeof(g_UsbMsdDeviceDesc),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDescriptorType = */ VUSB_DT_DEVICE,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bcdUsb = */ 0x200, /* USB 2.0 */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bMaxPacketSize0 = */ 64,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .idVendor = */ VBOX_USB_VENDOR,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .idProduct = */ USBMSD_PID_HD,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bcdDevice = */ 0x0100, /* 1.0 */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .iManufacturer = */ USBMSD_STR_ID_MANUFACTURER,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .iProduct = */ USBMSD_STR_ID_PRODUCT_HD,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .iSerialNumber = */ 0,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .bNumConfigurations = */ 1
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsyncstatic const VUSBDEVICEQUALIFIER g_UsbMsdDeviceQualifier =
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync{
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bLength = */ sizeof(g_UsbMsdDeviceQualifier),
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bDescriptorType = */ VUSB_DT_DEVICE_QUALIFIER,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bcdUsb = */ 0x200, /* USB 2.0 */
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bMaxPacketSize0 = */ 64,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bNumConfigurations = */ 1,
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* .bReserved = */ 0
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync};
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const PDMUSBDESCCACHE g_UsbMsdDescCacheFS =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .pDevice = */ &g_UsbMsdDeviceDesc,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .paConfigs = */ &g_UsbMsdConfigDescFS,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .paLanguages = */ g_aUsbMsdLanguages,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .fUseCachedDescriptors = */ true,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .fUseCachedStringsDescriptors = */ true
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync};
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsyncstatic const PDMUSBDESCCACHE g_UsbMsdDescCacheHS =
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync{
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .pDevice = */ &g_UsbMsdDeviceDesc,
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync /* .paConfigs = */ &g_UsbMsdConfigDescHS,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .paLanguages = */ g_aUsbMsdLanguages,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .cLanguages = */ RT_ELEMENTS(g_aUsbMsdLanguages),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .fUseCachedDescriptors = */ true,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* .fUseCachedStringsDescriptors = */ true
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/*******************************************************************************
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync* Internal Functions *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync*******************************************************************************/
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Initializes an URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pQueue The URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic void usbMsdQueueInit(PUSBMSDURBQUEUE pQueue)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->pHead = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->ppTail = &pQueue->pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Inserts an URB at the end of the queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pQueue The URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUrb The URB to insert.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncDECLINLINE(void) usbMsdQueueAddTail(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb->Dev.pNext = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *pQueue->ppTail = pUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->ppTail = &pUrb->Dev.pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Unlinks the head of the queue and returns it.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns The head entry.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pQueue The URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncDECLINLINE(PVUSBURB) usbMsdQueueRemoveHead(PUSBMSDURBQUEUE pQueue)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pUrb = pQueue->pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pNext = pUrb->Dev.pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->pHead = pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pNext)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->ppTail = &pQueue->pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb->Dev.pNext = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return pUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Removes an URB from anywhere in the queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns true if found, false if not.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pQueue The URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUrb The URB to remove.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncDECLINLINE(bool) usbMsdQueueRemove(PUSBMSDURBQUEUE pQueue, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pCur = pQueue->pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCur == pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->pHead = pUrb->Dev.pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync while (pCur)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCur->Dev.pNext == pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCur->Dev.pNext = pUrb->Dev.pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCur = pCur->Dev.pNext;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pCur)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pUrb->Dev.pNext)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pQueue->ppTail = &pQueue->pHead;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Checks if the queue is empty or not.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns true if it is, false if it isn't.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pQueue The URB queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncDECLINLINE(bool) usbMsdQueueIsEmpty(PCUSBMSDURBQUEUE pQueue)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return pQueue->pHead == NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Links an URB into the done queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pThis The MSD instance.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUrb The URB.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic void usbMsdLinkDone(PUSBMSD pThis, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueueAddTail(&pThis->DoneQueue, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->fHaveDoneQueueWaiter)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertRC(rc);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Allocates a new request and does basic init.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns Pointer to the new request. NULL if we're out of memory.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUsbIns The instance allocating it.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic PUSBMSDREQ usbMsdReqAlloc(PPDMUSBINS pUsbIns)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq = (PUSBMSDREQ)PDMUsbHlpMMHeapAllocZ(pUsbIns, sizeof(*pReq));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_READY;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->iScsiReqStatus = -1;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->pUsbIns = pUsbIns;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogRel(("usbMsdReqAlloc: Out of memory\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Frees a request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pReq The request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic void usbMsdReqFree(PUSBMSDREQ pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Check the input.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertReturnVoid( pReq->enmState > USBMSDREQSTATE_INVALID
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pReq->enmState != USBMSDREQSTATE_EXECUTING
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pReq->enmState < USBMSDREQSTATE_END);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PPDMUSBINS pUsbIns = pReq->pUsbIns;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertPtrReturnVoid(pUsbIns);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Invalidate it and free the associated resources.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_INVALID;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->cbBuf = 0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->offBuf = 0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pbCDB = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.paScatterGatherHead = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pbSenseBuffer = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pvUser = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSeg.cbSeg = 0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSeg.pvSeg = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq->pbBuf)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMUsbHlpMMHeapFree(pUsbIns, pReq->pbBuf);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->pbBuf = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMUsbHlpMMHeapFree(pUsbIns, pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Prepares a request for execution or data buffering.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pReq The request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pCbw The SCSI command block wrapper.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic void usbMsdReqPrepare(PUSBMSDREQ pReq, PCUSBCBW pCbw)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Copy the CBW */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync size_t cbCopy = RT_OFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync memcpy(&pReq->Cbw, pCbw, cbCopy);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync memset((uint8_t *)&pReq->Cbw + cbCopy, 0, sizeof(pReq->Cbw) - cbCopy);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Setup the SCSI request. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.uLogicalUnit = pReq->Cbw.bCBWLun;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.uDataDirection = (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync ? PDMSCSIREQUESTTXDIR_TO_DEVICE
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync : PDMSCSIREQUESTTXDIR_FROM_DEVICE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->offBuf = 0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSeg.cbSeg = pReq->Cbw.dCBWDataTransferLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.cbScatterGather = pReq->Cbw.dCBWDataTransferLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.cScatterGatherEntries = 1;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.pvUser = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RT_ZERO(pReq->ScsiReqSense);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->iScsiReqStatus = -1;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Makes sure that there is sufficient buffer space available.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns Success indicator (true/false)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pReq
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param cbBuf The required buffer space.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdReqEnsureBuffer(PUSBMSDREQ pReq, size_t cbBuf)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_LIKELY(pReq->cbBuf >= cbBuf))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RT_BZERO(pReq->pbBuf, cbBuf);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMUsbHlpMMHeapFree(pReq->pUsbIns, pReq->pbBuf);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->cbBuf = 0;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pReq->pUsbIns, cbBuf);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pReq->pbBuf)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->cbBuf = cbBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Completes the URB with a stalled state, halting the pipe.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdCompleteStall(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb, const char *pszWhy)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb->enmStatus = VUSBSTATUS_STALL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** @todo figure out if the stall is global or pipe-specific or both. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pEp)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pEp->fHalted = true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->aEps[1].fHalted = true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->aEps[2].fHalted = true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdLinkDone(pThis, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Completes the URB with a OK state.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdCompleteOk(PUSBMSD pThis, PVUSBURB pUrb, size_t cbData)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb->enmStatus = VUSBSTATUS_OK;
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync pUrb->cbData = (uint32_t)cbData;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdLinkDone(pThis, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Reset worker for usbMsdUsbReset, usbMsdUsbSetConfiguration and
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * usbMsdUrbHandleDefaultPipe.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns VBox status code.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pThis The MSD instance.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUrb Set when usbMsdUrbHandleDefaultPipe is the
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * caller.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param fSetConfig Set when usbMsdUsbSetConfiguration is the
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * caller.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdResetWorker(PUSBMSD pThis, PVUSBURB pUrb, bool fSetConfig)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Wait for the any command currently executing to complete before
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * resetting. (We cannot cancel its execution.) How we do this depends
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * on the reset method.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq = pThis->pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ( pReq
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pReq->enmState == USBMSDREQSTATE_EXECUTING)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* Don't try to deal with the set config variant nor multiple build-only
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync mass storage resets. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->pResetUrb && (pUrb || fSetConfig))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdResetWorker: pResetUrb is already %p:%s - stalling\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "pResetUrb");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Bulk-Only Mass Storage Reset: Complete the reset on request completion. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pResetUrb = pUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdResetWorker: Setting pResetUrb to %p:%s\n", pThis->pResetUrb, pThis->pResetUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Device reset: Wait for up to 10 ms. If it doesn't work, ditch
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync whoe the request structure. We'll allocate a new one when needed. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdResetWorker: Waiting for completion...\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(!pThis->fSignalResetSem);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->fSignalResetSem = true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSemEventMultiReset(pThis->hEvtReset);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = RTSemEventMultiWait(pThis->hEvtReset, 10 /*ms*/);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->fSignalResetSem = false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ( RT_FAILURE(rc)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync || pReq->enmState == USBMSDREQSTATE_EXECUTING)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdResetWorker: Didn't complete, ditching the current request (%p)!\n", pReq));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(pReq == pThis->pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_DESTROY_ON_COMPLETION;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pReq = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Reset the request and device state.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_READY;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->iScsiReqStatus = -1;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->aEps[i].fHalted = false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pUrb && !fSetConfig) /* (only device reset) */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->bConfigurationValue = 0; /* default */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Ditch all pending URBs.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pCurUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync while ((pCurUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCurUrb->enmStatus = VUSBSTATUS_CRC;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdLinkDone(pThis, pCurUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCurUrb = pThis->pResetUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCurUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pResetUrb = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCurUrb->enmStatus = VUSBSTATUS_CRC;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdLinkDone(pThis, pCurUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteOk(pThis, pUrb, 0);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsyncstatic DECLCALLBACK(int) usbMsdLun0ScsiRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync int rcCompletion, bool fRedo, int rcReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq = RT_FROM_MEMBER(pSCSIRequest, USBMSDREQ, ScsiReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdLun0ScsiRequestCompleted: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, rcCompletion));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq->enmState != USBMSDREQSTATE_DESTROY_ON_COMPLETION)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(pThis->pReq == pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->iScsiReqStatus = rcCompletion;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Advance the state machine. The state machine is not affected by
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * SCSI errors.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_STATUS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdLun0ScsiRequestCompleted: Entering STATUS\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdLun0ScsiRequestCompleted: Entering DATA_TO_HOST\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Deal with pending to-host URBs.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync for (;;)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->ToHostQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* Process it the normal way. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdLun0ScsiRequestCompleted: freeing %p\n", pReq));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdReqFree(pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->fSignalResetSem)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSemEventMultiSignal(pThis->hEvtReset);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->pResetUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pResetUrb = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdResetWorker(pThis, pThis->pResetUrb, false /*fSetConfig*/);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @interface_method_impl{PDMISCSIPORT,pfnQueryDeviceLocation}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController,
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync uint32_t *piInstance, uint32_t *piLUN)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PPDMUSBINS pUsbIns = pThis->pUsbIns;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync *ppcszController = pUsbIns->pReg->szName;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync *piInstance = pUsbIns->iInstance;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync *piLUN = 0;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync return VINF_SUCCESS;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(void *) usbMsdLun0QueryInterface(PPDMIBASE pInterface, const char *pszIID)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pThis->Lun0.IScsiPort);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * Checks if all asynchronous I/O is finished.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync *
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * Used by usbMsdVMReset, usbMsdVMSuspend and usbMsdVMPowerOff.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync *
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @returns true if quiesced, false if busy.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @param pUsbIns The USB device instance.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic bool usbMsdAllAsyncIOIsFinished(PPDMUSBINS pUsbIns)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if ( VALID_PTR(pThis->pReq)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync && pThis->pReq->enmState == USBMSDREQSTATE_EXECUTING)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return false;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return true;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * Callback employed by usbMsdVMSuspend and usbMsdVMPowerOff.}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(bool) usbMsdIsAsyncSuspendOrPowerOffDone(PPDMUSBINS pUsbIns)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return false;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return true;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * Common worker for usbMsdVMSuspend and usbMsdVMPowerOff.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic void usbMsdSuspendOrPowerOff(PPDMUSBINS pUsbIns)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, true);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncSuspendOrPowerOffDone);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync else
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/* -=-=-=-=- Saved State -=-=-=-=- */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @copydoc FNUSBSSMSAVEPREP
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(int) usbMsdSavePrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return VINF_SUCCESS;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @copydoc FNUSBSSMLOADPREP
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(int) usbMsdLoadPrep(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdAllAsyncIOIsFinished(pUsbIns));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdQueueIsEmpty(&pThis->ToHostQueue));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(usbMsdQueueIsEmpty(&pThis->DoneQueue));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return VINF_SUCCESS;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @copydoc FNUSBSSMLIVEEXEC
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(int) usbMsdLiveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /* config. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutBool(pSSM, pThis->Lun0.pIBase != NULL);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return VINF_SSM_DONT_CALL_AGAIN;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @copydoc FNUSBSSMSAVEEXEC
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(int) usbMsdSaveExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync uint32_t i;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync int rc;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /* The config */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = usbMsdLiveExec(pUsbIns, pSSM, SSM_PASS_FINAL);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync AssertRCReturn(rc, rc);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU8(pSSM, pThis->bConfigurationValue);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutBool(pSSM, pThis->aEps[0].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutBool(pSSM, pThis->aEps[1].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutBool(pSSM, pThis->aEps[2].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutBool(pSSM, pThis->pReq != NULL);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (pThis->pReq)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSDREQ pReq = pThis->pReq;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->enmState);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->cbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (pReq->cbBuf)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync AssertPtr(pReq->pbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutMem(pSSM, pReq->pbBuf, pReq->cbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->offBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->ScsiReq.uLogicalUnit);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->ScsiReq.uDataDirection);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->ScsiReq.cbCDB);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutU32(pSSM, pReq->ScsiReq.cbScatterGather);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3PutS32(pSSM, pReq->iScsiReqStatus);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return SSMR3PutU32(pSSM, UINT32_MAX); /* sanity/terminator */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync/**
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * @copydoc FNUSBSSMLOADEXEC
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsyncstatic DECLCALLBACK(int) usbMsdLoadExec(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync{
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync uint32_t u32;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync int rc;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (uVersion > USB_MSD_SAVED_STATE_VERSION)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /* Verify config. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync bool fInUse;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = SSMR3GetBool(pSSM, &fInUse);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync AssertRCReturn(rc, rc);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (fInUse != (pThis->Lun0.pIBase != NULL))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync N_("The %s VM is missing a USB mass storage device. Please make sure the source and target VMs have compatible storage configurations"),
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync fInUse ? "target" : "source");
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (uPass == SSM_PASS_FINAL)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /* Restore data. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync bool fReqAlloc = false;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(!pThis->pReq);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU8(pSSM, &pThis->bConfigurationValue);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetBool(pSSM, &pThis->aEps[0].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetBool(pSSM, &pThis->aEps[1].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetBool(pSSM, &pThis->aEps[2].fHalted);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetBool(pSSM, &fReqAlloc);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (fReqAlloc)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PUSBMSDREQ pReq = usbMsdReqAlloc(pUsbIns);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (pReq)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync uint32_t cbBuf = 0;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pThis->pReq = pReq;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, (uint32_t *)&pReq->enmState);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, &cbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (cbBuf)
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (usbMsdReqEnsureBuffer(pReq, cbBuf))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync AssertPtr(pReq->pbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync Assert(cbBuf = pReq->cbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetMem(pSSM, pReq->pbBuf, pReq->cbBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync else
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = VERR_NO_MEMORY;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (RT_SUCCESS(rc))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync {
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, &pReq->offBuf);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, &pReq->ScsiReq.uLogicalUnit);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, (uint32_t *)&pReq->ScsiReq.uDataDirection);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, &pReq->ScsiReq.cbCDB);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetU32(pSSM, &pReq->ScsiReq.cbScatterGather);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync SSMR3GetS32(pSSM, &pReq->iScsiReqStatus);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /* Setup the rest of the SCSI request. */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.cbCDB = pReq->Cbw.bCBWCBLength;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.pbCDB = &pReq->Cbw.CBWCB[0];
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReqSeg.pvSeg = pReq->pbBuf;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReqSeg.cbSeg = pReq->ScsiReq.cbScatterGather;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.cScatterGatherEntries = 1;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.cbSenseBuffer = sizeof(pReq->ScsiReqSense);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.pbSenseBuffer = &pReq->ScsiReqSense[0];
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync pReq->ScsiReq.pvUser = NULL;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync else
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = VERR_NO_MEMORY;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (RT_SUCCESS(rc))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = SSMR3GetU32(pSSM, &u32);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (RT_FAILURE(rc))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return rc;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync }
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return VINF_SUCCESS;
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync}
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUrbReap
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(PVUSBURB) usbMsdUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBURB pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pUrb && cMillies)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Wait */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->fHaveDoneQueueWaiter = true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->fHaveDoneQueueWaiter = false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb = usbMsdQueueRemoveHead(&pThis->DoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return pUrb;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUrbCancel
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Remove the URB from the to-host queue and move it onto the done queue.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (usbMsdQueueRemove(&pThis->ToHostQueue, pUrb))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdLinkDone(pThis, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Fails an illegal SCSI request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns VBox status code.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pThis The MSD instance data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pReq The MSD request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param bAsc The ASC for the SCSI_SENSE_ILLEGAL_REQUEST.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param bAscq The ASC qualifier.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pszWhy For logging why.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdScsiIllegalRequest(PUSBMSD pThis, PUSBMSDREQ pReq, uint8_t bAsc, uint8_t bAscq, const char *pszWhy)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdScsiIllegalRequest: bAsc=%#x bAscq=%#x %s\n", bAsc, bAscq, pszWhy));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RT_ZERO(pReq->ScsiReqSense);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[2] = SCSI_SENSE_ILLEGAL_REQUEST;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[7] = 10;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[12] = SCSI_ASC_INVALID_MESSAGE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[13] = 0; /* Should be ASCQ but it has the same value for success. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The SCSI driver doesn't handle SCSI_REQUEST_SENSE but instead
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * returns the sense info with the request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdHandleScsiReqestSense(PUSBMSD pThis, PUSBMSDREQ pReq, PCUSBCBW pCbw)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleScsiReqestSense: Entering EXECUTING (dCBWTag=%#x).\n", pReq->Cbw.dCBWTag));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(pReq == pThis->pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_EXECUTING;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* validation */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync if (pCbw->bCBWCBLength < 6)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "lun");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->bCBWLun != 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync if (pCbw->CBWCB[4] < 6)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* If the previous command succeeded successfully, whip up some sense data. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ( pReq->iScsiReqStatus == SCSI_STATUS_OK
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pReq->ScsiReqSense[0] == 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RT_ZERO(pReq->ScsiReqSense);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#if 0 /** @todo something upsets linux about this stuff. Needs investigation. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[0] = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[0] = SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[2] = SCSI_SENSE_NONE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[7] = 10;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[12] = SCSI_ASC_NONE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSense[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync#endif
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Copy the data into the result buffer. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync size_t cbCopy = RT_MIN(pCbw->dCBWDataTransferLength, sizeof(pReq->ScsiReqSense));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: SCSI_REQUEST_SENSE - CBWCB[4]=%#x iOldState=%d, %u bytes, raw: %.*Rhxs\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCbw->CBWCB[4], pReq->iScsiReqStatus, pCbw->dCBWDataTransferLength, RT_MAX(1, cbCopy), pReq->ScsiReqSense));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync memcpy(pReq->pbBuf, &pReq->ScsiReqSense[0], cbCopy);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdReqPrepare(pReq, pCbw);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Do normal completion. */
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Wrapper around PDMISCSICONNECTOR::pfnSCSIRequestSend that deals with
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * SCSI_REQUEST_SENSE.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns VBox status code.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pThis The MSD instance data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pReq The MSD request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pszCaller Where we're called from.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdSubmitScsiCommand(PUSBMSD pThis, PUSBMSDREQ pReq, const char *pszCaller)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("%s: Entering EXECUTING (dCBWTag=%#x).\n", pszCaller, pReq->Cbw.dCBWTag));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(pReq == pThis->pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_EXECUTING;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pReq->ScsiReq.pbCDB[0])
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case SCSI_REQUEST_SENSE:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return pThis->Lun0.pIScsiConnector->pfnSCSIRequestSend(pThis->Lun0.pIScsiConnector, &pReq->ScsiReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Validates a SCSI request before passing it down to the SCSI driver.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @returns true / false. The request will be completed on failure.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pThis The MSD instance data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pCbw The USB command block wrapper.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @param pUrb The URB.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic bool usbMsdIsValidCommand(PUSBMSD pThis, PCUSBCBW pCbw, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pCbw->CBWCB[0])
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case SCSI_REQUEST_SENSE:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** @todo validate this. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return true;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * Handle requests sent to the outbound (to device) bulk pipe.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdHandleBulkHostToDev(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Stall the request if the pipe is halted.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_UNLIKELY(pEp->fHalted))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Halted pipe");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Deal with the URB according to the current state.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq = pThis->pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync USBMSDREQSTATE enmState = pReq ? pReq->enmState : USBMSDREQSTATE_READY;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (enmState)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_STATUS:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdHandleBulkHostToDev: Skipping pending status.\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_READY;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* fall thru */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * We're ready to receive a command. Start off by validating the
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * incoming request.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_READY:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PCUSBCBW pCbw = (PUSBCBW)&pUrb->abData[0];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[1]))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Bad CBW: cbData=%#x < min=%#x\n", pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[1]) ));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "BAD CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->dCBWSignature != USBCBW_SIGNATURE)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: Invalid dCBWSignature value: %#x\n", pCbw->dCBWSignature));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync Log(("usbMsd: CBW: dCBWTag=%#x dCBWDataTransferLength=%#x bmCBWFlags=%#x bCBWLun=%#x bCBWCBLength=%#x cbData=%#x fShortNotOk=%RTbool\n",
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync pCbw->dCBWTag, pCbw->dCBWDataTransferLength, pCbw->bmCBWFlags, pCbw->bCBWLun, pCbw->bCBWCBLength, pUrb->cbData, pUrb->fShortNotOk));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->bmCBWFlags & ~USBCBW_DIR_MASK)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: Bad bmCBWFlags value: %#x\n", pCbw->bmCBWFlags));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->bCBWLun != 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: Bad bCBWLun value: %#x\n", pCbw->bCBWLun));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->bCBWCBLength == 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: Bad bCBWCBLength value: %#x\n", pCbw->bCBWCBLength));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb->cbData < RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: Mismatching cbData and bCBWCBLength values: %#x vs. %#x (%#x)\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pUrb->cbData, RT_UOFFSETOF(USBCBW, CBWCB[pCbw->bCBWCBLength]), pCbw->bCBWCBLength));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad CBW");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->dCBWDataTransferLength > _1M)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: CBW: dCBWDataTransferLength is too large: %#x (%u)\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCbw->dCBWDataTransferLength, pCbw->dCBWDataTransferLength));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Too big transfer");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!usbMsdIsValidCommand(pThis, pCbw, pUrb))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Make sure we've got a request and a sufficient buffer space.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Note! This will make sure the buffer is ZERO as well, thus
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * saving us the trouble of clearing the output buffer on
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * failure later.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq = usbMsdReqAlloc(pThis->pUsbIns);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pReq = pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!usbMsdReqEnsureBuffer(pReq, pCbw->dCBWDataTransferLength))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Special case REQUEST SENSE requests, usbMsdReqPrepare will
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * trash the sense data otherwise.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pCbw->CBWCB[0] == SCSI_REQUEST_SENSE)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdHandleScsiReqestSense(pThis, pReq, pCbw);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Prepare the request. Kick it off right away if possible.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdReqPrepare(pReq, pCbw);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ( pReq->Cbw.dCBWDataTransferLength == 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_FAILURE(rc))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
dedfbedd062921ee78fe4ef0f9edb2a9b8d0d97evboxsync return usbMsdCompleteOk(pThis, pUrb, pUrb->cbData);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Stuff the data into the buffer.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_DATA_FROM_HOST:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t cbData = pUrb->cbData;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t cbLeft = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (cbData > cbLeft)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Too much data: cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbLeft));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Too much data");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync memcpy(&pReq->pbBuf[pReq->offBuf], &pUrb->abData[0], cbData);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->offBuf += cbData;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_FAILURE(rc))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #2");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync return usbMsdCompleteOk(pThis, pUrb, cbData);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Bad state, stall.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_DATA_TO_HOST:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: DATA_TO_HOST");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_EXECUTING:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state H2D: EXECUTING");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertMsgFailed(("enmState=%d\n", enmState));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state (H2D)");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * Handle requests sent to the inbound (to host) bulk pipe.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdHandleBulkDevToHost(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Stall the request if the pipe is halted OR if there is no
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * pending request yet.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSDREQ pReq = pThis->pReq;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_UNLIKELY(pEp->fHalted || !pReq))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, pEp->fHalted ? "Halted pipe" : "No request");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Deal with the URB according to the state.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pReq->enmState)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * We've data left to transfer to the host.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_DATA_TO_HOST:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t cbData = pUrb->cbData;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync uint32_t cbCopy = pReq->Cbw.dCBWDataTransferLength - pReq->offBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (cbData <= cbCopy)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync cbCopy = cbData;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else if (pUrb->fShortNotOk)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Requested more data that we've got; cbData=%#x offBuf=%#x dCBWDataTransferLength=%#x cbLeft=%#x\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync cbData, pReq->offBuf, pReq->Cbw.dCBWDataTransferLength, cbCopy));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Data underrun");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync memcpy(&pUrb->abData[0], &pReq->pbBuf[pReq->offBuf], cbCopy);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->offBuf += cbCopy;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pReq->offBuf == pReq->Cbw.dCBWDataTransferLength)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: Entering STATUS\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_STATUS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteOk(pThis, pUrb, cbCopy);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Status transfer.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_STATUS:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync if ((pUrb->cbData < sizeof(USBCSW)) || (pUrb->cbData > sizeof(USBCSW) && pUrb->fShortNotOk))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync Log(("usbMsd: Unexpected status request size: %#x (expected %#x), fShortNotOK=%RTbool\n", pUrb->cbData, sizeof(USBCSW), pUrb->fShortNotOk));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Enter a CSW into the URB data buffer. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBCSW pCsw = (PUSBCSW)&pUrb->abData[0];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->dCSWSignature = USBCSW_SIGNATURE;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->dCSWTag = pReq->Cbw.dCBWTag;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->bCSWStatus = pReq->iScsiReqStatus == SCSI_STATUS_OK
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync ? USBCSW_STATUS_OK
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync : pReq->iScsiReqStatus >= 0
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync ? USBCSW_STATUS_FAILED
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync : USBCSW_STATUS_PHASE_ERROR;
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /** @todo the following is not always accurate; VSCSI needs
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync * to implement residual counts properly! */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync ? pReq->Cbw.dCBWDataTransferLength - pReq->ScsiReq.cbScatterGather
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync : pReq->Cbw.dCBWDataTransferLength;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync ? 0
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync : pReq->ScsiReq.cbScatterGather;
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: Entering READY\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_READY;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteOk(pThis, pUrb, sizeof(*pCsw));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Status request before we've received all (or even any) data.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Linux 2.4.31 does this sometimes. The recommended behavior is to
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * to accept the current data amount and execute the request. (The
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * alternative behavior is to stall.)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_DATA_FROM_HOST:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pUrb->cbData != sizeof(USBCSW))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: DATA_FROM_HOST; cbData=%#x -> stall\n", pUrb->cbData));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Invalid CSW size");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* Adjust the request and kick it off. Special case the no-data
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case since the SCSI driver doesn't like that. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReq.cbScatterGather = pReq->offBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->ScsiReqSeg.cbSeg = pReq->offBuf;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pReq->offBuf)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: Entering EXECUTING (offBuf=0x0).\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pReq->enmState = USBMSDREQSTATE_EXECUTING;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_FAILURE(rc))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #3");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* fall thru */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The SCSI command is still pending, queue the URB awaiting its
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * completion.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_EXECUTING:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Bad states, stall.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case USBMSDREQSTATE_READY:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: enmState=READ (cbData=%#x)\n", pReq->enmState, pUrb->cbData));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Bad state D2H: READY");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleBulkDevToHost: enmState=%d cbData=%#x\n", pReq->enmState, pUrb->cbData));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Handles request send to the default control pipe.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic int usbMsdHandleDefaultPipe(PUSBMSD pThis, PUSBMSDEP pEp, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pSetup->bRequest)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case VUSB_REQ_GET_DESCRIPTOR:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pSetup->bmRequestType != (VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pSetup->wValue >> 8)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync uint32_t cbCopy;
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case VUSB_DT_STRING:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync case VUSB_DT_DEVICE_QUALIFIER:
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync Log(("usbMsd: GET_DESCRIPTOR DT_DEVICE_QUALIFIER wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync /* Returned data is written after the setup message. */
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync cbCopy = pUrb->cbData - sizeof(*pSetup);
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync cbCopy = RT_MIN(cbCopy, sizeof(g_UsbMsdDeviceQualifier));
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbMsdDeviceQualifier, cbCopy);
5e1b3577b24e706f4e3e6dd840ab917c9c4942abvboxsync return usbMsdCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case VUSB_REQ_CLEAR_FEATURE:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /** @todo implement this. */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* 3.1 Bulk-Only Mass Storage Reset */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pSetup->bRequest == 0xff
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && !pSetup->wValue
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && !pSetup->wLength
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pSetup->wIndex == 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdResetWorker(pThis, pUrb, false /*fSetConfig*/);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* 3.2 Get Max LUN, may stall if we like (but we don't). */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE | VUSB_DIR_TO_HOST)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pSetup->bRequest == 0xfe
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && !pSetup->wValue
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pSetup->wLength == 1
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync && pSetup->wIndex == 0)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync *(uint8_t *)(pSetup + 1) = 0; /* max lun is 0 */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdCompleteOk(pThis, pUrb, 1);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync else
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsd: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return usbMsdCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnQueue
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Parse on a per end-point basis.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync switch (pUrb->EndPt)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case 0:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = usbMsdHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case 0x81:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertFailed();
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case 0x01:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = usbMsdHandleBulkDevToHost(pThis, &pThis->aEps[1], pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync case 0x02:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = usbMsdHandleBulkHostToDev(pThis, &pThis->aEps[2], pUrb);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync default:
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync break;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return rc;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUsbSetInterface
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(bAlternateSetting == 0);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUsbSetConfiguration
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Assert(bConfigurationValue == 1);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * If the same config is applied more than once, it's a kind of reset.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->bConfigurationValue == bConfigurationValue)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->bConfigurationValue = bConfigurationValue;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(PCPDMUSBDESCCACHE) usbMsdUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync if (pThis->pUsbIns->iUsbHubVersion & VUSB_STDVER_20)
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync return &g_UsbMsdDescCacheHS;
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync else
a32135908a8c242dda5a355b06c7ba93b6c39864vboxsync return &g_UsbMsdDescCacheFS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnUsbReset
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdUsbReset/#%u:\n", pUsbIns->iInstance));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return rc;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @copydoc PDMUSBREG::pfnVMSuspend
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(void) usbMsdVMSuspend(PPDMUSBINS pUsbIns)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync LogFlow(("usbMsdVMSuspend/#%u:\n", pUsbIns->iInstance));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdSuspendOrPowerOff(pUsbIns);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @copydoc PDMUSBREG::pfnVMSuspend
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(void) usbMsdVMPowerOff(PPDMUSBINS pUsbIns)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync LogFlow(("usbMsdVMPowerOff/#%u:\n", pUsbIns->iInstance));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdSuspendOrPowerOff(pUsbIns);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @copydoc PDMUSBREG::pfnDriverAttach
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(int) usbMsdDriverAttach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync int rc;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync ("UsbMsd: Device does not support hotplugging\n"));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync /* the usual paranoia */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertRelease(!pThis->Lun0.pIBase);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertRelease(!pThis->Lun0.pIScsiConnector);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync /*
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * Try attach the block device and get the interfaces,
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * required as well as optional.
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync rc = PDMUsbHlpDriverAttach(pUsbIns, iLUN, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, NULL);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync if (RT_SUCCESS(rc))
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync {
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync /* Get SCSI connector interface. */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsgReturn(pThis->Lun0.pIScsiConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync }
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync else
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", iLUN, rc));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync if (RT_FAILURE(rc))
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync {
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.pIBase = NULL;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.pIScsiConnector = NULL;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync }
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync return rc;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @copydoc PDMUSBREG::pfnDriverDetach
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(void) usbMsdDriverDetach(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync ("UsbMsd: Device does not support hotplugging\n"));
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync /*
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * Zero some important members.
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.pIBase = NULL;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.pIScsiConnector = NULL;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * Callback employed by usbMsdVMReset.}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(bool) usbMsdIsAsyncResetDone(PPDMUSBINS pUsbIns)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync return false;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertRC(rc);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync return true;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync/**
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync * @interface_method_impl{PDMDEVREG,pfnReset}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsyncstatic DECLCALLBACK(void) usbMsdVMReset(PPDMUSBINS pUsbIns)
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync{
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, true);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync if (!usbMsdAllAsyncIOIsFinished(pUsbIns))
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncResetDone);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync else
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync {
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync ASMAtomicWriteBool(&pThis->fSignalIdle, false);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync int rc = usbMsdResetWorker(pThis, NULL, false /*fSetConfig*/);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync AssertRC(rc);
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync }
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync}
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnDestruct
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic void usbMsdDestruct(PPDMUSBINS pUsbIns)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync LogFlow(("usbMsdDestruct/#%u:\n", pUsbIns->iInstance));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RTCritSectIsInitialized(&pThis->CritSect))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectEnter(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectLeave(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTCritSectDelete(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->pReq)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdReqFree(pThis->pReq);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pReq = NULL;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSemEventDestroy(pThis->hEvtDoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (pThis->hEvtReset != NIL_RTSEMEVENTMULTI)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync {
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync RTSemEventMultiDestroy(pThis->hEvtReset);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync }
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * @copydoc PDMUSBREG::pfnConstruct
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncstatic DECLCALLBACK(int) usbMsdConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync Log(("usbMsdConstruct/#%u:\n", iInstance));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Perform the basic structure initialization first so the destructor
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * will not misbehave.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->pUsbIns = pUsbIns;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->hEvtReset = NIL_RTSEMEVENTMULTI;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->Lun0.IBase.pfnQueryInterface = usbMsdLun0QueryInterface;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->Lun0.IScsiPort.pfnSCSIRequestCompleted = usbMsdLun0ScsiRequestCompleted;
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync pThis->Lun0.IScsiPort.pfnQueryDeviceLocation = usbMsdLun0QueryDeviceLocation;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueueInit(&pThis->ToHostQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueueInit(&pThis->DoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync int rc = RTCritSectInit(&pThis->CritSect);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertRCReturn(rc, rc);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertRCReturn(rc, rc);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = RTSemEventMultiCreate(&pThis->hEvtReset);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync AssertRCReturn(rc, rc);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Validate and read the configuration.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbMsd", iInstance);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_FAILURE(rc))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return rc;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /*
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * Attach the SCSI driver.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
712908e30894a2324fa7aa40c4ccf6d7198ef20fvboxsync rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pIBase, "SCSI Port");
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (RT_FAILURE(rc))
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync if (!pThis->Lun0.pIScsiConnector)
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync N_("MSD failed to query the PDMISCSICONNECTOR from the driver below it"));
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync /*
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync * Register the saved state data unit.
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync rc = PDMUsbHlpSSMRegister(pUsbIns, USB_MSD_SAVED_STATE_VERSION, sizeof(*pThis),
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync NULL, usbMsdLiveExec, NULL,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync usbMsdSavePrep, usbMsdSaveExec, NULL,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync usbMsdLoadPrep, usbMsdLoadExec, NULL);
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync if (RT_FAILURE(rc))
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync N_("MSD failed to register SSM save state handlers"));
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync return VINF_SUCCESS;
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync}
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync/**
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync * The USB Mass Storage Device (MSD) registration record.
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsyncconst PDMUSBREG g_UsbMsd =
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync{
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* u32Version */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDM_USBREG_VERSION,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* szName */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync "Msd",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pszDescription */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync "USB Mass Storage Device, one LUN.",
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* fFlags */
512ac71127c4fba43d0fd7ea838e96df5be2258bvboxsync PDM_USBREG_HIGHSPEED_CAPABLE | PDM_USBREG_EMULATED_DEVICE,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* cMaxInstances */
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync ~0U,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* cbInstance */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync sizeof(USBMSD),
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnConstruct */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdConstruct,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnDestruct */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdDestruct,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMInitComplete */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMPowerOn */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMReset */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdVMReset,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMSuspend */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdVMSuspend,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMResume */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnVMPowerOff */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdVMPowerOff,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnHotPlugged */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnHotUnplugged */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnDriverAttach */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdDriverAttach,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnDriverDetach */
f432a7a231aeafd3cf61a22bee6bff1ae5dfc51bvboxsync usbMsdDriverDetach,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnQueryInterface */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUsbReset */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUsbReset,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUsbGetCachedDescriptors */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUsbGetDescriptorCache,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUsbSetConfiguration */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUsbSetConfiguration,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUsbSetInterface */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUsbSetInterface,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUsbClearHaltedEndpoint */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUsbClearHaltedEndpoint,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUrbNew */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync NULL/*usbMsdUrbNew*/,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnQueue */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdQueue,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUrbCancel */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUrbCancel,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* pfnUrbReap */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync usbMsdUrbReap,
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync /* u32TheEnd */
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync PDM_USBREG_VERSION
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync};
82dbd9ef3e383af63ce3e6ac225143182711adffvboxsync