DrvSCSI.cpp revision f687f34bd232be13744edbc0cc5155fa5d4540ed
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/* $Id$ */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** @file
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync * VBox storage drivers: Generic SCSI command parser and execution driver
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync/*
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync *
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * General Public License (GPL) as published by the Free Software
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * additional information or have any questions.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/*******************************************************************************
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync* Header Files *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync//#define DEBUG
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define LOG_GROUP LOG_GROUP_DRV_SCSI
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <VBox/pdmdrv.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <VBox/pdmifs.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/pdmthread.h>
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <VBox/vscsi.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/assert.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/mem.h>
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#include <iprt/req.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/semaphore.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include <iprt/string.h>
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include <iprt/uuid.h>
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#include "Builtins.h"
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * SCSI driver instance data.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync *
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @implements PDMISCSICONNECTOR
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBLOCKASYNCPORT
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIMOUNTNOTIFY
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsynctypedef struct DRVSCSI
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer driver instance. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMDRVINS pDrvIns;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync /** Pointer to the attached driver's base interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIBASE pDrvBase;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the attached driver's block interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIBLOCK pDrvBlock;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the attached driver's async block interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIBLOCKASYNC pDrvBlockAsync;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the attached driver's block bios interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIBLOCKBIOS pDrvBlockBios;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the attached driver's mount interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMIMOUNT pDrvMount;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the SCSI port interface of the device above. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync PPDMISCSIPORT pDevScsiPort;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** pointer to the Led port interface of the dveice above. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PPDMILEDPORTS pLedPort;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** The scsi connector interface .*/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDMISCSICONNECTOR ISCSIConnector;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** The block port interface. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync PDMIBLOCKPORT IPort;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** The optional block async port interface. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync PDMIBLOCKASYNCPORT IPortAsync;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync#if 0 /* these interfaces aren't implemented */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** The mount notify interface. */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync PDMIMOUNTNOTIFY IMountNotify;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync#endif
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /** Fallback status LED state for this drive.
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync * This is used in case the device doesn't has a LED interface. */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync PDMLED Led;
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync /** Pointer to the status LED for this drive. */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync PPDMLED pLed;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
fa033b734cf3b131680f290326ccbbd23c42946bvboxsync /** VSCSI device handle. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIDEVICE hVScsiDevice;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** VSCSI LUN handle. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSILUN hVScsiLun;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** I/O callbacks. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSILUNIOCALLBACKS VScsiIoCallbacks;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** The dedicated I/O thread for the non async approach. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PPDMTHREAD pAsyncIOThread;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Queue for passing the requests to the thread. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PRTREQQUEUE pQueueRequests;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Request that we've left pending on wakeup or reset. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PRTREQ pPendingDummyReq;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /** Indicates whether PDMDrvHlpAsyncNotificationCompleted should be called by
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * any of the dummy functions. */
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync bool volatile fDummySignal;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync /** Release statistics: number of bytes written. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync STAMCOUNTER StatBytesWritten;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Release statistics: number of bytes read. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync STAMCOUNTER StatBytesRead;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Release statistics: Current I/O depth. */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync volatile uint32_t StatIoDepth;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync} DRVSCSI, *PDRVSCSI;
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync/** Converts a pointer to DRVSCSI::ISCSIConnector to a PDRVSCSI. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMISCSICONNECTOR_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, ISCSIConnector)) )
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync/** Converts a pointer to DRVSCSI::IPortAsync to a PDRVSCSI. */
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync#define PDMIBLOCKASYNCPORT_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, IPortAsync)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int drvscsiProcessRequestOne(PDRVSCSI pThis, VSCSIIOREQ hVScsiIoReq)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync int rc = VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIIOREQTXDIR enmTxDir;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync switch (enmTxDir)
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync case VSCSIIOREQTXDIR_FLUSH:
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = pThis->pDrvBlock->pfnFlush(pThis->pDrvBlock);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync break;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync }
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync case VSCSIIOREQTXDIR_READ:
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync case VSCSIIOREQTXDIR_WRITE:
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync uint64_t uOffset = 0;
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync size_t cbTransfer = 0;
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync size_t cbSeg = 0;
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync PCRTSGSEG paSeg = NULL;
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync unsigned cSeg = 0;
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer, &cSeg, &cbSeg,
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync &paSeg);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertRC(rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync while (cbTransfer && cSeg)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync size_t cbProcess = (cbTransfer < paSeg->cbSeg) ? cbTransfer : paSeg->cbSeg;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync Log(("%s: uOffset=%llu cbProcess=%u\n", __FUNCTION__, uOffset, cbProcess));
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = pThis->pDrvBlock->pfnRead(pThis->pDrvBlock, uOffset,
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync paSeg->pvSeg, cbProcess);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->pLed->Actual.s.fReading = 0;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync if (RT_FAILURE(rc))
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbProcess);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync else
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync {
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = pThis->pDrvBlock->pfnWrite(pThis->pDrvBlock, uOffset,
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync paSeg->pvSeg, cbProcess);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pThis->pLed->Actual.s.fWriting = 0;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (RT_FAILURE(rc))
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbProcess);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync /* Go to the next entry. */
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync uOffset += cbProcess;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync cbTransfer -= cbProcess;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync paSeg++;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync cSeg--;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync break;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync }
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync default:
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync AssertMsgFailed(("Invalid transfer direction %d\n", enmTxDir));
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync }
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync ASMAtomicDecU32(&pThis->StatIoDepth);
06696af9c885503e8dc3b1fe5836033c833e51a9vboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc);
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync return VINF_SUCCESS;
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync}
8137be2315957032783c582a2e5c2523ea96f9bcvboxsync
8137be2315957032783c582a2e5c2523ea96f9bcvboxsyncstatic int drvscsiGetSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pcbSize)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync *pcbSize = pThis->pDrvBlock->pfnGetSize(pThis->pDrvBlock);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int drvscsiTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rc)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDRVSCSI pThis = PDMIBLOCKASYNCPORT_2_DRVSCSI(pInterface);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIIOREQ hVScsiIoReq = (VSCSIIOREQ)pvUser;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIIOREQTXDIR enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogFlowFunc(("Request hVScsiIoReq=%#p completed\n", hVScsiIoReq));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pThis->pLed->Actual.s.fReading = 0;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync pThis->pLed->Actual.s.fWriting = 0;
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync else
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ASMAtomicDecU32(&pThis->StatIoDepth);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun,
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync void *pvScsiLunUser,
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync VSCSIIOREQ hVScsiIoReq)
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync{
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync int rc = VINF_SUCCESS;
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
fe813b3594039ba864493438e78ee0e7132bc445vboxsync
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync ASMAtomicIncU32(&pThis->StatIoDepth);
c6958b923ed12aadcf58ebbdbc80aadebbd9493evboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pThis->pDrvBlockAsync)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* async I/O path. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIIOREQTXDIR enmTxDir;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogFlowFunc(("Enqueuing hVScsiIoReq=%#p\n", hVScsiIoReq));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync switch (enmTxDir)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync case VSCSIIOREQTXDIR_FLUSH:
f379f813372b948dc6603b556f0ade7f838a5a65vboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = pThis->pDrvBlockAsync->pfnStartFlush(pThis->pDrvBlockAsync, hVScsiIoReq);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertMsgFailed(("%s: Failed to flush data %Rrc\n", __FUNCTION__, rc));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync break;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync case VSCSIIOREQTXDIR_READ:
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync case VSCSIIOREQTXDIR_WRITE:
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync uint64_t uOffset = 0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync size_t cbTransfer = 0;
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync size_t cbSeg = 0;
fe813b3594039ba864493438e78ee0e7132bc445vboxsync PCRTSGSEG paSeg = NULL;
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync unsigned cSeg = 0;
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync &cSeg, &cbSeg, &paSeg);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertRC(rc);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
362838d79d234a41380be42aae9118850cc3c929vboxsync pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
362838d79d234a41380be42aae9118850cc3c929vboxsync rc = pThis->pDrvBlockAsync->pfnStartRead(pThis->pDrvBlockAsync, uOffset,
362838d79d234a41380be42aae9118850cc3c929vboxsync paSeg, cSeg, cbTransfer,
362838d79d234a41380be42aae9118850cc3c929vboxsync hVScsiIoReq);
362838d79d234a41380be42aae9118850cc3c929vboxsync if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
bc36547e8dd3d35e5f756643a267bbe01e2c1d4cvboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer);
362838d79d234a41380be42aae9118850cc3c929vboxsync }
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync else
362838d79d234a41380be42aae9118850cc3c929vboxsync {
362838d79d234a41380be42aae9118850cc3c929vboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
362838d79d234a41380be42aae9118850cc3c929vboxsync rc = pThis->pDrvBlockAsync->pfnStartWrite(pThis->pDrvBlockAsync, uOffset,
362838d79d234a41380be42aae9118850cc3c929vboxsync paSeg, cSeg, cbTransfer,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync hVScsiIoReq);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer);
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync }
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync break;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync }
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync default:
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir));
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync }
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (rc == VINF_VD_ASYNC_IO_FINISHED)
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync {
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pThis->pLed->Actual.s.fReading = 0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->pLed->Actual.s.fWriting = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync else
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync ASMAtomicDecU32(&pThis->StatIoDepth);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync rc = VINF_SUCCESS;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync else if (RT_FAILURE(rc))
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync pThis->pLed->Actual.s.fReading = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->pLed->Actual.s.fWriting = 0;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync else
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync ASMAtomicDecU32(&pThis->StatIoDepth);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync else
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync AssertMsgFailed(("Invalid return code rc=%Rrc\n", rc));
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync }
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync else
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync {
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync /* I/O thread. */
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync rc = RTReqCallEx(pThis->pQueueRequests, NULL, 0, RTREQFLAGS_NO_WAIT,
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync (PFNRT)drvscsiProcessRequestOne, 2, pThis, hVScsiIoReq);
cbaf00194b28ee57e4aeee473f66f91f1be4e022vboxsync }
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync return rc;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync}
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsyncstatic void drvscsiVScsiReqCompleted(VSCSIDEVICE hVScsiDevice, void *pVScsiDeviceUser,
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync void *pVScsiReqUser, int rcReq)
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDRVSCSI pThis = (PDRVSCSI)pVScsiDeviceUser;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->pDevScsiPort->pfnSCSIRequestCompleted(pThis->pDevScsiPort, (PPDMSCSIREQUEST)pVScsiReqUser,
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync rcReq);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync}
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/**
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync * Dummy request function used by drvscsiReset to wait for all pending requests
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync * to complete prior to the device reset.
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync *
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync * @param pThis Pointer to the instace data.
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync * @returns VINF_SUCCESS.
ddab1f70f4034896cebf5e6af5a492ac46218346vboxsync */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncstatic int drvscsiAsyncIOLoopSyncCallback(PDRVSCSI pThis)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pThis->fDummySignal)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync}
cba6719bd64ec749967bbe931230452664109857vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync * Request function to wakeup the thread.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param pThis Pointer to the instace data.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VWRN_STATE_CHANGED.
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int drvscsiAsyncIOLoopWakeupFunc(PDRVSCSI pThis)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pThis->fDummySignal)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return VWRN_STATE_CHANGED;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync}
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync/**
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * The thread function which processes the requests asynchronously.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync *
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @returns VBox status code.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @param pDrvIns Pointer to the driver instance data.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync * @param pThread Pointer to the thread instance data.
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync */
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsyncstatic int drvscsiAsyncIOLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync int rc = VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
0f1e77149ab5ab40fa2bd74a5330e087416b3c7bvboxsync LogFlowFunc(("Entering async IO loop.\n"));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VINF_SUCCESS;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = RTReqProcess(pThis->pQueueRequests, RT_INDEFINITE_WAIT);
cba6719bd64ec749967bbe931230452664109857vboxsync AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc));
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync }
30adc6dd25ed9fef4d800a6d9f1ab7e765b4c340vboxsync
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync return VINF_SUCCESS;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/**
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync * Deals with any pending dummy request
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync *
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @returns true if no pending dummy request, false if still pending.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @param pThis The instance data.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @param cMillies The number of milliseconds to wait for any
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync * pending request to finish.
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync */
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsyncstatic bool drvscsiAsyncIOLoopNoPendingDummy(PDRVSCSI pThis, uint32_t cMillies)
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync{
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync if (!pThis->pPendingDummyReq)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return true;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int rc = RTReqWait(pThis->pPendingDummyReq, cMillies);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync if (RT_FAILURE(rc))
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return false;
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync RTReqFree(pThis->pPendingDummyReq);
dd97657cc7e8460edff31ebcff4c9d19bf8ad694vboxsync pThis->pPendingDummyReq = NULL;
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync return true;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync}
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsyncstatic int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync PRTREQ pReq;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync int rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertMsgReturn(pThis->pQueueRequests, ("pQueueRequests is NULL\n"), VERR_INVALID_STATE);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync {
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return VERR_TIMEOUT;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = RTReqCall(pThis->pQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 1, pThis);
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync if (RT_SUCCESS(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RTReqFree(pReq);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync else
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync {
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync pThis->pPendingDummyReq = pReq;
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync }
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/* -=-=-=-=- ISCSIConnector -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync/** @copydoc PDMISCSICONNECTOR::pfnSCSIRequestSend. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic DECLCALLBACK(int) drvscsiRequestSend(PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync{
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync int rc;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PDRVSCSI pThis = PDMISCSICONNECTOR_2_DRVSCSI(pInterface);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync VSCSIREQ hVScsiReq;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync rc = VSCSIDeviceReqCreate(pThis->hVScsiDevice, &hVScsiReq,
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync pSCSIRequest->uLogicalUnit,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->pbCDB,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->cbCDB,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->cbScatterGather,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->cScatterGatherEntries,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->paScatterGatherHead,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->pbSenseBuffer,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest->cbSenseBuffer,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pSCSIRequest);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (RT_FAILURE(rc))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return rc;
cba6719bd64ec749967bbe931230452664109857vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync rc = VSCSIDeviceReqEnqueue(pThis->hVScsiDevice, hVScsiReq);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync return rc;
cba6719bd64ec749967bbe931230452664109857vboxsync}
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync/* -=-=-=-=- IBase -=-=-=-=- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync
cba6719bd64ec749967bbe931230452664109857vboxsync/**
cba6719bd64ec749967bbe931230452664109857vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync */
static DECLCALLBACK(void *) drvscsiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSICONNECTOR, &pThis->ISCSIConnector);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKPORT, &pThis->IPort);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNCPORT, &pThis->IPortAsync);
return NULL;
}
/**
* Worker for drvscsiReset, drvscsiSuspend and drvscsiPowerOff.
*
* @param pDrvIns The driver instance.
* @param pfnAsyncNotify The async callback.
*/
static void drvscsiR3ResetOrSuspendOrPowerOff(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!pThis->pQueueRequests)
return;
ASMAtomicWriteBool(&pThis->fDummySignal, true);
if (drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
{
if (!RTReqIsBusy(pThis->pQueueRequests))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
return;
}
PRTREQ pReq;
int rc = RTReqCall(pThis->pQueueRequests, &pReq, 0 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 1, pThis);
if (RT_SUCCESS(rc))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
RTReqFree(pReq);
return;
}
pThis->pPendingDummyReq = pReq;
}
PDMDrvHlpSetAsyncNotification(pDrvIns, pfnAsyncNotify);
}
/**
* Callback employed by drvscsiSuspend and drvscsiPowerOff.
*
* @returns true if we've quiesced, false if we're still working.
* @param pDrvIns The driver instance.
*/
static DECLCALLBACK(bool) drvscsiIsAsyncSuspendOrPowerOffDone(PPDMDRVINS pDrvIns)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
return false;
ASMAtomicWriteBool(&pThis->fDummySignal, false);
PDMR3ThreadSuspend(pThis->pAsyncIOThread);
return true;
}
/**
* @copydoc FNPDMDRVPOWEROFF
*/
static DECLCALLBACK(void) drvscsiPowerOff(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
}
/**
* @copydoc FNPDMDRVSUSPEND
*/
static DECLCALLBACK(void) drvscsiSuspend(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
}
/**
* Callback employed by drvscsiReset.
*
* @returns true if we've quiesced, false if we're still working.
* @param pDrvIns The driver instance.
*/
static DECLCALLBACK(bool) drvscsiIsAsyncResetDone(PPDMDRVINS pDrvIns)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
return false;
ASMAtomicWriteBool(&pThis->fDummySignal, false);
return true;
}
/**
* @copydoc FNPDMDRVRESET
*/
static DECLCALLBACK(void) drvscsiReset(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncResetDone);
}
/**
* Destruct a driver instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvscsiDestruct(PPDMDRVINS pDrvIns)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
if (pThis->pQueueRequests)
{
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 100 /*ms*/))
LogRel(("drvscsiDestruct#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
int rc = RTReqDestroyQueue(pThis->pQueueRequests);
AssertMsgRC(rc, ("Failed to destroy queue rc=%Rrc\n", rc));
}
/* Free the VSCSI device and LUN handle. */
VSCSILUN hVScsiLun;
int rc = VSCSIDeviceLunDetach(pThis->hVScsiDevice, 0, &hVScsiLun);
AssertRC(rc);
Assert(hVScsiLun == pThis->hVScsiLun);
rc = VSCSILunDestroy(hVScsiLun);
AssertRC(rc);
rc = VSCSIDeviceDestroy(pThis->hVScsiDevice);
AssertRC(rc);
}
/**
* Construct a block driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg));
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
/*
* Initialize the instance data.
*/
pThis->pDrvIns = pDrvIns;
pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend;
pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface;
pThis->IPortAsync.pfnTransferCompleteNotify = drvscsiTransferCompleteNotify;
/*
* Try attach driver below and query it's block interface.
*/
int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase);
AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc);
/*
* Query the block and blockbios interfaces.
*/
pThis->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCK);
if (!pThis->pDrvBlock)
{
AssertMsgFailed(("Configuration error: No block interface!\n"));
return VERR_PDM_MISSING_INTERFACE;
}
pThis->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKBIOS);
if (!pThis->pDrvBlockBios)
{
AssertMsgFailed(("Configuration error: No block BIOS interface!\n"));
return VERR_PDM_MISSING_INTERFACE;
}
/* Query the SCSI port interface above. */
pThis->pDevScsiPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISCSIPORT);
AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE);
pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT);
/* Query the optional LED interface above. */
pThis->pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
if (pThis->pLedPort != NULL)
{
/* Get The Led. */
rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed);
if (RT_FAILURE(rc))
pThis->pLed = &pThis->Led;
}
else
pThis->pLed = &pThis->Led;
/* Try to get the optional async block interface. */
pThis->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKASYNC);
PDMBLOCKTYPE enmType = pThis->pDrvBlock->pfnGetType(pThis->pDrvBlock);
if (enmType != PDMBLOCKTYPE_HARD_DISK)
return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS,
N_("Only hard disks are currently supported as SCSI devices (enmType=%d)"),
enmType);
/* Create VSCSI device and LUN. */
pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize;
pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue;
rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n"), rc);
rc = VSCSILunCreate(&pThis->hVScsiLun, VSCSILUNTYPE_SBC, &pThis->VScsiIoCallbacks,
pThis);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI LUN rc=%Rrc\n"), rc);
rc = VSCSIDeviceLunAttach(pThis->hVScsiDevice, pThis->hVScsiLun, 0);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to attached the LUN to the SCSI device\n"), rc);
/* Create request queue. */
rc = RTReqCreateQueue(&pThis->pQueueRequests);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc);
/* Register statistics counter. */
/** @todo aeichner: Find a way to put the instance number of the attached
* controller device when we support more than one controller of the same type.
* At the moment we have the 0 hardcoded. */
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
"Amount of data read.", "/Devices/SCSI0/%d/ReadBytes", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
"Amount of data written.", "/Devices/SCSI0/%d/WrittenBytes", pDrvIns->iInstance);
pThis->StatIoDepth = 0;
PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->StatIoDepth, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
"Number of active tasks.", "/Devices/SCSI0/%d/IoDepth", pDrvIns->iInstance);
/* Create I/O thread. */
rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsiAsyncIOLoop,
drvscsiAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO");
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n"), rc);
return VINF_SUCCESS;
}
/**
* SCSI driver registration record.
*/
const PDMDRVREG g_DrvSCSI =
{
/* u32Version */
PDM_DRVREG_VERSION,
/* szName */
"SCSI",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Generic SCSI driver.",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
/* fClass. */
PDM_DRVREG_CLASS_SCSI,
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(DRVSCSI),
/* pfnConstruct */
drvscsiConstruct,
/* pfnDestruct */
drvscsiDestruct,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
drvscsiReset,
/* pfnSuspend */
drvscsiSuspend,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
drvscsiPowerOff,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
PDM_DRVREG_VERSION
};