DrvSCSI.cpp revision da3503c04ce76e653401396fe2795a9bc2427a1d
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/* $Id$ */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/** @file
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * VBox storage drivers: Generic SCSI command parser and execution driver
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/*
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Copyright (C) 2006-2010 Sun Microsystems, Inc.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * available from http://www.virtualbox.org. This file is free software;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * General Public License (GPL) as published by the Free Software
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * additional information or have any questions.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/*******************************************************************************
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync* Header Files *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync*******************************************************************************/
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync//#define DEBUG
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#define LOG_GROUP LOG_GROUP_DRV_SCSI
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <VBox/pdmdrv.h>
359f2915f947abde1bba4358eada89941ee87cccvboxsync#include <VBox/pdmifs.h>
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync#include <VBox/pdmthread.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <VBox/scsi.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/assert.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/mem.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/req.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/semaphore.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/string.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include <iprt/uuid.h>
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#include "Builtins.h"
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * SCSI driver instance data.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @implements PDMISCSICONNECTOR
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @implements PDMIBLOCKASYNCPORT
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @implements PDMIMOUNTNOTIFY
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsynctypedef struct DRVSCSI
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer driver instance. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMDRVINS pDrvIns;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the attached driver's base interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMIBASE pDrvBase;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the attached driver's block interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMIBLOCK pDrvBlock;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the attached driver's async block interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMIBLOCKASYNC pDrvBlockAsync;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the attached driver's block bios interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMIBLOCKBIOS pDrvBlockBios;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the attached driver's mount interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMIMOUNT pDrvMount;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the SCSI port interface of the device above. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMISCSIPORT pDevScsiPort;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** pointer to the Led port interface of the dveice above. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMILEDPORTS pLedPort;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** The scsi connector interface .*/
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMISCSICONNECTOR ISCSIConnector;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** The block port interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMIBLOCKPORT IPort;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#if 0 /* these interfaces aren't implemented */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** The optional block async port interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMIBLOCKASYNCPORT IPortAsync;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** The mount notify interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMIMOUNTNOTIFY IMountNotify;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#endif
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Fallback status LED state for this drive.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * This is used in case the device doesn't has a LED interface. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMLED Led;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Pointer to the status LED for this drive. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMLED pLed;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Device type. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMBLOCKTYPE enmType;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** BIOS PCHS Geometry. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMMEDIAGEOMETRY PCHSGeometry;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** BIOS LCHS Geometry. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMMEDIAGEOMETRY LCHSGeometry;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Number of sectors this device has. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint64_t cSectors;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** The dedicated I/O thread for the non async approach. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMTHREAD pAsyncIOThread;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Queue for passing the requests to the thread. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PRTREQQUEUE pQueueRequests;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Request that we've left pending on wakeup or reset. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PRTREQ pPendingDummyReq;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Indicates whether PDMDrvHlpAsyncNotificationCompleted should be called by
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * any of the dummy functions. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync bool volatile fDummySignal;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Release statistics: number of bytes written. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync STAMCOUNTER StatBytesWritten;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /** Release statistics: number of bytes read. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync STAMCOUNTER StatBytesRead;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync} DRVSCSI, *PDRVSCSI;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/** Converts a pointer to DRVSCSI::ISCSIConnecotr to a PDRVSCSI. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#define PDMISCSICONNECTOR_2_DRVSCSI(pInterface) ( (PDRVSCSI)((uintptr_t)pInterface - RT_OFFSETOF(DRVSCSI, ISCSIConnector)) )
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#ifdef DEBUG
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Dumps a SCSI request structure for debugging purposes.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns nothing.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pRequest Pointer to the request to dump.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic void drvscsiDumpScsiRequest(PPDMSCSIREQUEST pRequest)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("Dump for pRequest=%#p Command: %s\n", pRequest, SCSICmdText(pRequest->pbCDB[0])));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("cbCDB=%u\n", pRequest->cbCDB));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync for (uint32_t i = 0; i < pRequest->cbCDB; i++)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("pbCDB[%u]=%#x\n", i, pRequest->pbCDB[i]));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("cbScatterGather=%u\n", pRequest->cbScatterGather));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("cScatterGatherEntries=%u\n", pRequest->cScatterGatherEntries));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* Print all scatter gather entries. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync for (uint32_t i = 0; i < pRequest->cScatterGatherEntries; i++)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("ScatterGatherEntry[%u].cbSeg=%u\n", i, pRequest->paScatterGatherHead[i].cbSeg));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("ScatterGatherEntry[%u].pvSeg=%#p\n", i, pRequest->paScatterGatherHead[i].pvSeg));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("pvUser=%#p\n", pRequest->pvUser));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#endif
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Copy the content of a buffer to a scatter gather list only
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * copying only the amount of data which fits into the
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * scatter gather list.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns VBox status code.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pRequest Pointer to the request which contains the S/G list entries.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pvBuf Pointer to the buffer which should be copied.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param cbBuf Size of the buffer.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic int drvscsiScatterGatherListCopyFromBuffer(PPDMSCSIREQUEST pRequest, void *pvBuf, size_t cbBuf)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync unsigned cSGEntry = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMDATASEG pSGEntry = &pRequest->paScatterGatherHead[cSGEntry];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t *pu8Buf = (uint8_t *)pvBuf;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync LogFlowFunc(("pRequest=%#p pvBuf=%#p cbBuf=%u\n", pRequest, pvBuf, cbBuf));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#ifdef DEBUG
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync for (unsigned i = 0; i < cbBuf; i++)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync Log(("%s: pvBuf[%u]=%#x\n", __FUNCTION__, i, pu8Buf[i]));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#endif
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync while (cSGEntry < pRequest->cScatterGatherEntries)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync size_t cbToCopy = (cbBuf < pSGEntry->cbSeg) ? cbBuf : pSGEntry->cbSeg;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync cbBuf -= cbToCopy;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* We finished. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (!cbBuf)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* Advance the buffer. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pu8Buf += cbToCopy;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* Go to the next entry in the list. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pSGEntry++;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync cSGEntry++;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return VINF_SUCCESS;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic void drvscsiPadStr(int8_t *pbDst, const char *pbSrc, uint32_t cbSize)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync for (uint32_t i = 0; i < cbSize; i++)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (*pbSrc)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbDst[i] = *pbSrc++;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync else
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbDst[i] = ' ';
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Set the sense and advanced sense key in the buffer for error conditions.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns SCSI status code.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pRequest Pointer to the request which contains the sense buffer.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param uSCSISenseKey The sense key to set.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param uSCSIASC The advanced sense key to set.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(int) drvscsiCmdError(PPDMSCSIREQUEST pRequest, uint8_t uSCSISenseKey, uint8_t uSCSIASC)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgReturn(pRequest->cbSenseBuffer >= 18, ("Sense buffer is not big enough\n"), SCSI_STATUS_OK);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgReturn(pRequest->pbSenseBuffer, ("Sense buffer pointer is NULL\n"), SCSI_STATUS_OK);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(pRequest->pbSenseBuffer, 0, pRequest->cbSenseBuffer);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[0] = (1 << 7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED; /* Fixed format */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[2] = uSCSISenseKey;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[7] = 10;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[12] = uSCSIASC;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[13] = 0x00; /** @todo: Provide more info. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return SCSI_STATUS_CHECK_CONDITION;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Sets the sense key for a status good condition.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns SCSI status code.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pRequest Pointer to the request which contains the sense buffer.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(int) drvscsiCmdOk(PPDMSCSIREQUEST pRequest)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgReturn(pRequest->cbSenseBuffer >= 18, ("Sense buffer is not big enough\n"), SCSI_STATUS_OK);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgReturn(pRequest->pbSenseBuffer, ("Sense buffer pointer is NULL\n"), SCSI_STATUS_OK);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(pRequest->pbSenseBuffer, 0, pRequest->cbSenseBuffer);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /*
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Setting this breaks Linux guests on the BusLogic controller.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * According to the SCSI SPC spec sense data is returned after a
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * CHECK CONDITION status or a REQUEST SENSE command.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * Both SCSI controllers have a feature called Auto Sense which
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * fetches the sense data automatically from the device
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * with REQUEST SENSE. So the SCSI subsystem in Linux should
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * find this sense data even if the command finishes successfully
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * but if it finds valid sense data it will let the command fail
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * and it doesn't detect attached disks anymore.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Disabling makes it work again and no other guest shows errors
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * so I will leave it disabled for now.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * On the other hand it is possible that the devices fetch the sense data
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * only after a command failed so the content is really invalid if
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * the command succeeds.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#if 0
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[0] = (1 << 7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED; /* Fixed format */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[2] = SCSI_SENSE_NONE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[7] = 10;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[12] = SCSI_ASC_NONE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pRequest->pbSenseBuffer[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#endif
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return SCSI_STATUS_OK;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(void) drvscsiH2BE_U16(uint8_t *pbBuf, uint16_t val)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[0] = val >> 8;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[1] = val;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(void) drvscsiH2BE_U24(uint8_t *pbBuf, uint32_t val)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
359f2915f947abde1bba4358eada89941ee87cccvboxsync pbBuf[0] = val >> 16;
359f2915f947abde1bba4358eada89941ee87cccvboxsync pbBuf[1] = val >> 8;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[2] = val;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(void) drvscsiH2BE_U32(uint8_t *pbBuf, uint32_t val)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[0] = val >> 24;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[1] = val >> 16;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[2] = val >> 8;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[3] = val;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(void) drvscsiH2BE_U64(uint8_t *pbBuf, uint64_t val)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[0] = val >> 56;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[1] = val >> 48;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[2] = val >> 40;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[3] = val >> 32;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[4] = val >> 24;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[5] = val >> 16;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[6] = val >> 8;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pbBuf[7] = val;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(uint16_t) drvscsiBE2H_U16(const uint8_t *pbBuf)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return (pbBuf[0] << 8) | pbBuf[1];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(uint32_t) drvscsiBE2H_U24(const uint8_t *pbBuf)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncDECLINLINE(uint32_t) drvscsiBE2H_U32(const uint8_t *pbBuf)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3];
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync}
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsyncDECLINLINE(uint64_t) drvscsiBE2H_U64(const uint8_t *pbBuf)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync{
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync return ((uint64_t)pbBuf[0] << 56)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[1] << 48)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[2] << 40)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[3] << 32)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[4] << 24)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[5] << 16)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | ((uint64_t)pbBuf[6] << 8)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync | (uint64_t)pbBuf[7];
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync}
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync/**
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * Parses the CDB of a request and acts accordingly.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync *
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @returns transfer direction type.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @param pThis Pointer to the SCSI driver instance data.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @param pRequest Pointer to the request to process.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @param puOffset Where to store the start offset to start data transfer from.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @param pcbToTransfer Where to store the number of bytes to transfer.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @param piTxDir Where to store the data transfer direction.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
3913cd08445c46b26002468dfb336d50e0de65e7vboxsyncstatic int drvscsiProcessCDB(PDRVSCSI pThis, PPDMSCSIREQUEST pRequest, uint64_t *puOffset, uint32_t *pcbToTransfer, int *piTxDir)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync int iTxDir = PDMBLOCKTXDIR_NONE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync int rc = SCSI_STATUS_OK;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync /* We check for a command which needs to be handled even for non existant LUNs. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync switch (pRequest->pbCDB[0])
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_INQUIRY:
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync SCSIINQUIRYDATA ScsiInquiryReply;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync ScsiInquiryReply.cbAdditional = 31;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync /* We support only one attached device at LUN0 at the moment. */
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync if (pRequest->uLogicalUnit != 0)
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync {
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync }
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync else
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync {
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync switch (pThis->enmType)
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync {
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync case PDMBLOCKTYPE_HARD_DISK:
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync break;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync default:
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync AssertMsgFailed(("Device type %u not supported\n", pThis->enmType));
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync }
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync ScsiInquiryReply.u3AnsiVersion = 0x05; /* SPC-4 compliant */
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync drvscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiPadStr(ScsiInquiryReply.achProductId, "HARDDISK", 16);
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync drvscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync }
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, &ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync rc = drvscsiCmdOk(pRequest);
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync case SCSI_REPORT_LUNS:
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync {
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync /*
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * If allocation length is less than 16 bytes SPC compliant devices have
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * to return an error.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync */
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync if (drvscsiBE2H_U32(&pRequest->pbCDB[6]) < 16)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync else
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t aReply[16]; /* We report only one LUN. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(aReply, 0, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U32(&aReply[0], 8); /* List length starts at position 0. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_TEST_UNIT_READY:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync default:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* Now for commands which are only implemented for existant LUNs. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (RT_LIKELY(pRequest->uLogicalUnit == 0))
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync switch(pRequest->pbCDB[0])
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_READ_CAPACITY:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t aReply[8];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(aReply, 0, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /*
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * If sector size exceeds the maximum value that is
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * able to be stored in 4 bytes return 0xffffffff in this field
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (pThis->cSectors > UINT32_C(0xffffffff))
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U32(aReply, UINT32_C(0xffffffff));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync else
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U32(aReply, pThis->cSectors - 1);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U32(&aReply[4], 512);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_MODE_SENSE_6:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t uModePage = pRequest->pbCDB[2] & 0x3f;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t aReply[24];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t *pu8ReplyPos;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(aReply, 0, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[0] = 4; /* Reply length 4. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[1] = 0; /* Default media type. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[2] = RT_BIT(4); /* Caching supported. */
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync aReply[3] = 0; /* Block descriptor length. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pu8ReplyPos = aReply + 4;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if ((uModePage == 0x08) || (uModePage == 0x3f))
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(pu8ReplyPos, 0, 20);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pu8ReplyPos++ = 0x08; /* Page code. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pu8ReplyPos++ = 0x12; /* Size of the page. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pu8ReplyPos++ = 0x4; /* Write cache enabled. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_READ_6:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync iTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *puOffset = ((uint64_t) pRequest->pbCDB[3]
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync | (pRequest->pbCDB[2] << 8)
359f2915f947abde1bba4358eada89941ee87cccvboxsync | ((pRequest->pbCDB[1] & 0x1f) << 16)) * 512;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pcbToTransfer = ((uint32_t)pRequest->pbCDB[4]) * 512;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
84dc976c881418db3750f92b02280bf987c035c7vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_READ_10:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *puOffset = ((uint64_t)drvscsiBE2H_U32(&pRequest->pbCDB[2])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U16(&pRequest->pbCDB[7])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_READ_12:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *puOffset = ((uint64_t)drvscsiBE2H_U32(&pRequest->pbCDB[2])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U32(&pRequest->pbCDB[6])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_READ_16:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_FROM_DEVICE;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *puOffset = drvscsiBE2H_U64(&pRequest->pbCDB[2]) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U32(&pRequest->pbCDB[10])) * 512;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_WRITE_6:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_TO_DEVICE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *puOffset = ((uint64_t) pRequest->pbCDB[3]
359f2915f947abde1bba4358eada89941ee87cccvboxsync | (pRequest->pbCDB[2] << 8)
359f2915f947abde1bba4358eada89941ee87cccvboxsync | ((pRequest->pbCDB[1] & 0x1f) << 16)) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *pcbToTransfer = ((uint32_t)pRequest->pbCDB[4]) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_WRITE_10:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_TO_DEVICE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *puOffset = ((uint64_t)drvscsiBE2H_U32(&pRequest->pbCDB[2])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U16(&pRequest->pbCDB[7])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_WRITE_12:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_TO_DEVICE;
359f2915f947abde1bba4358eada89941ee87cccvboxsync *puOffset = ((uint64_t)drvscsiBE2H_U32(&pRequest->pbCDB[2])) * 512;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U32(&pRequest->pbCDB[6])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_WRITE_16:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync iTxDir = PDMBLOCKTXDIR_TO_DEVICE;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *puOffset = drvscsiBE2H_U64(&pRequest->pbCDB[2]) * 512;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *pcbToTransfer = ((uint32_t)drvscsiBE2H_U32(&pRequest->pbCDB[10])) * 512;
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_SYNCHRONIZE_CACHE:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* @todo When async mode implemented we have to move this out here. */
359f2915f947abde1bba4358eada89941ee87cccvboxsync int rc2 = pThis->pDrvBlock->pfnFlush(pThis->pDrvBlock);
359f2915f947abde1bba4358eada89941ee87cccvboxsync AssertMsgRC(rc2, ("Flushing data failed rc=%Rrc\n", rc2));
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_READ_BUFFER:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync uint8_t uDataMode = pRequest->pbCDB[1] & 0x1f;
359f2915f947abde1bba4358eada89941ee87cccvboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync switch (uDataMode)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x00:
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x01:
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x02:
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x03:
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x0a:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x0b:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync uint8_t aReply[4];
359f2915f947abde1bba4358eada89941ee87cccvboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync /* We do not implement an echo buffer. */
359f2915f947abde1bba4358eada89941ee87cccvboxsync memset(aReply, 0, sizeof(aReply));
359f2915f947abde1bba4358eada89941ee87cccvboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
359f2915f947abde1bba4358eada89941ee87cccvboxsync rc = drvscsiCmdOk(pRequest);
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x1a:
359f2915f947abde1bba4358eada89941ee87cccvboxsync case 0x1c:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync default:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgFailed(("Invalid data mode\n"));
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_START_STOP_UNIT:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync /* Nothing to do. */
359f2915f947abde1bba4358eada89941ee87cccvboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_LOG_SENSE:
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint16_t cbMax = drvscsiBE2H_U16(&pRequest->pbCDB[7]);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync uint8_t uPageCode = pRequest->pbCDB[2] & 0x3f;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t uSubPageCode = pRequest->pbCDB[3];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync switch (uPageCode)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case 0x00:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (uSubPageCode == 0)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t aReply[4];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[0] = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[1] = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[2] = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync aReply[3] = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync default:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
359f2915f947abde1bba4358eada89941ee87cccvboxsync case SCSI_SERVICE_ACTION_IN_16:
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync switch (pRequest->pbCDB[1] & 0x1f)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint8_t aReply[32];
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync memset(aReply, 0, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U64(aReply, pThis->cSectors - 1);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiH2BE_U32(&aReply[8], 512);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync /* Leave the rest 0 */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiScatterGatherListCopyFromBuffer(pRequest, aReply, sizeof(aReply));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdOk(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync default:
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); /* Don't know if this is correct */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync }
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync default:
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync //AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync rc = drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync }
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync }
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync else
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync {
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync /* Report an error. */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = drvscsiCmdError(pRequest, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync break;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *piTxDir = iTxDir;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return rc;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic int drvscsiProcessRequestOne(PDRVSCSI pThis, PPDMSCSIREQUEST pRequest)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync int rc = VINF_SUCCESS;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync int iTxDir;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync int rcCompletion;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint64_t uOffset = UINT64_MAX; /* initialized to shut up gcc warnings. */
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync uint32_t cbToTransfer = UINT32_MAX; /* ditto */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync uint32_t cSegmentsLeft = UINT32_MAX; /* ditto */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync LogFlowFunc(("Entered\n"));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#ifdef DEBUG
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync drvscsiDumpScsiRequest(pRequest);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync#endif
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rcCompletion = drvscsiProcessCDB(pThis, pRequest, &uOffset, &cbToTransfer, &iTxDir);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync if ((rcCompletion == SCSI_STATUS_OK) && (iTxDir != PDMBLOCKTXDIR_NONE))
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PPDMDATASEG pSegActual;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pSegActual = &pRequest->paScatterGatherHead[0];
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync cSegmentsLeft = pRequest->cScatterGatherEntries;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync while(cbToTransfer && cSegmentsLeft)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync uint32_t cbProcess = (cbToTransfer < pSegActual->cbSeg) ? cbToTransfer : (uint32_t)pSegActual->cbSeg;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
5ef77498a407e49995c654a15755f35125acba5fvboxsync Log(("%s: uOffset=%llu cbToTransfer=%u\n", __FUNCTION__, uOffset, cbToTransfer));
5ef77498a407e49995c654a15755f35125acba5fvboxsync
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync if (iTxDir == PDMBLOCKTXDIR_FROM_DEVICE)
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync {
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync pThis->pLed->Asserted.s.fReading = pThis->pLed->Actual.s.fReading = 1;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync rc = pThis->pDrvBlock->pfnRead(pThis->pDrvBlock, uOffset,
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync pSegActual->pvSeg, cbProcess);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pThis->pLed->Actual.s.fReading = 0;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync if (RT_FAILURE(rc))
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgFailed(("%s: Failed to read data %Rrc\n", __FUNCTION__, rc));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesRead, cbProcess);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync else
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync {
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync rc = pThis->pDrvBlock->pfnWrite(pThis->pDrvBlock, uOffset,
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pSegActual->pvSeg, cbProcess);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync pThis->pLed->Actual.s.fWriting = 0;
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (RT_FAILURE(rc))
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync AssertMsgFailed(("%s: Failed to write data %Rrc\n", __FUNCTION__, rc));
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync STAM_REL_COUNTER_ADD(&pThis->StatBytesWritten, cbProcess);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync /* Go to the next entry. */
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync uOffset += cbProcess;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync cbToTransfer -= cbProcess;
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync pSegActual++;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync cSegmentsLeft--;
5ef77498a407e49995c654a15755f35125acba5fvboxsync }
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync AssertMsg(!cbToTransfer && !cSegmentsLeft,
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync ("Transfer incomplete cbToTransfer=%u cSegmentsLeft=%u\n", cbToTransfer, cSegmentsLeft));
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync drvscsiCmdOk(pRequest);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync }
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync /* Notify device. */
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync rc = pThis->pDevScsiPort->pfnSCSIRequestCompleted(pThis->pDevScsiPort, pRequest, rcCompletion);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync AssertMsgRC(rc, ("Error while notifying device rc=%Rrc\n", rc));
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
3913cd08445c46b26002468dfb336d50e0de65e7vboxsync return rc;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync * Dummy request function used by drvscsiReset to wait for all pending requests
5ef77498a407e49995c654a15755f35125acba5fvboxsync * to complete prior to the device reset.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pThis Pointer to the instace data.
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync * @returns VINF_SUCCESS.
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic int drvscsiAsyncIOLoopSyncCallback(PDRVSCSI pThis)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync if (pThis->fDummySignal)
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync return VINF_SUCCESS;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync}
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync/**
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * Request function to wakeup the thread.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param pThis Pointer to the instace data.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns VWRN_STATE_CHANGED.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic int drvscsiAsyncIOLoopWakeupFunc(PDRVSCSI pThis)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync{
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync if (pThis->fDummySignal)
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync PDMDrvHlpAsyncNotificationCompleted(pThis->pDrvIns);
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync return VWRN_STATE_CHANGED;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync}
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync/**
359f2915f947abde1bba4358eada89941ee87cccvboxsync * The thread function which processes the requests asynchronously.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync *
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @returns VBox status code.
359f2915f947abde1bba4358eada89941ee87cccvboxsync * @param pDrvIns Pointer to the driver instance data.
359f2915f947abde1bba4358eada89941ee87cccvboxsync * @param pThread Pointer to the thread instance data.
359f2915f947abde1bba4358eada89941ee87cccvboxsync */
359f2915f947abde1bba4358eada89941ee87cccvboxsyncstatic int drvscsiAsyncIOLoop(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync{
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync int rc = VINF_SUCCESS;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync LogFlowFunc(("Entering async IO loop.\n"));
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync return VINF_SUCCESS;
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
359f2915f947abde1bba4358eada89941ee87cccvboxsync {
359f2915f947abde1bba4358eada89941ee87cccvboxsync rc = RTReqProcess(pThis->pQueueRequests, RT_INDEFINITE_WAIT);
69d98a445b29f294fe2aa4c3ba9a24f1da9ae5b2vboxsync AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc));
359f2915f947abde1bba4358eada89941ee87cccvboxsync }
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync return VINF_SUCCESS;
359f2915f947abde1bba4358eada89941ee87cccvboxsync}
0a7c9cc36ee176228eab4150144ad2561b0c4647vboxsync
359f2915f947abde1bba4358eada89941ee87cccvboxsync/**
359f2915f947abde1bba4358eada89941ee87cccvboxsync * Deals with any pending dummy request
359f2915f947abde1bba4358eada89941ee87cccvboxsync *
359f2915f947abde1bba4358eada89941ee87cccvboxsync * @returns true if no pending dummy request, false if still pending.
359f2915f947abde1bba4358eada89941ee87cccvboxsync * @param pThis The instance data.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * @param cMillies The number of milliseconds to wait for any
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync * pending request to finish.
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsync */
2b73ea648457a8fb1ec027d1eeea63f879dad507vboxsyncstatic bool drvscsiAsyncIOLoopNoPendingDummy(PDRVSCSI pThis, uint32_t cMillies)
{
if (!pThis->pPendingDummyReq)
return true;
int rc = RTReqWait(pThis->pPendingDummyReq, cMillies);
if (RT_FAILURE(rc))
return false;
RTReqFree(pThis->pPendingDummyReq);
pThis->pPendingDummyReq = NULL;
return true;
}
static int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
PRTREQ pReq;
int rc;
AssertMsgReturn(pThis->pQueueRequests, ("pQueueRequests is NULL\n"), VERR_INVALID_STATE);
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */))
{
LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
return VERR_TIMEOUT;
}
rc = RTReqCall(pThis->pQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 1, pThis);
if (RT_SUCCESS(rc))
RTReqFree(pReq);
else
{
pThis->pPendingDummyReq = pReq;
LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq));
}
return rc;
}
/* -=-=-=-=- ISCSIConnector -=-=-=-=- */
/** @copydoc PDMISCSICONNECTOR::pfnSCSIRequestSend. */
static DECLCALLBACK(int) drvscsiRequestSend(PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest)
{
int rc;
PDRVSCSI pThis = PDMISCSICONNECTOR_2_DRVSCSI(pInterface);
PRTREQ pReq;
AssertMsgReturn(pThis->pQueueRequests, ("pQueueRequests is NULL\n"), VERR_INVALID_STATE);
rc = RTReqCallEx(pThis->pQueueRequests, &pReq, 0, RTREQFLAGS_NO_WAIT, (PFNRT)drvscsiProcessRequestOne, 2, pThis, pSCSIRequest);
AssertMsgReturn(RT_SUCCESS(rc), ("Inserting request into queue failed rc=%Rrc\n", rc), rc);
return VINF_SUCCESS;
}
/* -=-=-=-=- 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);
if (RTUuidCompare2Strs(pszIID, PDMIBASE_IID) == 0)
return &pDrvIns->IBase;
if (RTUuidCompare2Strs(pszIID, PDMINTERFACE_SCSI_CONNECTOR) == 0)
return &pThis->ISCSIConnector;
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBLOCKPORT, &pThis->IPort);
return NULL;
}
/**
* Worker for drvscsiReset, drvscsiSuspend and drvscsiPowerOff.
*
* @param pDrvIns The driver instance.
* @param pfnAsyncNotify The async callback.
*/
static void drvscsiR3ResetOrSuspendOrPowerOff(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!pThis->pQueueRequests)
return;
ASMAtomicWriteBool(&pThis->fDummySignal, true);
if (drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
{
if (!RTReqIsBusy(pThis->pQueueRequests))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
return;
}
PRTREQ pReq;
int rc = RTReqCall(pThis->pQueueRequests, &pReq, 0 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 1, pThis);
if (RT_SUCCESS(rc))
{
ASMAtomicWriteBool(&pThis->fDummySignal, false);
RTReqFree(pReq);
return;
}
pThis->pPendingDummyReq = pReq;
}
PDMDrvHlpSetAsyncNotification(pDrvIns, pfnAsyncNotify);
}
/**
* Callback employed by drvscsiSuspend and drvscsiPowerOff.
*
* @returns true if we've quiesced, false if we're still working.
* @param pDrvIns The driver instance.
*/
static DECLCALLBACK(bool) drvscsiIsAsyncSuspendOrPowerOffDone(PPDMDRVINS pDrvIns)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
return false;
ASMAtomicWriteBool(&pThis->fDummySignal, false);
PDMR3ThreadSuspend(pThis->pAsyncIOThread);
return true;
}
/**
* @copydoc FNPDMDRVPOWEROFF
*/
static DECLCALLBACK(void) drvscsiPowerOff(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
}
/**
* @copydoc FNPDMDRVSUSPEND
*/
static DECLCALLBACK(void) drvscsiSuspend(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncSuspendOrPowerOffDone);
}
/**
* Callback employed by drvscsiReset.
*
* @returns true if we've quiesced, false if we're still working.
* @param pDrvIns The driver instance.
*/
static DECLCALLBACK(bool) drvscsiIsAsyncResetDone(PPDMDRVINS pDrvIns)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/))
return false;
ASMAtomicWriteBool(&pThis->fDummySignal, false);
return true;
}
/**
* @copydoc FNPDMDRVRESET
*/
static DECLCALLBACK(void) drvscsiReset(PPDMDRVINS pDrvIns)
{
drvscsiR3ResetOrSuspendOrPowerOff(pDrvIns, drvscsiIsAsyncResetDone);
}
/**
* Destruct a driver instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvscsiDestruct(PPDMDRVINS pDrvIns)
{
int rc;
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
if (pThis->pQueueRequests)
{
if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 100 /*ms*/))
LogRel(("drvscsiDestruct#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
rc = RTReqDestroyQueue(pThis->pQueueRequests);
AssertMsgRC(rc, ("Failed to destroy queue rc=%Rrc\n", rc));
}
}
/**
* Construct a block driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvscsiConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
{
PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
LogFlowFunc(("pDrvIns=%#p pCfgHandle=%#p\n", pDrvIns, pCfgHandle));
/*
* Initialize the instance data.
*/
pThis->pDrvIns = pDrvIns;
pThis->ISCSIConnector.pfnSCSIRequestSend = drvscsiRequestSend;
pDrvIns->IBase.pfnQueryInterface = drvscsiQueryInterface;
/*
* Try attach driver below and query it's block interface.
*/
int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pThis->pDrvBase);
AssertMsgReturn(RT_SUCCESS(rc), ("Attaching driver below failed rc=%Rrc\n", rc), rc);
/*
* Query the block and blockbios interfaces.
*/
pThis->pDrvBlock = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCK);
if (!pThis->pDrvBlock)
{
AssertMsgFailed(("Configuration error: No block interface!\n"));
return VERR_PDM_MISSING_INTERFACE;
}
pThis->pDrvBlockBios = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKBIOS);
if (!pThis->pDrvBlockBios)
{
AssertMsgFailed(("Configuration error: No block BIOS interface!\n"));
return VERR_PDM_MISSING_INTERFACE;
}
/* Query the SCSI port interface above. */
pThis->pDevScsiPort = (PPDMISCSIPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_SCSI_PORT);
AssertMsgReturn(pThis->pDevScsiPort, ("Missing SCSI port interface above\n"), VERR_PDM_MISSING_INTERFACE);
pThis->pDrvMount = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIMOUNT);
/* Query the optional LED interface above. */
pThis->pLedPort = (PPDMILEDPORTS)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_LED_PORTS);
if (pThis->pLedPort != NULL)
{
/* Get The Led. */
rc = pThis->pLedPort->pfnQueryStatusLed(pThis->pLedPort, 0, &pThis->pLed);
if (RT_FAILURE(rc))
pThis->pLed = &pThis->Led;
}
else
pThis->pLed = &pThis->Led;
/* Try to get the optional async block interface. */
pThis->pDrvBlockAsync = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIBLOCKASYNC);
PDMBLOCKTYPE enmType = pThis->pDrvBlock->pfnGetType(pThis->pDrvBlock);
if (enmType != PDMBLOCKTYPE_HARD_DISK)
return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_UNSUPPORTED_BLOCK_TYPE, RT_SRC_POS,
N_("Only hard disks are currently supported as SCSI devices (enmType=%d)"),
enmType);
pThis->enmType = enmType;
pThis->cSectors = pThis->pDrvBlock->pfnGetSize(pThis->pDrvBlock) / 512;
/* Create request queue. */
rc = RTReqCreateQueue(&pThis->pQueueRequests);
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create request queue rc=%Rrc\n"), rc);
/* Register statistics counter. */
/** @todo aeichner: Find a way to put the instance number of the attached
* controller device when we support more than one controller of the same type.
* At the moment we have the 0 hardcoded. */
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
"Amount of data read.", "/Devices/SCSI0/%d/ReadBytes", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
"Amount of data written.", "/Devices/SCSI0/%d/WrittenBytes", pDrvIns->iInstance);
/* Create I/O thread. */
rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pAsyncIOThread, pThis, drvscsiAsyncIOLoop,
drvscsiAsyncIOLoopWakeup, 0, RTTHREADTYPE_IO, "SCSI async IO");
AssertMsgReturn(RT_SUCCESS(rc), ("Failed to create async I/O thread rc=%Rrc\n"), rc);
return VINF_SUCCESS;
}
/**
* SCSI driver registration record.
*/
const PDMDRVREG g_DrvSCSI =
{
/* u32Version */
PDM_DRVREG_VERSION,
/* szDriverName */
"SCSI",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Generic SCSI driver.",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
/* fClass. */
PDM_DRVREG_CLASS_SCSI,
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(DRVSCSI),
/* pfnConstruct */
drvscsiConstruct,
/* pfnDestruct */
drvscsiDestruct,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
drvscsiReset,
/* pfnSuspend */
drvscsiSuspend,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
drvscsiPowerOff,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
PDM_DRVREG_VERSION
};