DevBusLogic.cpp revision 29fda0ded103a7b8b31a8e3ed7ebc56828efdac4
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * VBox storage devices: BusLogic SCSI host adapter BT-958.
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * Copyright (C) 2006-2009 Oracle Corporation
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * This file is part of VirtualBox Open Source Edition (OSE), as
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * available from http://www.virtualbox.org. This file is free software;
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * you can redistribute it and/or modify it under the terms of the GNU
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * General Public License (GPL) as published by the Free Software
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * Foundation, in version 2 as it comes in the "COPYING" file of the
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
21dcdac963f79c098a5ea1a2c5c5e109429c9786Brendan Miller/* Implemented looking at the driver source in the linux kernel (drivers/scsi/BusLogic.[ch]). */
ad0b283113c3f11ac1877df97d5d0fae899b56caBrendan Mmiller/*******************************************************************************
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller* Header Files *
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller*******************************************************************************/
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller//#define DEBUG
ad0b283113c3f11ac1877df97d5d0fae899b56caBrendan Mmiller/* Maximum number of attached devices the adapter can handle. */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/* Maximum number of scatter gather elements this device can handle. */
ad0b283113c3f11ac1877df97d5d0fae899b56caBrendan Mmiller#define BUSLOGIC_MAX_SCATTER_GATHER_LIST_SIZE 128
01f9c7d314ab242f004a7ce919c82ca886aedc3fBrendan Miller/* Size of the command buffer. */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/* Size of the reply buffer. */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/* I/O port registered in the ISA compatible range to let the BIOS access
80a21b2f138c5017c1d929d4879bfc686d6841ebBrendan Miller * the controller.
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller/** State saved version. */
8cd098376c309764dca1f83a689922be51f04785Brendan Mmiller * State of a device attached to the buslogic host adapter.
72b75f9642d4c117775b8613ccffddd5ff9c59a8Brendan Mmiller * @implements PDMIBASE
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller * @implements PDMISCSIPORT
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller * @implements PDMILEDPORTS
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller /** Pointer to the owning buslogic device instance. - R3 pointer */
e7bcfc8fc3a59824ed58768c7ef24163fed628cfBrendan Mmiller /** Pointer to the owning buslogic device instance. - R0 pointer */
bfd9faff49961e9db7b92f310d59923fd6234372Brendan Mmiller /** Pointer to the owning buslogic device instance. - RC pointer */
3f424ffdb194d6ff7ac053c5b3e53211a2de2d64Brendan Mmiller /** Flag whether device is present. */
bool fPresent;
enum BUSLOGICCOMMAND
typedef struct AutoSCSIRam
#pragma pack()
typedef union HostAdapterLocalRam
} structured;
#pragma pack()
typedef struct BUSLOGIC
bool fR0Enabled;
bool fGCEnabled;
bool fUseLocalRam;
bool fIRQEnabled;
bool fISAEnabled;
volatile bool fNotificationSend;
bool fStrictRoundRobinMode;
bool fExtendedLunCCBFormat;
bool volatile fSignalIdle;
typedef struct ReplyInquirePCIHostAdapterInformation
#pragma pack()
typedef struct ReplyInquireConfiguration
#pragma pack()
typedef struct ReplyInquireSetupInformationSynchronousValue
#pragma pack()
typedef struct ReplyInquireSetupInformation
#pragma pack()
typedef struct ReplyInquireExtendedSetupInformation
#pragma pack()
typedef struct RequestInitializeExtendedMailbox
#pragma pack()
typedef struct Mailbox
} out;
} in;
#pragma pack()
enum BUSLOGIC_CCB_OPCODE
typedef struct CommandControlBlock
#pragma pack()
typedef struct ScatterGatherEntry
#pragma pack()
typedef struct BUSLOGICTASKSTATE
bool fBIOS;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#define PDMIBASE_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, IBase)) )
#define PDMISCSIPORT_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, ISCSIPort)) )
#define PDMILEDPORTS_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, ILed)) )
#define PDMIBASE_2_PBUSLOGIC(pInterface) ( (PBUSLOGIC)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGIC, IBase)) )
#define PDMILEDPORTS_2_PBUSLOGIC(pInterface) ( (PBUSLOGIC)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGIC, ILeds)) )
#if defined(IN_RING3)
pBusLogic->LocalRam.structured.autoSCSIData.fExtendedTranslation = true; /* Same as in geometry register. */
pBusLogic->LocalRam.structured.autoSCSIData.u16DeviceEnabledMask = ~0; /* All enabled. Maybe mask out non present devices? */
pBusLogic->LocalRam.structured.autoSCSIData.fStrictRoundRobinMode = pBusLogic->fStrictRoundRobinMode;
pBusLogic->regStatus = BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY | BUSLOGIC_REGISTER_STATUS_INITIALIZATION_REQUIRED;
return VINF_SUCCESS;
#if defined(IN_RING3)
RTGCPHYS GCPhysAddrMailboxIncoming = pBusLogic->GCPhysAddrMailboxIncomingBase + (pBusLogic->uMailboxIncomingPositionCurrent * sizeof(Mailbox));
PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrCCB, &pTaskState->CommandControlBlockGuest, sizeof(CommandControlBlock));
PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxIncoming, &pTaskState->MailboxGuest, sizeof(Mailbox));
#if defined(DEBUG)
if (fOutgoing)
if ( (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_SCATTER_GATHER)
|| (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
ScatterGatherEntry aScatterGatherReadGC[32]; /* Number of scatter gather list entries read from guest memory. */
uint32_t cScatterGatherGCLeft = pTaskState->CommandControlBlockGuest.cbData / sizeof(ScatterGatherEntry);
RTGCPHYS GCPhysAddrScatterGatherCurrent = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
} while (cScatterGatherGCLeft > 0);
return VERR_NO_MEMORY;
Log(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u\n", __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer));
} while (cScatterGatherGCLeft > 0);
|| pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
return VERR_NO_MEMORY;
PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pTaskState->DataSeg.pvSeg, pTaskState->DataSeg.cbSeg);
return VINF_SUCCESS;
if ( (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_SCATTER_GATHER)
|| (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
ScatterGatherEntry aScatterGatherReadGC[32]; /* Number of scatter gather list entries read from guest memory. */
uint32_t cScatterGatherGCLeft = pTaskState->CommandControlBlockGuest.cbData / sizeof(ScatterGatherEntry);
RTGCPHYS GCPhysAddrScatterGatherCurrent = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
Log(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u\n", __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer));
} while (cScatterGatherGCLeft > 0);
|| pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pTaskState->DataSeg.pvSeg, pTaskState->DataSeg.cbSeg);
RTGCPHYS GCPhysAddrSenseBuffer = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrSenseData;
if (fCopy)
* @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary.
return VERR_NO_MEMORY;
return VINF_SUCCESS;
PReplyInquirePCIHostAdapterInformation pReply = (PReplyInquirePCIHostAdapterInformation)pBusLogic->aReplyBuffer;
for (int i = 0; i < cCharsToTransfer; i++)
PReplyInquireExtendedSetupInformation pReply = (PReplyInquireExtendedSetupInformation)pBusLogic->aReplyBuffer;
PRequestInitializeExtendedMailbox pRequest = (PRequestInitializeExtendedMailbox)pBusLogic->aCommandBuffer;
pBusLogic->GCPhysAddrMailboxIncomingBase = (RTGCPHYS)pRequest->uMailboxBaseAddress + (pBusLogic->cMailbox * sizeof(Mailbox));
pBusLogic->aReplyBuffer[i] = 0; /* @todo Figure if we need something other here. It's not needed for the linux driver */
Log(("uOperationCode=%#x, cbReplyParametersLeft=%d\n", pBusLogic->uOperationCode, pBusLogic->cbReplyParametersLeft));
return rc;
switch (iRegister)
case BUSLOGIC_REGISTER_STATUS:
case BUSLOGIC_REGISTER_DATAIN:
return rc;
switch (iRegister)
return rc;
#ifdef IN_RING3
return rc;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
#ifdef IN_RING3
int rc;
return VINF_SUCCESS;
return rc;
int rc;
ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
rc = pTaskState->CTX_SUFF(pTargetDevice)->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->CTX_SUFF(pTargetDevice)->pDrvSCSIConnector,
return rc;
int rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
static DECLCALLBACK(int) buslogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
int rc;
return rc;
static DECLCALLBACK(int) buslogicIsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
static DECLCALLBACK(int) buslogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, int rcCompletion)
int rc;
return VINF_SUCCESS;
int rc;
AssertMsgReturn(RT_SUCCESS(rc) && (pTaskState != NULL), ("Failed to get task state from cache\n"), rc);
GCPhysAddrMailboxCurrent = pBusLogic->GCPhysAddrMailboxOutgoingBase + (pBusLogic->uMailboxOutgoingPositionCurrent * sizeof(Mailbox));
GCPhysAddrMailboxCurrent = pBusLogic->GCPhysAddrMailboxOutgoingBase + (pBusLogic->uMailboxOutgoingPositionCurrent * sizeof(Mailbox));
#ifdef DEBUG
PBUSLOGICDEVICE pTargetDevice = &pBusLogic->aDeviceStates[pTaskState->CommandControlBlockGuest.uTargetId];
#ifdef DEBUG
/* Check if device is present on bus. If not return error immediately and don't process this further. */
AssertMsgFailed(("Invalid data direction type %d\n", pTaskState->CommandControlBlockGuest.uDataDirection));
rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest);
else if (pTaskState->MailboxGuest.u.out.uActionCode == BUSLOGIC_MAILBOX_OUTGOING_ACTION_ABORT_COMMAND)
AssertMsgFailed(("Invalid outgoing mailbox action code %u\n", pTaskState->MailboxGuest.u.out.uActionCode));
PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxCurrent, &pTaskState->MailboxGuest, sizeof(Mailbox));
return rc;
int rc;
return VINF_SSM_DONT_CALL_AGAIN;
static DECLCALLBACK(int) buslogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
int rc;
bool fPresent;
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"), i, pDevice->fPresent, fPresent);
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) buslogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
if (iLUN == 0)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
return NULL;
static DECLCALLBACK(int) buslogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
return NULL;
int rc;
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
return rc;
uint32_t i;
for (i = 0; i < BUSLOGIC_MAX_DEVICES; i++)
return rc;
return rc;
return rc;
return rc;
return rc;
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
return rc;
return rc;
sizeof(BUSLOGIC),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,