VBoxSCSI.cpp revision 8b90eb0585fa16024709ca374c69f1eb5d5a5a7c
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/* $Id$ */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/** @file
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VBox storage devices:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Simple SCSI interface for BIOS access
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Copyright (C) 2006-2009 Sun Microsystems, Inc.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * available from http://www.virtualbox.org. This file is free software;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * General Public License (GPL) as published by the Free Software
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync *
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * additional information or have any questions.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync */
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync/*******************************************************************************
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync* Header Files *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync//#define DEBUG
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#define LOG_GROUP LOG_GROUP_DEV_BUSLOGIC /* @todo: Create extra group. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#if defined(IN_R0) || defined(IN_RC)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync# error This device has no R0 or GC components
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#endif
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <VBox/pdmdev.h>
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync#include <VBox/pgm.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <iprt/asm.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <iprt/mem.h>
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#include <iprt/thread.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include <iprt/string.h>
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync#include "VBoxSCSI.h"
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/**
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Initializes the state for the SCSI interface.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @returns VBox status code.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param pVBoxSCSI Pointer to the unitialized SCSI state.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncint vboxscsiInitialize(PVBOXSCSI pVBoxSCSI)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync{
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->regIdentify = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbCDB = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync memset(pVBoxSCSI->aCDB, 0, sizeof(pVBoxSCSI->aCDB));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iCDB = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->fBusy = false;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbBuf = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iBuf = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->pBuf = NULL;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync return VINF_SUCCESS;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync}
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/**
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Reads a register value.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @returns VBox status code.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @param pVBoxSCSI Pointer to the SCSI state.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param iRegister Index of the register to read.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param pu32Value Where to store the content of the register.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncint vboxscsiReadRegister(PVBOXSCSI pVBoxSCSI, uint8_t iRegister, uint32_t *pu32Value)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync{
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uint8_t uVal = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync switch (iRegister)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync case 0:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (ASMAtomicReadBool(&pVBoxSCSI->fBusy) == true)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uVal |= VBOX_SCSI_BUSY;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /* There is an I/O operation in progress.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Yield the execution thread to let the I/O thread make progress.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTThreadYield();
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync else
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uVal &= ~VBOX_SCSI_BUSY;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync case 1:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (pVBoxSCSI->cbBuf > 0)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertMsg(pVBoxSCSI->pBuf, ("pBuf is NULL\n"));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uVal = pVBoxSCSI->pBuf[pVBoxSCSI->iBuf];
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iBuf++;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbBuf--;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (pVBoxSCSI->cbBuf == 0)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** The guest read the last byte from the data in buffer.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Clear everything and reset command buffer.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTMemFree(pVBoxSCSI->pBuf);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->pBuf = NULL;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbCDB = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iCDB = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iBuf = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->uTargetDevice = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync memset(pVBoxSCSI->aCDB, 0, sizeof(pVBoxSCSI->aCDB));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync case 2:
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uVal = pVBoxSCSI->regIdentify;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync break;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync default:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertMsgFailed(("Invalid register to read from %u\n", iRegister));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync }
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *pu32Value = uVal;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync return VINF_SUCCESS;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync}
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/**
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Writes to a register.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @returns VBox status code.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VERR_MORE_DATA if a command is ready to be sent to the SCSI driver.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param pVBoxSCSI Pointer to the SCSI state.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param iRegister Index of the register to write to.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @param uVal Value to write.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncint vboxscsiWriteRegister(PVBOXSCSI pVBoxSCSI, uint8_t iRegister, uint8_t uVal)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync{
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync int rc = VINF_SUCCESS;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync switch (iRegister)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync case 0:
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync if (pVBoxSCSI->enmState == VBOXSCSISTATE_NO_COMMAND)
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_READ_TXDIR;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->uTargetDevice = uVal;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync }
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_TXDIR)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_READ_CDB_SIZE;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->uTxDir = uVal;
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync }
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_CDB_SIZE)
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync {
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_READ_BUFFER_SIZE_LOW;
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync pVBoxSCSI->cbCDB = uVal;
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync }
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_BUFFER_SIZE_LOW)
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync {
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_READ_BUFFER_SIZE_HIGH;
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync pVBoxSCSI->cbBuf = uVal;
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_BUFFER_SIZE_HIGH)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_READ_COMMAND;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->cbBuf |= (((uint16_t)uVal) << 8);
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_COMMAND)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->aCDB[pVBoxSCSI->iCDB] = uVal;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->iCDB++;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync /* Check if we have all neccessary command data. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (pVBoxSCSI->iCDB == pVBoxSCSI->cbCDB)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync Log(("%s: Command ready for processing\n", __FUNCTION__));
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_COMMAND_READY;
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync /* This is a write allocate buffer. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->pBuf = (uint8_t *)RTMemAllocZ(pVBoxSCSI->cbBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (!pVBoxSCSI->pBuf)
044af0d1e6474076366759db86f101778c5f20ccvboxsync return VERR_NO_MEMORY;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync else
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync /* This is a read from the device. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync ASMAtomicXchgBool(&pVBoxSCSI->fBusy, true);
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = VERR_MORE_DATA; /** @todo Better return value to indicate ready command? */
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync else
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertMsgFailed(("Invalid state %d\n", pVBoxSCSI->enmState));
044af0d1e6474076366759db86f101778c5f20ccvboxsync break;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync case 1:
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertMsg(pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY, ("Invalid state\n"));
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->pBuf[pVBoxSCSI->iBuf++] = uVal;
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (pVBoxSCSI->iBuf == pVBoxSCSI->cbBuf)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = VERR_MORE_DATA;
044af0d1e6474076366759db86f101778c5f20ccvboxsync ASMAtomicXchgBool(&pVBoxSCSI->fBusy, true);
2bb12e589d2c280ad042e4e70635ae7224c7eceevboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync break;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync case 2:
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync {
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->regIdentify = uVal;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync break;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync default:
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync AssertMsgFailed(("Invalid register to write to %u\n", iRegister));
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync }
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync return rc;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync}
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync/**
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Sets up a SCSI request which the owning SCSI device can process.
044af0d1e6474076366759db86f101778c5f20ccvboxsync *
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @returns VBox status code.
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync * @param pVBoxSCSI Pointer to the SCSI state.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * @param pScsiRequest Pointer to a scsi request to setup.
044af0d1e6474076366759db86f101778c5f20ccvboxsync * @param puTargetDevice Where to store the target device ID.
044af0d1e6474076366759db86f101778c5f20ccvboxsync */
044af0d1e6474076366759db86f101778c5f20ccvboxsyncint vboxscsiSetupRequest(PVBOXSCSI pVBoxSCSI, PPDMSCSIREQUEST pScsiRequest, uint32_t *puTargetDevice)
044af0d1e6474076366759db86f101778c5f20ccvboxsync{
044af0d1e6474076366759db86f101778c5f20ccvboxsync int rc = VINF_SUCCESS;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync LogFlowFunc(("pVBoxSCSI=%#p pScsiRequest=%#p puTargetDevice=%#p\n", pVBoxSCSI, pScsiRequest, puTargetDevice));
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertMsg(pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY, ("Invalid state %u\n", pVBoxSCSI->enmState));
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_FROM_DEVICE)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync Assert(!pVBoxSCSI->pBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->pBuf = (uint8_t *)RTMemAllocZ(pVBoxSCSI->cbBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (!pVBoxSCSI->pBuf)
044af0d1e6474076366759db86f101778c5f20ccvboxsync return VERR_NO_MEMORY;
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** Allocate scatter gather element. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync pScsiRequest->paScatterGatherHead = (PPDMDATASEG)RTMemAllocZ(sizeof(PDMDATASEG) * 1); /* Only one element. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync if (!pScsiRequest->paScatterGatherHead)
044af0d1e6474076366759db86f101778c5f20ccvboxsync {
044af0d1e6474076366759db86f101778c5f20ccvboxsync RTMemFree(pVBoxSCSI->pBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->pBuf = NULL;
044af0d1e6474076366759db86f101778c5f20ccvboxsync return VERR_NO_MEMORY;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync }
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** Allocate sense buffer. */
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pScsiRequest->cbSenseBuffer = 18;
172ae196da38208e5f1e3485715a89f2d53c6880vboxsync pScsiRequest->pbSenseBuffer = (uint8_t *)RTMemAllocZ(pScsiRequest->cbSenseBuffer);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pScsiRequest->cbCDB = pVBoxSCSI->cbCDB;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pScsiRequest->pbCDB = pVBoxSCSI->aCDB;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pScsiRequest->uLogicalUnit = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pScsiRequest->cbScatterGather = pVBoxSCSI->cbBuf;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pScsiRequest->cScatterGatherEntries = 1;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pScsiRequest->paScatterGatherHead[0].cbSeg = pVBoxSCSI->cbBuf;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pScsiRequest->paScatterGatherHead[0].pvSeg = pVBoxSCSI->pBuf;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
a1df400bbe9d64aad400442e56eb637019300a5evboxsync *puTargetDevice = pVBoxSCSI->uTargetDevice;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync return rc;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync}
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/**
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Notifies the device that a request finished and the incoming data
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * is ready at the incoming data port.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsyncint vboxscsiRequestFinished(PVBOXSCSI pVBoxSCSI, PPDMSCSIREQUEST pScsiRequest)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync{
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync LogFlowFunc(("pVBoxSCSI=%#p pScsiRequest=%#p\n", pVBoxSCSI, pScsiRequest));
044af0d1e6474076366759db86f101778c5f20ccvboxsync RTMemFree(pScsiRequest->paScatterGatherHead);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTMemFree(pScsiRequest->pbSenseBuffer);
044af0d1e6474076366759db86f101778c5f20ccvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync {
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync if (pVBoxSCSI->pBuf)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync RTMemFree(pVBoxSCSI->pBuf);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->pBuf = NULL;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbBuf = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->cbCDB = 0;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pVBoxSCSI->iCDB = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync pVBoxSCSI->iBuf = 0;
a1df400bbe9d64aad400442e56eb637019300a5evboxsync pVBoxSCSI->uTargetDevice = 0;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
044af0d1e6474076366759db86f101778c5f20ccvboxsync memset(pVBoxSCSI->aCDB, 0, sizeof(pVBoxSCSI->aCDB));
044af0d1e6474076366759db86f101778c5f20ccvboxsync }
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync ASMAtomicXchgBool(&pVBoxSCSI->fBusy, false);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync return VINF_SUCCESS;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync}
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsyncint vboxscsiReadString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync{
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync RTGCPTR GCDst = *pGCPtrDst;
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync uint32_t cbTransfer = *pcTransfer * cb;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync LogFlowFunc(("pDevIns=%#p pVBoxSCSI=%#p iRegister=%d cTransfer=%u cb=%u\n",
044af0d1e6474076366759db86f101778c5f20ccvboxsync pDevIns, pVBoxSCSI, iRegister, *pcTransfer, cb));
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync /* Read string only valid for data in register. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertMsg(iRegister == 1, ("Hey only register 1 can be read from with string\n"));
044af0d1e6474076366759db86f101778c5f20ccvboxsync Assert(pVBoxSCSI->pBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync int rc = PGMPhysSimpleDirtyWriteGCPtr(PDMDevHlpGetVMCPU(pDevIns), GCDst, pVBoxSCSI->pBuf, cbTransfer);
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertRC(rc);
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync *pGCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCDst + cbTransfer);
044af0d1e6474076366759db86f101778c5f20ccvboxsync *pcTransfer = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync RTMemFree(pVBoxSCSI->pBuf);
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->pBuf = NULL;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->cbBuf = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->cbCDB = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->iCDB = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->iBuf = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->uTargetDevice = 0;
044af0d1e6474076366759db86f101778c5f20ccvboxsync pVBoxSCSI->enmState = VBOXSCSISTATE_NO_COMMAND;
044af0d1e6474076366759db86f101778c5f20ccvboxsync memset(pVBoxSCSI->aCDB, 0, sizeof(pVBoxSCSI->aCDB));
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync return rc;
044af0d1e6474076366759db86f101778c5f20ccvboxsync}
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsyncint vboxscsiWriteString(PPDMDEVINS pDevIns, PVBOXSCSI pVBoxSCSI, uint8_t iRegister,
044af0d1e6474076366759db86f101778c5f20ccvboxsync RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
044af0d1e6474076366759db86f101778c5f20ccvboxsync{
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync RTGCPTR GCSrc = *pGCPtrSrc;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync uint32_t cbTransfer = *pcTransfer * cb;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /* Read string only valid for data in register. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync AssertMsg(iRegister == 1, ("Hey only register 1 can be read from with string\n"));
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertMsg(cbTransfer == 512, ("Only 512 byte transfers are allowed\n"));
044af0d1e6474076366759db86f101778c5f20ccvboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync int rc = PDMDevHlpPhysReadGCVirt(pDevIns, pVBoxSCSI->pBuf, GCSrc, cbTransfer);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertRC(rc);
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *pGCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCSrc + cbTransfer);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync *pcTransfer = 0;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync return VERR_MORE_DATA;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync}
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync
044af0d1e6474076366759db86f101778c5f20ccvboxsync
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync