DrvSCSI.cpp revision 29914189ae23645ef08a2f8477f28fd6f440a936
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/* $Id$ */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** @file
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * VBox storage drivers: Generic SCSI command parser and execution driver
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/*
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2012 Oracle Corporation
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * available from http://www.virtualbox.org. This file is free software;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * General Public License (GPL) as published by the Free Software
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/*******************************************************************************
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync* Header Files *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync*******************************************************************************/
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync//#define DEBUG
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define LOG_GROUP LOG_GROUP_DRV_SCSI
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <VBox/vmm/pdmdrv.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <VBox/vmm/pdmifs.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <VBox/vmm/pdmthread.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <VBox/vscsi.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <VBox/scsi.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/asm.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/assert.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/mem.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/req.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/semaphore.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/string.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include <iprt/uuid.h>
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#include "VBoxDD.h"
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** The maximum number of release log entries per device. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define MAX_LOG_REL_ERRORS 1024
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/**
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * SCSI driver instance data.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @implements PDMISCSICONNECTOR
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @implements PDMIBLOCKASYNCPORT
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @implements PDMIMOUNTNOTIFY
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsynctypedef struct DRVSCSI
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Pointer driver instance. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PPDMDRVINS pDrvIns;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the attached driver's base interface. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMIBASE pDrvBase;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the attached driver's block interface. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMIBLOCK pDrvBlock;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the attached driver's async block interface. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMIBLOCKASYNC pDrvBlockAsync;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the attached driver's block bios interface. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMIBLOCKBIOS pDrvBlockBios;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the attached driver's mount interface. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMIMOUNT pDrvMount;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** Pointer to the SCSI port interface of the device above. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMISCSIPORT pDevScsiPort;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** pointer to the Led port interface of the dveice above. */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PPDMILEDPORTS pLedPort;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync /** The scsi connector interface .*/
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PDMISCSICONNECTOR ISCSIConnector;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** The block port interface. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMIBLOCKPORT IPort;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** The optional block async port interface. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMIBLOCKASYNCPORT IPortAsync;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** The mount notify interface. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMIMOUNTNOTIFY IMountNotify;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Fallback status LED state for this drive.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * This is used in case the device doesn't has a LED interface. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMLED Led;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Pointer to the status LED for this drive. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PPDMLED pLed;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** VSCSI device handle. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIDEVICE hVScsiDevice;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** VSCSI LUN handle. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSILUN hVScsiLun;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** I/O callbacks. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSILUNIOCALLBACKS VScsiIoCallbacks;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** The dedicated I/O thread for the non async approach. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PPDMTHREAD pAsyncIOThread;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Queue for passing the requests to the thread. */
09e11be404479b989812ad9da85a16f3654ab320vboxsync RTREQQUEUE hQueueRequests;
09e11be404479b989812ad9da85a16f3654ab320vboxsync /** Request that we've left pending on wakeup or reset. */
09e11be404479b989812ad9da85a16f3654ab320vboxsync PRTREQ pPendingDummyReq;
09e11be404479b989812ad9da85a16f3654ab320vboxsync /** Indicates whether PDMDrvHlpAsyncNotificationCompleted should be called by
09e11be404479b989812ad9da85a16f3654ab320vboxsync * any of the dummy functions. */
09e11be404479b989812ad9da85a16f3654ab320vboxsync bool volatile fDummySignal;
09e11be404479b989812ad9da85a16f3654ab320vboxsync /** Release statistics: number of bytes written. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync STAMCOUNTER StatBytesWritten;
09e11be404479b989812ad9da85a16f3654ab320vboxsync /** Release statistics: number of bytes read. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync STAMCOUNTER StatBytesRead;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Release statistics: Current I/O depth. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync volatile uint32_t StatIoDepth;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Errors printed in the release log. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync unsigned cErrors;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Mark the drive as having a non-rotational medium (i.e. as a SSD). */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync bool fNonRotational;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /** Medium is readonly */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync bool fReadonly;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync} DRVSCSI, *PDRVSCSI;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** Converts a pointer to DRVSCSI::ISCSIConnector to a PDRVSCSI. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define PDMISCSICONNECTOR_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, ISCSIConnector)) )
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** Converts a pointer to DRVSCSI::IPortAsync to a PDRVSCSI. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define PDMIBLOCKASYNCPORT_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, IPortAsync)) )
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** Converts a pointer to DRVSCSI::IMountNotify to PDRVSCSI. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define PDMIMOUNTNOTIFY_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, IMountNotify)) )
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/** Converts a pointer to DRVSCSI::IPort to a PDRVSCSI. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync#define PDMIBLOCKPORT_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, IPort)) )
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic bool drvscsiIsRedoPossible(int rc)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync{
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if ( rc == VERR_DISK_FULL
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync || rc == VERR_FILE_TOO_BIG
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync || rc == VERR_BROKEN_PIPE
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync || rc == VERR_NET_CONNECTION_REFUSED)
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync return true;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return false;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic int drvscsiProcessRequestOne(PDRVSCSI pThis, VSCSIIOREQ hVScsiIoReq)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync int rc = VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIOREQTXDIR enmTxDir;
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync switch (enmTxDir)
09e11be404479b989812ad9da85a16f3654ab320vboxsync {
09e11be404479b989812ad9da85a16f3654ab320vboxsync case VSCSIIOREQTXDIR_FLUSH:
09e11be404479b989812ad9da85a16f3654ab320vboxsync {
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync rc = pThis->pDrvBlock->pfnFlush(pThis->pDrvBlock);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if ( RT_FAILURE(rc)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
36f105528f08a78e2eff142de3d160b66dffd496vboxsync pThis->pDrvIns->iInstance, rc));
36f105528f08a78e2eff142de3d160b66dffd496vboxsync break;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_READ:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_WRITE:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync uint64_t uOffset = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbTransfer = 0;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync size_t cbSeg = 0;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PCRTSGSEG paSeg = NULL;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync unsigned cSeg = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer, &cSeg, &cbSeg,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync &paSeg);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync AssertRC(rc);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync while (cbTransfer && cSeg)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbProcess = (cbTransfer < paSeg->cbSeg) ? cbTransfer : paSeg->cbSeg;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync Log(("%s: uOffset=%llu cbProcess=%u\n", __FUNCTION__, uOffset, cbProcess));
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync {
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync rc = pThis->pDrvBlock->pfnRead(pThis->pDrvBlock, uOffset,
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync paSeg->pvSeg, cbProcess);
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync pThis->pLed->Actual.s.fReading = 0;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync if (RT_FAILURE(rc))
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync break;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbProcess);
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = pThis->pDrvBlock->pfnWrite(pThis->pDrvBlock, uOffset,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync paSeg->pvSeg, cbProcess);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Actual.s.fWriting = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (RT_FAILURE(rc))
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync break;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbProcess);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync /* Go to the next entry. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync uOffset += cbProcess;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync cbTransfer -= cbProcess;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync paSeg++;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync cSeg--;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if ( RT_FAILURE(rc)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDrvIns->iInstance,
0aa150e34ed49f14aaa37368c2e6999ec89e5f43vboxsync enmTxDir == VSCSIIOREQTXDIR_READ
0aa150e34ed49f14aaa37368c2e6999ec89e5f43vboxsync ? "Read"
0aa150e34ed49f14aaa37368c2e6999ec89e5f43vboxsync : "Write",
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync uOffset,
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync cbTransfer, rc));
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync break;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
09e11be404479b989812ad9da85a16f3654ab320vboxsync case VSCSIIOREQTXDIR_UNMAP:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PCRTRANGE paRanges;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync unsigned cRanges;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges);
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync AssertRC(rc);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = pThis->pDrvBlock->pfnDiscard(pThis->pDrvBlock, paRanges, cRanges);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync pThis->pLed->Actual.s.fWriting = 0;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if ( RT_FAILURE(rc)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: Unmap returned rc=%Rrc\n",
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync pThis->pDrvIns->iInstance, rc));
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync break;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync }
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync default:
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync AssertMsgFailed(("Invalid transfer direction %d\n", enmTxDir));
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync }
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync if (RT_SUCCESS(rc))
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc, false /* fRedoPossible */);
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync else
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc, drvscsiIsRedoPossible(rc));
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync return VINF_SUCCESS;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic DECLCALLBACK(int) drvscsiGetSize(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pcbSize)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *pcbSize = pThis->pDrvBlock->pfnGetSize(pThis->pDrvBlock);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic DECLCALLBACK(int) drvscsiSetLock(VSCSILUN hVScsiLun, void *pvScsiLunUser, bool fLocked)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if (fLocked)
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync pThis->pDrvMount->pfnLock(pThis->pDrvMount);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync else
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync pThis->pDrvMount->pfnUnlock(pThis->pDrvMount);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic int drvscsiTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rc)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDRVSCSI pThis = PDMIBLOCKASYNCPORT_2_DRVSCSI(pInterface);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIOREQ hVScsiIoReq = (VSCSIIOREQ)pvUser;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIOREQTXDIR enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogFlowFunc(("Request hVScsiIoReq=%#p completed\n", hVScsiIoReq));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Actual.s.fReading = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if ( enmTxDir == VSCSIIOREQTXDIR_WRITE
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync || enmTxDir == VSCSIIOREQTXDIR_UNMAP)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Actual.s.fWriting = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (RT_SUCCESS(rc))
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc, false /* fRedoPossible */);
c307f0d7384bfc4d19d2290a28be89868f02f42avboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->cErrors++;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (pThis->cErrors < MAX_LOG_REL_ERRORS)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_FLUSH)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDrvIns->iInstance, rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if (enmTxDir == VSCSIIOREQTXDIR_UNMAP)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: Unmap returned rc=%Rrc\n",
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDrvIns->iInstance, rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync uint64_t uOffset = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbTransfer = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbSeg = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PCRTSGSEG paSeg = NULL;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync unsigned cSeg = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync &cSeg, &cbSeg, &paSeg);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDrvIns->iInstance,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync enmTxDir == VSCSIIOREQTXDIR_READ
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync ? "Read"
09e11be404479b989812ad9da85a16f3654ab320vboxsync : "Write",
09e11be404479b989812ad9da85a16f3654ab320vboxsync uOffset,
09e11be404479b989812ad9da85a16f3654ab320vboxsync cbTransfer, rc));
09e11be404479b989812ad9da85a16f3654ab320vboxsync }
09e11be404479b989812ad9da85a16f3654ab320vboxsync }
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc, drvscsiIsRedoPossible(rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync return VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic DECLCALLBACK(int) drvscsiReqTransferEnqueue(VSCSILUN hVScsiLun,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync void *pvScsiLunUser,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIOREQ hVScsiIoReq)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync int rc = VINF_SUCCESS;
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync if (pThis->pDrvBlockAsync)
09e11be404479b989812ad9da85a16f3654ab320vboxsync {
09e11be404479b989812ad9da85a16f3654ab320vboxsync /* async I/O path. */
09e11be404479b989812ad9da85a16f3654ab320vboxsync VSCSIIOREQTXDIR enmTxDir;
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync LogFlowFunc(("Enqueuing hVScsiIoReq=%#p\n", hVScsiIoReq));
09e11be404479b989812ad9da85a16f3654ab320vboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync enmTxDir = VSCSIIoReqTxDirGet(hVScsiIoReq);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync switch (enmTxDir)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_FLUSH:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = pThis->pDrvBlockAsync->pfnStartFlush(pThis->pDrvBlockAsync, hVScsiIoReq);
c7ff622115966b69b482bd2896662e40d823b22fvboxsync if ( RT_FAILURE(rc)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync && rc != VERR_VD_ASYNC_IO_IN_PROGRESS
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
704377ab2f9056b54fb01a500448f54b38bb3001vboxsync pThis->pDrvIns->iInstance, rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync break;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_UNMAP:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PCRTRANGE paRanges;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync unsigned cRanges;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertRC(rc);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = pThis->pDrvBlockAsync->pfnStartDiscard(pThis->pDrvBlockAsync, paRanges, cRanges, hVScsiIoReq);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if ( RT_FAILURE(rc)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync && rc != VERR_VD_ASYNC_IO_IN_PROGRESS
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync LogRel(("SCSI#%u: Discard returned rc=%Rrc\n",
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDrvIns->iInstance, rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync break;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_READ:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync case VSCSIIOREQTXDIR_WRITE:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync uint64_t uOffset = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbTransfer = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync size_t cbSeg = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PCRTSGSEG paSeg = NULL;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync unsigned cSeg = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VSCSIIoReqParamsGet(hVScsiIoReq, &uOffset, &cbTransfer,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync &cSeg, &cbSeg, &paSeg);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertRC(rc);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
d273db24f1a69abac22a9c2f9c8251e16b66c47fvboxsync {
5a7561300d631625bc381bcc85dd2087f34d0bf9vboxsync pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = pThis->pDrvBlockAsync->pfnStartRead(pThis->pDrvBlockAsync, uOffset,
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync paSeg, cSeg, cbTransfer,
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync hVScsiIoReq);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbTransfer);
c7ff622115966b69b482bd2896662e40d823b22fvboxsync }
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync else
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync {
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync rc = pThis->pDrvBlockAsync->pfnStartWrite(pThis->pDrvBlockAsync, uOffset,
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync paSeg, cSeg, cbTransfer,
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync hVScsiIoReq);
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbTransfer);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync }
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync if ( RT_FAILURE(rc)
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync && rc != VERR_VD_ASYNC_IO_IN_PROGRESS
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync LogRel(("SCSI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync pThis->pDrvIns->iInstance,
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync enmTxDir == VSCSIIOREQTXDIR_READ
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync ? "Read"
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync : "Write",
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync uOffset,
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync cbTransfer, rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync break;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync default:
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertMsgFailed(("Invalid transfer direction %u\n", enmTxDir));
09e11be404479b989812ad9da85a16f3654ab320vboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (rc == VINF_VD_ASYNC_IO_FINISHED)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Actual.s.fReading = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync pThis->pLed->Actual.s.fWriting = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIoReqCompleted(hVScsiIoReq, VINF_SUCCESS, false);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if (rc == VERR_VD_ASYNC_IO_IN_PROGRESS)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if (RT_FAILURE(rc))
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (enmTxDir == VSCSIIOREQTXDIR_READ)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pLed->Actual.s.fReading = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
c7ff622115966b69b482bd2896662e40d823b22fvboxsync pThis->pLed->Actual.s.fWriting = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertMsg(enmTxDir == VSCSIIOREQTXDIR_FLUSH, ("Invalid transfer direction %u\n", enmTxDir));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync VSCSIIoReqCompleted(hVScsiIoReq, rc, drvscsiIsRedoPossible(rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync AssertMsgFailed(("Invalid return code rc=%Rrc\n", rc));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync else
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
c7ff622115966b69b482bd2896662e40d823b22fvboxsync /* I/O thread. */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rc = RTReqQueueCallEx(pThis->hQueueRequests, NULL, 0, RTREQFLAGS_NO_WAIT,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync (PFNRT)drvscsiProcessRequestOne, 2, pThis, hVScsiIoReq);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return rc;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic DECLCALLBACK(int) drvscsiGetFeatureFlags(VSCSILUN hVScsiLun,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync void *pvScsiLunUser,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync uint64_t *pfFeatures)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync int rc = VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDRVSCSI pThis = (PDRVSCSI)pvScsiLunUser;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *pfFeatures = 0;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if ( pThis->pDrvBlock->pfnDiscard
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync || ( pThis->pDrvBlockAsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync && pThis->pDrvBlockAsync->pfnStartDiscard))
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *pfFeatures |= VSCSI_LUN_FEATURE_UNMAP;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync if (pThis->fNonRotational)
09e11be404479b989812ad9da85a16f3654ab320vboxsync *pfFeatures |= VSCSI_LUN_FEATURE_NON_ROTATIONAL;
09e11be404479b989812ad9da85a16f3654ab320vboxsync
09e11be404479b989812ad9da85a16f3654ab320vboxsync if (pThis->fReadonly)
09e11be404479b989812ad9da85a16f3654ab320vboxsync *pfFeatures |= VSCSI_LUN_FEATURE_READONLY;
09e11be404479b989812ad9da85a16f3654ab320vboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VINF_SUCCESS;
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic void drvscsiVScsiReqCompleted(VSCSIDEVICE hVScsiDevice, void *pVScsiDeviceUser,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync void *pVScsiReqUser, int rcScsiCode, bool fRedoPossible,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync int rcReq)
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDRVSCSI pThis = (PDRVSCSI)pVScsiDeviceUser;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync ASMAtomicDecU32(&pThis->StatIoDepth);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync pThis->pDevScsiPort->pfnSCSIRequestCompleted(pThis->pDevScsiPort, (PPDMSCSIREQUEST)pVScsiReqUser,
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync rcScsiCode, fRedoPossible, rcReq);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (RT_UNLIKELY(pThis->fDummySignal) && !pThis->StatIoDepth)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/**
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * Dummy request function used by drvscsiReset to wait for all pending requests
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * to complete prior to the device reset.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @param pThis Pointer to the instance data.
64babf0f32eaf36212d54af4a3ce5fe193b24825vboxsync * @returns VINF_SUCCESS.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic int drvscsiAsyncIOLoopSyncCallback(PDRVSCSI pThis)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (pThis->fDummySignal)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VINF_SUCCESS;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/**
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * Request function to wakeup the thread.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @param pThis Pointer to the instance data.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @returns VWRN_STATE_CHANGED.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync */
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsyncstatic int drvscsiAsyncIOLoopWakeupFunc(PDRVSCSI pThis)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync{
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync if (pThis->fDummySignal)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VWRN_STATE_CHANGED;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync}
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync/**
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * The thread function which processes the requests asynchronously.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync *
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @returns VBox status code.
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync * @param pDrvIns Pointer to the driver instance data.
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync * @param pThread Pointer to the thread instance data.
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsyncstatic int drvscsiAsyncIOLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync{
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync int rc = VINF_SUCCESS;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync LogFlowFunc(("Entering async IO loop.\n"));
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync return VINF_SUCCESS;
1f963f01f4f9a3848e72d4748c4f36feb715dba3vboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync {
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync rc = RTReqQueueProcess(pThis->hQueueRequests, RT_INDEFINITE_WAIT);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc));
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync }
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync return VINF_SUCCESS;
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync}
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync/**
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync * Deals with any pending dummy request
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync *
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync * @returns true if no pending dummy request, false if still pending.
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync * @param pThis The instance data.
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync * @param cMillies The number of milliseconds to wait for any
21a96ae495634bdc8bbcc6ed7d8d727a1b9430f5vboxsync * pending request to finish.
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync */
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsyncstatic bool drvscsiAsyncIOLoopNoPendingDummy(PDRVSCSI pThis, uint32_t cMillies)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync{
36f105528f08a78e2eff142de3d160b66dffd496vboxsync if (!pThis->pPendingDummyReq)
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return true;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync int rc = RTReqWait(pThis->pPendingDummyReq, cMillies);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if (RT_FAILURE(rc))
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync return false;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync RTReqRelease(pThis->pPendingDummyReq);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync pThis->pPendingDummyReq = NULL;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync return true;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync}
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsyncstatic int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync{
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync PRTREQ pReq;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync int rc;
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync AssertMsgReturn(pThis->hQueueRequests != NIL_RTREQQUEUE, ("hQueueRequests is NULL\n"), VERR_INVALID_STATE);
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */))
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync {
db2893e30b129fbadd201b8f56cd7bc1974b395dvboxsync LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync return VERR_TIMEOUT;
66b15150e35f27f9499bb0a8399e452d6a04895dvboxsync }
rc = RTReqQueueCall(pThis->hQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 1, pThis);
if (RT_SUCCESS(rc))
RTReqRelease(pReq);
else
{
pThis->pPendingDummyReq = pReq;
LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq));
}
return rc;
}
/* -=-=-=-=- ISCSIConnector -=-=-=-=- */
#ifdef DEBUG
/**
* Dumps a SCSI request structure for debugging purposes.
*
* @returns nothing.
* @param pRequest Pointer to the request to dump.
*/
static void drvscsiDumpScsiRequest(PPDMSCSIREQUEST pRequest)
{
Log(("Dump for pRequest=%#p Command: %s\n", pRequest, SCSICmdText(pRequest->pbCDB[0])));
Log(("cbCDB=%u\n", pRequest->cbCDB));
for (uint32_t i = 0; i < pRequest->cbCDB; i++)
Log(("pbCDB[%u]=%#x\n", i, pRequest->pbCDB[i]));
Log(("cbScatterGather=%u\n", pRequest->cbScatterGather));
Log(("cScatterGatherEntries=%u\n", pRequest->cScatterGatherEntries));
/* Print all scatter gather entries. */
for (uint32_t i = 0; i < pRequest->cScatterGatherEntries; i++)
{
Log(("ScatterGatherEntry[%u].cbSeg=%u\n", i, pRequest->paScatterGatherHead[i].cbSeg));
Log(("ScatterGatherEntry[%u].pvSeg=%#p\n", i, pRequest->paScatterGatherHead[i].pvSeg));
}
Log(("pvUser=%#p\n", pRequest->pvUser));
}
#endif
/** @copydoc PDMISCSICONNECTOR::pfnSCSIRequestSend. */
static DECLCALLBACK(int) drvscsiRequestSend(PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)
{
int rc;
PDRVSCSI pThis = PDMISCSICONNECTOR_2_DRVSCSI(pInterface);
VSCSIREQ hVScsiReq;
#ifdef DEBUG
drvscsiDumpScsiRequest(pSCSIRequest);
#endif
rc = VSCSIDeviceReqCreate(pThis->hVScsiDevice, &hVScsiReq,
pSCSIRequest->uLogicalUnit,
pSCSIRequest->pbCDB,
pSCSIRequest->cbCDB,
pSCSIRequest->cbScatterGather,
pSCSIRequest->cScatterGatherEntries,
pSCSIRequest->paScatterGatherHead,
pSCSIRequest->pbSenseBuffer,
pSCSIRequest->cbSenseBuffer,
pSCSIRequest);
if (RT_FAILURE(rc))
return rc;
ASMAtomicIncU32(&pThis->StatIoDepth);
rc = VSCSIDeviceReqEnqueue(pThis->hVScsiDevice, hVScsiReq);
return rc;
}
/* -=-=-=-=- IBase -=-=-=-=- */
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
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, PDMIMOUNT, pThis->pDrvMount);
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, PDMIMOUNTNOTIFY, &pThis->IMountNotify);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKASYNCPORT, &pThis->IPortAsync);
return NULL;
}
static DECLCALLBACK(int) drvscsiQueryDeviceLocation(PPDMIBLOCKPORT pInterface, const char **ppcszController,
uint32_t *piInstance, uint32_t *piLUN)
{
PDRVSCSI pThis = PDMIBLOCKPORT_2_DRVSCSI(pInterface);
return pThis->pDevScsiPort->pfnQueryDeviceLocation(pThis->pDevScsiPort, ppcszController,
piInstance, piLUN);
}
/**
* Called when media is mounted.
*
* @param pInterface Pointer to the interface structure containing the called function pointer.
*/
static DECLCALLBACK(void) drvscsiMountNotify(PPDMIMOUNTNOTIFY pInterface)
{
PDRVSCSI pThis = PDMIMOUNTNOTIFY_2_DRVSCSI(pInterface);
LogFlowFunc(("mounting LUN#%p\n", pThis->hVScsiLun));
/* Ignore the call if we're called while being attached. */
if (!pThis->pDrvBlock)
return;
/* Let the LUN know that a medium was mounted. */
VSCSILunMountNotify(pThis->hVScsiLun);
}
/**
* Called when media is unmounted
*
* @param pInterface Pointer to the interface structure containing the called function pointer.
*/
static DECLCALLBACK(void) drvscsiUnmountNotify(PPDMIMOUNTNOTIFY pInterface)
{
PDRVSCSI pThis = PDMIMOUNTNOTIFY_2_DRVSCSI(pInterface);
LogFlowFunc(("unmounting LUN#%p\n", pThis->hVScsiLun));
/* Let the LUN know that the medium was unmounted. */
VSCSILunUnmountNotify(pThis->hVScsiLun);
}
/**
* 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->pDrvBlockAsync)
{
if (pThis->hQueueRequests != NIL_RTREQQUEUE)
return;
ASMAtomicWriteBool(&pThis->fDummySignal, true);
if (drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
{
if (!RTReqQueueIsBusy(pThis->hQueueRequests))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
return;
}
PRTREQ pReq;
int rc = RTReqQueueCall(pThis->hQueueRequests, &pReq, 0 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 1, pThis);
if (RT_SUCCESS(rc))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
RTReqRelease(pReq);
return;
}
pThis->pPendingDummyReq = pReq;
}
}
else
{
if (pThis->StatIoDepth > 0)
{
ASMAtomicWriteBool(&pThis->fDummySignal, true);
}
return;
}
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 (pThis->pDrvBlockAsync)
{
if (pThis->StatIoDepth > 0)
return false;
else
return true;
}
else
{
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 (pThis->pDrvBlockAsync)
{
if (pThis->StatIoDepth > 0)
return false;
else
return true;
}
else
{
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->hQueueRequests != NIL_RTREQQUEUE)
{
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 100 /*ms*/))
LogRel(("drvscsiDestruct#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
int rc = RTReqQueueDestroy(pThis->hQueueRequests);
AssertMsgRC(rc, ("Failed to destroy queue rc=%Rrc\n", rc));
pThis->hQueueRequests = NIL_RTREQQUEUE;
}
/* 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)
{
int rc = VINF_SUCCESS;
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg));
LogRelFunc(("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->IMountNotify.pfnMountNotify = drvscsiMountNotify;
pThis->IMountNotify.pfnUnmountNotify = drvscsiUnmountNotify;
pThis->IPort.pfnQueryDeviceLocation = drvscsiQueryDeviceLocation;
pThis->IPortAsync.pfnTransferCompleteNotify = drvscsiTransferCompleteNotify;
pThis->hQueueRequests = NIL_RTREQQUEUE;
/* 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);
/* 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;
/*
* Validate and read configuration.
*/
if (!CFGMR3AreValuesValid(pCfg, "NonRotationalMedium\0Readonly\0"))
return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
N_("SCSI configuration error: unknown option specified"));
rc = CFGMR3QueryBoolDef(pCfg, "NonRotationalMedium", &pThis->fNonRotational, false);
if (RT_FAILURE(rc))
return PDMDRV_SET_ERROR(pDrvIns, rc,
N_("SCSI configuration error: failed to read \"NonRotationalMedium\" as boolean"));
rc = CFGMR3QueryBoolDef(pCfg, "Readonly", &pThis->fReadonly, false);
if (RT_FAILURE(rc))
return PDMDRV_SET_ERROR(pDrvIns, rc,
N_("SCSI configuration error: failed to read \"Readonly\" as boolean"));
/*
* Try attach driver below and query it's block interface.
*/
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;
}
pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT);
/* Try to get the optional async block interface. */
pThis->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKASYNC);
PDMBLOCKTYPE enmType = pThis->pDrvBlock->pfnGetType(pThis->pDrvBlock);
VSCSILUNTYPE enmLunType;
switch (enmType)
{
case PDMBLOCKTYPE_HARD_DISK:
enmLunType = VSCSILUNTYPE_SBC;
break;
case PDMBLOCKTYPE_CDROM:
case PDMBLOCKTYPE_DVD:
enmLunType = VSCSILUNTYPE_MMC;
break;
default:
return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS,
N_("Only hard disks and CD/DVD-ROMs are currently supported as SCSI devices (enmType=%d)"),
enmType);
}
if ( ( enmType == PDMBLOCKTYPE_DVD
|| enmType == PDMBLOCKTYPE_CDROM)
&& !pThis->pDrvMount)
{
AssertMsgFailed(("Internal error: cdrom without a mountable interface\n"));
return VERR_INTERNAL_ERROR;
}
/* Create VSCSI device and LUN. */
pThis->VScsiIoCallbacks.pfnVScsiLunMediumGetSize = drvscsiGetSize;
pThis->VScsiIoCallbacks.pfnVScsiLunReqTransferEnqueue = drvscsiReqTransferEnqueue;
pThis->VScsiIoCallbacks.pfnVScsiLunGetFeatureFlags = drvscsiGetFeatureFlags;
pThis->VScsiIoCallbacks.pfnVScsiLunMediumSetLock = drvscsiSetLock;
rc = VSCSIDeviceCreate(&pThis->hVScsiDevice, drvscsiVScsiReqCompleted, pThis);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create VSCSI device rc=%Rrc\n"), rc);
rc = VSCSILunCreate(&pThis->hVScsiLun, enmLunType, &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);
//@todo: This is a very hacky way of telling the LUN whether a medium was mounted.
// The mount/unmount interface doesn't work in a very sensible manner!
if (pThis->pDrvMount)
{
if (pThis->pDrvBlock->pfnGetSize(pThis->pDrvBlock))
{
rc = VINF_SUCCESS; VSCSILunMountNotify(pThis->hVScsiLun);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being mounted\n"), rc);
}
else
{
rc = VINF_SUCCESS; VSCSILunUnmountNotify(pThis->hVScsiLun);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to notify the LUN of media being unmounted\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);
if (!pThis->pDrvBlockAsync)
{
/* Create request queue. */
rc = RTReqQueueCreate(&pThis->hQueueRequests);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc);
/* 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);
LogRel(("SCSI#%d: using normal I/O\n", pDrvIns->iInstance));
}
else
LogRel(("SCSI#%d: using async I/O\n", pDrvIns->iInstance));
if ( pThis->pDrvBlock->pfnDiscard
|| ( pThis->pDrvBlockAsync
&& pThis->pDrvBlockAsync->pfnStartDiscard))
LogRel(("SCSI#%d: Enabled UNMAP support\n"));
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 */
~0U,
/* 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
};