9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* $Id$ */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @file
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * VBox storage drivers: Host SCSI access driver.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*
b9b68f3564c772c4154e52dff6eac9a4763d82b6vboxsync * Copyright (C) 2006-2014 Oracle Corporation
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * available from http://www.virtualbox.org. This file is free software;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * General Public License (GPL) as published by the Free Software
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/*******************************************************************************
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync* Header Files *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync*******************************************************************************/
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync//#define DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define LOG_GROUP LOG_GROUP_DRV_SCSIHOST
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmdrv.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmifs.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pdmthread.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <VBox/scsi.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/assert.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#include <iprt/file.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/mem.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/req.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/string.h>
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync#include <iprt/uuid.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(RT_OS_LINUX)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <limits.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <scsi/sg.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync# include <sys/ioctl.h>
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include "VBoxDD.h"
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * SCSI driver instance data.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync *
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMISCSICONNECTOR
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsynctypedef struct DRVSCSIHOST
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer driver instance. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDRVINS pDrvIns;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Pointer to the SCSI port interface of the device above. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMISCSIPORT pDevScsiPort;
b9b68f3564c772c4154e52dff6eac9a4763d82b6vboxsync /** The SCSI connector interface. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDMISCSICONNECTOR ISCSIConnector;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** Path to the device file. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync char *pszDevicePath;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Handle to the device. */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTFILE hDeviceFile;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** The dedicated I/O thread. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMTHREAD pAsyncIOThread;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /** Queue for passing the requests to the thread. */
36411046d85fccaa66061120a064225fd1b5ae01vboxsync RTREQQUEUE hQueueRequests;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync} DRVSCSIHOST, *PDRVSCSIHOST;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** Converts a pointer to DRVSCSIHOST::ISCSIConnecotr to a PDRVSCSIHOST. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#define PDMISCSICONNECTOR_2_DRVSCSIHOST(pInterface) ( (PDRVSCSIHOST)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSIHOST, ISCSIConnector)) )
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Dumps a SCSI request structure for debugging purposes.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pRequest Pointer to the request to dump.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic void drvscsihostDumpScsiRequest(PPDMSCSIREQUEST pRequest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("Dump for pRequest=%#p Command: %s\n", pRequest, SCSICmdText(pRequest->pbCDB[0])));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("cbCDB=%u\n", pRequest->cbCDB));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < pRequest->cbCDB; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("pbCDB[%u]=%#x\n", i, pRequest->pbCDB[i]));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("cbScatterGather=%u\n", pRequest->cbScatterGather));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("cScatterGatherEntries=%u\n", pRequest->cScatterGatherEntries));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Print all scatter gather entries. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (uint32_t i = 0; i < pRequest->cScatterGatherEntries; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("ScatterGatherEntry[%u].cbSeg=%u\n", i, pRequest->paScatterGatherHead[i].cbSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("ScatterGatherEntry[%u].pvSeg=%#p\n", i, pRequest->paScatterGatherHead[i].pvSeg));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("pvUser=%#p\n", pRequest->pvUser));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Copy the content of a buffer to a scatter gather list
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * copying only the amount of data which fits into the
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * scatter gather list.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pRequest Pointer to the request which contains the S/G list entries.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pvBuf Pointer to the buffer which should be copied.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param cbBuf Size of the buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int drvscsihostScatterGatherListCopyFromBuffer(PPDMSCSIREQUEST pRequest, void *pvBuf, size_t cbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned cSGEntry = 0;
a9f41cb889f53e8407561a6155052c441eb0fc5fvboxsync PRTSGSEG pSGEntry = &pRequest->paScatterGatherHead[cSGEntry];
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uint8_t *pu8Buf = (uint8_t *)pvBuf;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (cSGEntry < pRequest->cScatterGatherEntries)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync size_t cbToCopy = (cbBuf < pSGEntry->cbSeg) ? cbBuf : pSGEntry->cbSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cbBuf -= cbToCopy;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We finished. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (!cbBuf)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Advance the buffer. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pu8Buf += cbToCopy;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Go to the next entry in the list. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pSGEntry++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync cSGEntry++;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Set the sense and advanced sense key in the buffer for error conditions.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pRequest Pointer to the request which contains the sense buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param uSCSISenseKey The sense key to set.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param uSCSIASC The advanced sense key to set.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) drvscsiCmdError(PPDMSCSIREQUEST pRequest, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pRequest->cbSenseBuffer >= 2, ("Sense buffer is not big enough\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pRequest->pbSenseBuffer, ("Sense buffer pointer is NULL\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pRequest->pbSenseBuffer[0] = uSCSISenseKey;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pRequest->pbSenseBuffer[1] = uSCSIASC;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Sets the sense key for a status good condition.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns nothing.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pRequest Pointer to the request which contains the sense buffer.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncDECLINLINE(void) drvscsihostCmdOk(PPDMSCSIREQUEST pRequest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pRequest->cbSenseBuffer >= 2, ("Sense buffer is not big enough\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(pRequest->pbSenseBuffer, ("Sense buffer pointer is NULL\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pRequest->pbSenseBuffer[0] = SCSI_SENSE_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync pRequest->pbSenseBuffer[1] = SCSI_ASC_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Returns the transfer direction of the given command
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * in case the device does not provide this info.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns transfer direction of the command.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * SCSIHOSTTXDIR_NONE if no data is transferred.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * SCSIHOSTTXDIR_FROM_DEVICE if the data is read from the device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * SCSIHOSTTXDIR_TO_DEVICE if the data is written to the device.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param uCommand The command byte.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic unsigned drvscsihostGetTransferDirectionFromCommand(uint8_t uCommand)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (uCommand)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_INQUIRY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_REPORT_LUNS:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODE_SENSE_6:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_TOC_PMA_ATIP:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_CAPACITY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_MODE_SENSE_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_GET_EVENT_STATUS_NOTIFICATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_GET_CONFIGURATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_12:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_BUFFER:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_BUFFER_CAPACITY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_DISC_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_DVD_STRUCTURE:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_FORMAT_CAPACITIES:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_SUBCHANNEL:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_TRACK_INFORMATION:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_CD:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_READ_CD_MSF:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMSCSIREQUESTTXDIR_FROM_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_TEST_UNIT_READY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_START_STOP_UNIT:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMSCSIREQUESTTXDIR_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_WRITE_10:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_WRITE_12:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_WRITE_BUFFER:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMSCSIREQUESTTXDIR_TO_DEVICE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Command not known %#x\n", uCommand));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We should never get here in debug mode. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Impossible to get here!!!\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMSCSIREQUESTTXDIR_NONE; /* to make compilers happy. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int drvscsihostProcessRequestOne(PDRVSCSIHOST pThis, PPDMSCSIREQUEST pRequest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync unsigned uTxDir;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlowFunc(("Entered\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#ifdef DEBUG
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsihostDumpScsiRequest(pRequest);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* We implement only one device. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pRequest->uLogicalUnit != 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync switch (pRequest->pbCDB[0])
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync case SCSI_INQUIRY:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync SCSIINQUIRYDATA ScsiInquiryReply;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsihostScatterGatherListCopyFromBuffer(pRequest, &ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsihostCmdOk(pRequest);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync break;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync default:
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Command not implemented for attached device\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_NONE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#if defined(RT_OS_LINUX)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sg_io_hdr_t ScsiIoReq;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sg_iovec_t *paSG = NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Setup SCSI request. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync memset(&ScsiIoReq, 0, sizeof(sg_io_hdr_t));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.interface_id = 'S';
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pRequest->uDataDirection == PDMSCSIREQUESTTXDIR_UNKNOWN)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uTxDir = drvscsihostGetTransferDirectionFromCommand(pRequest->pbCDB[0]);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync uTxDir = pRequest->uDataDirection;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (uTxDir == PDMSCSIREQUESTTXDIR_NONE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxfer_direction = SG_DXFER_NONE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (uTxDir == PDMSCSIREQUESTTXDIR_TO_DEVICE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxfer_direction = SG_DXFER_TO_DEV;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else if (uTxDir == PDMSCSIREQUESTTXDIR_FROM_DEVICE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxfer_direction = SG_DXFER_FROM_DEV;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Invalid transfer direction %u\n", uTxDir));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.cmd_len = pRequest->cbCDB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.mx_sb_len = pRequest->cbSenseBuffer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxfer_len = pRequest->cbScatterGather;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pRequest->cScatterGatherEntries > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pRequest->cScatterGatherEntries == 1)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.iovec_count = 0;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxferp = pRequest->paScatterGatherHead[0].pvSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync else
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.iovec_count = pRequest->cScatterGatherEntries;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync paSG = (sg_iovec_t *)RTMemAllocZ(pRequest->cScatterGatherEntries * sizeof(sg_iovec_t));
710471d588cfb61fa17fdbbd6a42ffd68e950f02vboxsync AssertReturn(paSG, VERR_NO_MEMORY);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync for (unsigned i = 0; i < pRequest->cScatterGatherEntries; i++)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync paSG[i].iov_base = pRequest->paScatterGatherHead[i].pvSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync paSG[i].iov_len = pRequest->paScatterGatherHead[i].cbSeg;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.dxferp = paSG;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.cmdp = pRequest->pbCDB;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.sbp = pRequest->pbSenseBuffer;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.timeout = UINT_MAX;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync ScsiIoReq.flags |= SG_FLAG_DIRECT_IO;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync /* Issue command. */
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = ioctl(RTFileToNative(pThis->hDeviceFile), SG_IO, &ScsiIoReq);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (rc < 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgFailed(("Ioctl failed with rc=%d\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Request processed successfully. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync Log(("Command successfully processed\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (ScsiIoReq.iovec_count > 0)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync RTMemFree(paSG);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync#endif
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Notify device that request finished. */
96a7e06717e2d7398642eadb5ebab1bf13fbe2dbvboxsync rc = pThis->pDevScsiPort->pfnSCSIRequestCompleted(pThis->pDevScsiPort, pRequest, SCSI_STATUS_OK, false, VINF_SUCCESS);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("Notifying device above failed rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Request function to wakeup the thread.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VWRN_STATE_CHANGED.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int drvscsihostAsyncIOLoopWakeupFunc(void)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VWRN_STATE_CHANGED;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * The thread function which processes the requests asynchronously.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @returns VBox status code.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDrvIns Pointer to the device instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pThread Pointer to the thread instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int drvscsihostAsyncIOLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc = VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDRVSCSIHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSIHOST);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync LogFlowFunc(("Entering async IO loop.\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
36411046d85fccaa66061120a064225fd1b5ae01vboxsync rc = RTReqQueueProcess(pThis->hQueueRequests, RT_INDEFINITE_WAIT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic int drvscsihostAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDRVSCSIHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSIHOST);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PRTREQ pReq;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync AssertReturn(pThis->hQueueRequests != NIL_RTREQQUEUE, VERR_INVALID_STATE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync rc = RTReqQueueCall(pThis->hQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsihostAsyncIOLoopWakeupFunc, 0);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/* -=-=-=-=- ISCSIConnector -=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/** @copydoc PDMISCSICONNECTOR::pfnSCSIRequestSend. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(int) drvscsihostRequestSend(PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync int rc;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDRVSCSIHOST pThis = PDMISCSICONNECTOR_2_DRVSCSIHOST(pInterface);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PRTREQ pReq;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync AssertReturn(pThis->hQueueRequests != NIL_RTREQQUEUE, VERR_INVALID_STATE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync rc = RTReqQueueCallEx(pThis->hQueueRequests, &pReq, 0, RTREQFLAGS_NO_WAIT, (PFNRT)drvscsihostProcessRequestOne, 2, pThis, pSCSIRequest);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgReturn(RT_SUCCESS(rc), ("Inserting request into queue failed rc=%Rrc\n", rc), rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/* -=-=-=-=- PDMIBASE -=-=-=-=- */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync/**
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) drvscsihostQueryInterface(PPDMIBASE pInterface, const char *pszIID)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync PDRVSCSIHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSIHOST);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSICONNECTOR, &pThis->ISCSIConnector);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return NULL;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Destruct a driver instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * resources can be freed correctly.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * @param pDrvIns The driver instance data.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncstatic DECLCALLBACK(void) drvscsihostDestruct(PPDMDRVINS pDrvIns)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDRVSCSIHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSIHOST);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync RTFileClose(pThis->hDeviceFile);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->hDeviceFile = NIL_RTFILE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (pThis->pszDevicePath)
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync {
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync MMR3HeapFree(pThis->pszDevicePath);
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync pThis->pszDevicePath = NULL;
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync if (pThis->hQueueRequests != NIL_RTREQQUEUE)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync {
36411046d85fccaa66061120a064225fd1b5ae01vboxsync int rc = RTReqQueueDestroy(pThis->hQueueRequests);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgRC(rc, ("Failed to destroy queue rc=%Rrc\n", rc));
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pThis->hQueueRequests = NIL_RTREQQUEUE;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync }
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Construct a block driver instance.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync *
cba6719bd64ec749967bbe931230452664109857vboxsync * @copydoc FNPDMDRVCONSTRUCT
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsyncstatic DECLCALLBACK(int) drvscsihostConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDRVSCSIHOST pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSIHOST);
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync LogFlowFunc(("pDrvIns=%#p pCfg=%#p\n", pDrvIns, pCfg));
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
36411046d85fccaa66061120a064225fd1b5ae01vboxsync /*
36411046d85fccaa66061120a064225fd1b5ae01vboxsync * Initialize the instance data first because of the destructor.
36411046d85fccaa66061120a064225fd1b5ae01vboxsync */
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pDrvIns->IBase.pfnQueryInterface = drvscsihostQueryInterface;
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsihostRequestSend;
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pThis->pDrvIns = pDrvIns;
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pThis->hDeviceFile = NIL_RTFILE;
36411046d85fccaa66061120a064225fd1b5ae01vboxsync pThis->hQueueRequests = NIL_RTREQQUEUE;
36411046d85fccaa66061120a064225fd1b5ae01vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /*
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * Read the configuration.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if (!CFGMR3AreValuesValid(pCfg, "DevicePath\0"))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
5530d99d77afedf5676a976e5135c89478b4e8d0vboxsync N_("Invalid configuration for host scsi access driver"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Query the SCSI port interface above. */
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync pThis->pDevScsiPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMISCSIPORT);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create request queue. */
36411046d85fccaa66061120a064225fd1b5ae01vboxsync int rc = RTReqQueueCreate(&pThis->hQueueRequests);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Open the device. */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryStringAlloc(pCfg, "DevicePath", &pThis->pszDevicePath);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDRV_SET_ERROR(pDrvIns, rc,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("Configuration error: Failed to get the \"DevicePath\" value"));
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
dc0a54940789f994c84390cb4a9f03da0b492285vboxsync rc = RTFileOpen(&pThis->hDeviceFile, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync if (RT_FAILURE(rc))
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync N_("DrvSCSIHost#%d: Failed to open device '%s'"), pDrvIns->iInstance, pThis->pszDevicePath);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* Create I/O thread. */
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsihostAsyncIOLoop,
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync drvscsihostAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO");
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n"), rc);
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync return VINF_SUCCESS;
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync}
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync/**
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync * SCSI driver registration record.
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsyncconst PDMDRVREG g_DrvSCSIHost =
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync{
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* u32Version */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DRVREG_VERSION,
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync /* szName */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "SCSIHost",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szRCMod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* szR0Mod */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync "",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pszDescription */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync "Host SCSI driver.",
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fFlags */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* fClass. */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync PDM_DRVREG_CLASS_SCSI,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cMaxInstances */
ad48e47654d22f79b025dc4b21cb162cb123801avboxsync ~0U,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* cbInstance */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync sizeof(DRVSCSIHOST),
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnConstruct */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsihostConstruct,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDestruct */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync drvscsihostDestruct,
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync /* pfnRelocate */
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnIOCtl */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnPowerOn */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnReset */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnSuspend */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
be284093a5d9a46ac136e8d272fda9201eb8d048vboxsync /* pfnResume */
be284093a5d9a46ac136e8d272fda9201eb8d048vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnAttach */
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync NULL,
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync /* pfnDetach */
5530d99d77afedf5676a976e5135c89478b4e8d0vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnPowerOff */
5530d99d77afedf5676a976e5135c89478b4e8d0vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* pfnSoftReset */
cba6719bd64ec749967bbe931230452664109857vboxsync NULL,
cba6719bd64ec749967bbe931230452664109857vboxsync /* u32EndVersion */
cba6719bd64ec749967bbe931230452664109857vboxsync PDM_DRVREG_VERSION
9dca051a5f8ff457ef1692990f6ecfa280daf265vboxsync};
be284093a5d9a46ac136e8d272fda9201eb8d048vboxsync