DrvSCSIHost.cpp revision ad77e3ec3cde24263bc7537575f5cae442bee3b1
/* $Id$ */
/** @file
*
* VBox storage drivers:
* Host SCSI access driver.
*/
/*
* Copyright (C) 2006-2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
//#define DEBUG
#define LOG_GROUP LOG_GROUP_DRV_SCSIHOST
#include <VBox/pdmthread.h>
#if defined(RT_OS_LINUX)
# include <limits.h>
#endif
#include "../Builtins.h"
/**
* SCSI driver instance data.
*/
typedef struct DRVSCSIHOST
{
/** Pointer driver instance. */
/** Pointer to the SCSI port interface of the device above. */
/** The scsi connector interface .*/
/** PAth to the device file. */
char *pszDevicePath;
/** Handle to the device. */
/** The dedicated I/O thread. */
/** Queue for passing the requests to the thread. */
} DRVSCSIHOST, *PDRVSCSIHOST;
/** Converts a pointer to DRVSCSIHOST::ISCSIConnecotr to a PDRVSCSIHOST. */
#define PDMISCSICONNECTOR_2_DRVSCSIHOST(pInterface) ( (PDRVSCSIHOST)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSIHOST, ISCSIConnector)) )
#ifdef DEBUG
/**
* Dumps a SCSI request structure for debugging purposes.
*
* @returns nothing.
* @param pRequest Pointer to the request to dump.
*/
{
/* Print all scatter gather entries. */
{
}
}
#endif
/**
* Copy the content of a buffer to a scatter gather list
* copying only the amount of data which fits into the
* scatter gather list.
*
* @returns VBox status code.
* @param pRequest Pointer to the request which contains the S/G list entries.
* @param pvBuf Pointer to the buffer which should be copied.
* @param cbBuf Size of the buffer.
*/
static int drvscsihostScatterGatherListCopyFromBuffer(PPDMSCSIREQUEST pRequest, void *pvBuf, size_t cbBuf)
{
unsigned cSGEntry = 0;
{
/* We finished. */
if (!cbBuf)
break;
/* Advance the buffer. */
/* Go to the next entry in the list. */
pSGEntry++;
cSGEntry++;
}
return VINF_SUCCESS;
}
/**
* Set the sense and advanced sense key in the buffer for error conditions.
*
* @returns nothing.
* @param pRequest Pointer to the request which contains the sense buffer.
* @param uSCSISenseKey The sense key to set.
* @param uSCSIASC The advanced sense key to set.
*/
{
}
/**
* Sets the sense key for a status good condition.
*
* @returns nothing.
* @param pRequest Pointer to the request which contains the sense buffer.
*/
{
}
/**
* Returns the transfer direction of the given command
* in case the device does not provide this info.
*
* @returns transfer direction of the command.
* SCSIHOSTTXDIR_NONE if no data is transfered.
* SCSIHOSTTXDIR_FROM_DEVICE if the data is read from the device.
* SCSIHOSTTXDIR_TO_DEVICE if the data is written to the device.
* @param uCommand The command byte.
*/
{
switch (uCommand)
{
case SCSI_INQUIRY:
case SCSI_REPORT_LUNS:
case SCSI_MODE_SENSE_6:
case SCSI_READ_TOC_PMA_ATIP:
case SCSI_READ_CAPACITY:
case SCSI_MODE_SENSE_10:
case SCSI_GET_CONFIGURATION:
case SCSI_READ_10:
case SCSI_READ_12:
case SCSI_READ_BUFFER:
case SCSI_READ_DVD_STRUCTURE:
case SCSI_READ_SUBCHANNEL:
case SCSI_READ_CD:
case SCSI_READ_CD_MSF:
return PDMSCSIREQUESTTXDIR_FROM_DEVICE;
case SCSI_TEST_UNIT_READY:
case SCSI_START_STOP_UNIT:
return PDMSCSIREQUESTTXDIR_NONE;
case SCSI_WRITE_10:
case SCSI_WRITE_12:
case SCSI_WRITE_BUFFER:
return PDMSCSIREQUESTTXDIR_TO_DEVICE;
default:
}
/* We should never get here in debug mode. */
AssertMsgFailed(("Impossible to get here!!!\n"));
return PDMSCSIREQUESTTXDIR_NONE; /* to make compilers happy. */
}
{
int rc = VINF_SUCCESS;
unsigned uTxDir;
LogFlowFunc(("Entered\n"));
#ifdef DEBUG
#endif
/* We implement only one device. */
if (pRequest->uLogicalUnit != 0)
{
{
case SCSI_INQUIRY:
{
ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
break;
}
default:
AssertMsgFailed(("Command not implemented for attached device\n"));
}
}
else
{
#if defined(RT_OS_LINUX)
/* Setup SCSI request. */
else
if (uTxDir == PDMSCSIREQUESTTXDIR_NONE)
else if (uTxDir == PDMSCSIREQUESTTXDIR_TO_DEVICE)
else if (uTxDir == PDMSCSIREQUESTTXDIR_FROM_DEVICE)
else
if (pRequest->cScatterGatherEntries > 0)
{
{
ScsiIoReq.iovec_count = 0;
}
else
{
for (unsigned i = 0; i < pRequest->cScatterGatherEntries; i++)
{
}
}
}
/** Issue command. */
if (rc < 0)
{
}
/* Request processed successfully. */
Log(("Command successfully processed\n"));
if (ScsiIoReq.iovec_count > 0)
#endif
}
/* Notify device that request finished. */
return rc;
}
/**
* Request function to wakeup the thread.
*
* @returns VWRN_STATE_CHANGED.
*/
static int drvscsihostAsyncIOLoopWakeupFunc(void)
{
return VWRN_STATE_CHANGED;
}
/**
* The thread function which processes the requests asynchronously.
*
* @returns VBox status code.
* @param pDrvIns Pointer to the device instance data.
* @param pThread Pointer to the thread instance data.
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("Entering async IO loop.\n"));
return VINF_SUCCESS;
{
AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc));
}
return VINF_SUCCESS;
}
{
int rc;
rc = RTReqCall(pThis->pQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsihostAsyncIOLoopWakeupFunc, 0);
return rc;
}
/* -=-=-=-=- ISCSIConnector -=-=-=-=- */
/** @copydoc PDMISCSICONNECTOR::pfnSCSIRequestSend. */
static DECLCALLBACK(int) drvscsihostRequestSend(PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)
{
int rc;
rc = RTReqCallEx(pThis->pQueueRequests, &pReq, 0, RTREQFLAGS_NO_WAIT, (PFNRT)drvscsihostProcessRequestOne, 2, pThis, pSCSIRequest);
return VINF_SUCCESS;
}
/* -=-=-=-=- IBase -=-=-=-=- */
/** @copydoc PDMIBASE::pfnQueryInterface. */
static DECLCALLBACK(void *) drvscsihostQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
{
switch (enmInterface)
{
case PDMINTERFACE_BASE:
return &pThis->ISCSIConnector;
default:
return NULL;
}
}
/**
* 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.
*/
{
int rc;
if (pThis->pszDevicePath)
if (pThis->pQueueRequests)
{
}
}
/**
* Construct a block driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvscsihostConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
{
/*
* Read the configuration.
*/
N_("Invalid configuration for host scsi access driver"));
/*
* Initialize interfaces.
*/
/* Query the SCSI port interface above. */
pThis->pDevScsiPort = (PPDMISCSIPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_SCSI_PORT);
AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE);
/* Create request queue. */
/* Open the device. */
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"DevicePath\" value"));
rc = RTFileOpen(&pThis->DeviceFile, pThis->pszDevicePath, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
if (RT_FAILURE(rc))
/* Create I/O thread. */
return VINF_SUCCESS;
}
/**
* SCSI driver registration record.
*/
const PDMDRVREG g_DrvSCSIHost =
{
/* u32Version */
/* szDriverName */
"SCSIHost",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Host SCSI driver.",
/* fFlags */
/* fClass. */
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(DRVSCSIHOST),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
};