DevLsiLogicSCSI.cpp revision 9720b869e4f9c242a50e892b300db1120c6a03c9
/* $Id$ */
/** @file
*
* VBox storage devices:
* LsiLogic LSI53c1030 SCSI controller.
*/
/*
* Copyright (C) 2006-2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
//#define DEBUG
#define LOG_GROUP LOG_GROUP_DEV_LSILOGICSCSI
#include <VBox/pdmqueue.h>
#include <VBox/pdmcritsect.h>
#ifdef IN_RING3
#endif
#include "VBoxSCSI.h"
#include "../Builtins.h"
/* I/O port registered in the ISA compatible range to let the BIOS access
* the controller.
*/
#define LSILOGIC_ISA_IO_PORT 0x340
#define LSILOGIC_PORTS_MAX 1
#define LSILOGIC_BUSES_MAX 1
#define LSILOGIC_DEVICES_PER_BUS_MAX 16
#define LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT 1024
#define LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT 128
#define LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH 3
#define LSILOGIC_NR_OF_ALLOWED_BIGGER_LISTS 100
#define LSILOGICSCSI_PCI_VENDOR_ID (0x1000)
#define LSILOGICSCSI_PCI_DEVICE_ID (0x0030)
#define LSILOGICSCSI_PCI_REVISION_ID (0x00)
#define LSILOGICSCSI_PCI_CLASS_CODE (0x01)
#define LSILOGICSCSI_PCI_SUBSYSTEM_VENDOR_ID (0x1000)
#define LSILOGICSCSI_PCI_SUBSYSTEM_ID (0x8000)
#define LSILOGIC_SAVED_STATE_MINOR_VERSION 1
/**
* A simple SG element for a 64bit adress.
*/
#pragma pack(1)
typedef struct MptSGEntrySimple64
{
/** Length of the buffer this entry describes. */
unsigned u24Length: 24;
/** Flag whether this element is the end of the list. */
unsigned fEndOfList: 1;
/** Flag whether the address is 32bit or 64bits wide. */
unsigned f64BitAddress: 1;
/** Flag whether this buffer contains data to be transfered or is the destination. */
unsigned fBufferContainsData: 1;
/** Flag whether this is a local address or a system address. */
unsigned fLocalAddress: 1;
/** Element type. */
unsigned u2ElementType: 2;
/** Flag whether this is the last element of the buffer. */
unsigned fEndOfBuffer: 1;
/** Flag whether this is the last element of the current segment. */
unsigned fLastElement: 1;
/** Lower 32bits of the address of the data buffer. */
unsigned u32DataBufferAddressLow: 32;
/** Upper 32bits of the address of the data buffer. */
unsigned u32DataBufferAddressHigh: 32;
#pragma pack()
/**
* A simple SG element for a 32bit adress.
*/
#pragma pack(1)
typedef struct MptSGEntrySimple32
{
/** Length of the buffer this entry describes. */
unsigned u24Length: 24;
/** Flag whether this element is the end of the list. */
unsigned fEndOfList: 1;
/** Flag whether the address is 32bit or 64bits wide. */
unsigned f64BitAddress: 1;
/** Flag whether this buffer contains data to be transfered or is the destination. */
unsigned fBufferContainsData: 1;
/** Flag whether this is a local address or a system address. */
unsigned fLocalAddress: 1;
/** Element type. */
unsigned u2ElementType: 2;
/** Flag whether this is the last element of the buffer. */
unsigned fEndOfBuffer: 1;
/** Flag whether this is the last element of the current segment. */
unsigned fLastElement: 1;
/** Lower 32bits of the address of the data buffer. */
unsigned u32DataBufferAddressLow: 32;
#pragma pack()
/**
* A chain SG element.
*/
#pragma pack(1)
typedef struct MptSGEntryChain
{
/** Size of the segment. */
unsigned u16Length: 16;
/** Offset in 32bit words of the next chain element in the segment
* identified by this element. */
unsigned u8NextChainOffset: 8;
/** Reserved. */
unsigned fReserved0: 1;
/** Flag whether the address is 32bit or 64bits wide. */
unsigned f64BitAddress: 1;
/** Reserved. */
unsigned fReserved1: 1;
/** Flag whether this is a local address or a system address. */
unsigned fLocalAddress: 1;
/** Element type. */
unsigned u2ElementType: 2;
/** Flag whether this is the last element of the buffer. */
unsigned u2Reserved2: 2;
/** Lower 32bits of the address of the data buffer. */
unsigned u32SegmentAddressLow: 32;
/** Upper 32bits of the address of the data buffer. */
unsigned u32SegmentAddressHigh: 32;
#pragma pack()
typedef union MptSGEntryUnion
{
/**
* MPT Fusion message header - Common for all message frames.
* This is filled in by the guest.
*/
#pragma pack(1)
typedef struct MptMessageHdr
{
/** Function dependent data. */
/** Chain offset. */
/** The function code. */
/** Function dependent data. */
/** Message flags. */
/** Message context - Unique ID from the guest unmodified by the device. */
#pragma pack()
/** Defined function codes found in the message header. */
#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST (0x00)
#define MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT (0x01)
#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT (0x02)
#define MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS (0x03)
#define MPT_MESSAGE_HDR_FUNCTION_CONFIG (0x04)
#define MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS (0x05)
#define MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE (0x06)
#define MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION (0x07)
#define MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK (0x08)
#define MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD (0x09)
#define MPT_MESSAGE_HDR_FUNCTION_TARGET_CMD_BUFFER_POST (0x0A)
#define MPT_MESSAGE_HDR_FUNCTION_TARGET_ASSIST (0x0B)
#define MPT_MESSAGE_HDR_FUNCTION_TARGET_STATUS_SEND (0x0C)
#define MPT_MESSAGE_HDR_FUNCTION_TARGET_MODE_ABORT (0x0D)
#ifdef DEBUG
/**
* Function names
*/
static const char * const g_apszMPTFunctionNames[] =
{
"SCSI I/O Request",
"SCSI Task Management",
"IOC Init",
"IOC Facts",
"Config",
"Port Facts",
"Port Enable",
"Event Notification",
"Event Ack",
"Firmware Download"
};
#endif
/**
* Default reply message.
* Send from the device to the guest upon completion of a request.
*/
#pragma pack(1)
typedef struct MptDefaultReplyMessage
{
/** Function dependent data. */
/** Length of the message in 32bit DWords. */
/** Function which completed. */
/** Function dependent. */
/** Message flags. */
/** Message context given in the request. */
/** Function dependent status code. */
/** Status of the IOC. */
/** Additional log info. */
#pragma pack()
/**
* IO controller init request.
*/
#pragma pack(1)
typedef struct MptIOCInitRequest
{
/** Which system send this init request. */
/** Reserved */
/** Chain offset in the SG list. */
/** Function to execute. */
/** Flags */
/** Maximum number of devices the driver can handle. */
/** Maximum number of buses the driver can handle. */
/** Message flags. */
/** Message context ID. */
/** Reply frame size. */
/** Reserved */
/** Upper 32bit part of the 64bit address the message frames are in.
* That means all frames must be in the same 4GB segment. */
/** Upper 32bit of the sense buffer. */
#pragma pack()
/**
* IO controller init reply.
*/
#pragma pack(1)
typedef struct MptIOCInitReply
{
/** Which subsystem send this init request. */
/** Reserved */
/** Message length */
/** Function. */
/** Flags */
/** Maximum number of devices the driver can handle. */
/** Maximum number of busses the driver can handle. */
/** Message flags. */
/** Message context ID */
/** Reserved */
/** IO controller status. */
/** IO controller log information. */
#pragma pack()
/**
* IO controller facts request.
*/
#pragma pack(1)
typedef struct MptIOCFactsRequest
{
/** Reserved. */
/** Chain offset in SG list. */
/** Function number. */
/** Reserved */
/** Message flags. */
/** Message context ID. */
#pragma pack()
/**
* IO controller facts reply.
*/
#pragma pack(1)
typedef struct MptIOCFactsReply
{
/** Message version. */
/** Message length. */
/** Function number. */
/** Reserved */
/** IO controller number */
/** Message flags. */
/** Message context ID. */
/** IO controller exceptions */
/** IO controller status. */
/** IO controller log information. */
/** Maximum chain depth. */
/** The current value of the WhoInit field. */
/** Block size. */
/** Flags. */
/** Depth of the reply queue. */
/** Size of a request frame. */
/** Reserved */
/** Product ID. */
/** Current value of the high 32bit MFA address. */
/** Global credits - Number of entries allocated to queues */
/** Number of ports on the IO controller */
/** Event state. */
/** Current value of the high 32bit sense buffer address. */
/** Current reply frame size. */
/** Maximum number of devices. */
/** Maximum number of buses. */
/** Size of the firmware image. */
/** Reserved. */
/** Firmware version */
#pragma pack()
/**
* Port facts request
*/
#pragma pack(1)
typedef struct MptPortFactsRequest
{
/** Reserved */
/** Message length. */
/** Function number. */
/** Reserved */
/** Port number to get facts for. */
/** Message flags. */
/** Message context ID. */
#pragma pack()
/**
* Port facts reply.
*/
#pragma pack(1)
typedef struct MptPortFactsReply
{
/** Reserved. */
/** Message length. */
/** Function number. */
/** Reserved */
/** Port number the facts are for. */
/** Message flags. */
/** Message context ID. */
/** Reserved. */
/** IO controller status. */
/** IO controller log information. */
/** Reserved */
/** Port type */
/** Maximum number of devices on this port. */
/** SCSI ID of this port on the attached bus. */
/** Protocol flags. */
/** Maxmimum number of target command buffers which can be posted to this port at a time. */
/** Maximum number of LAN buckets. */
/** Reserved. */
/** Reserved. */
#pragma pack()
/**
* Port Enable request.
*/
#pragma pack(1)
typedef struct MptPortEnableRequest
{
/** Reserved. */
/** Message length. */
/** Function number. */
/** Reserved. */
/** Port number to enable. */
/** Message flags. */
/** Message context ID. */
#pragma pack()
/**
* Port enable reply.
*/
#pragma pack(1)
typedef struct MptPortEnableReply
{
/** Reserved. */
/** Message length. */
/** Function number. */
/** Reserved */
/** Port number which was enabled. */
/** Message flags. */
/** Message context ID. */
/** Reserved. */
/** IO controller status */
/** IO controller log information. */
#pragma pack()
/**
* Event notification request.
*/
#pragma pack(1)
typedef struct MptEventNotificationRequest
{
/** Switch - Turns event notification on and off. */
/** Reserved. */
/** Chain offset. */
/** Function number. */
/** Reserved. */
/** Message flags. */
/** Message context ID. */
#pragma pack()
/**
* Event notification reply.
*/
#pragma pack(1)
typedef struct MptEventNotificationReply
{
/** Event data length. */
/** Message length. */
/** Function number. */
/** Reserved. */
/** Ack required. */
/** Message flags. */
/** Message context ID. */
/** Reserved. */
/** IO controller status. */
/** IO controller log information. */
/** Notification event. */
/** Event context. */
/** Event data. */
#pragma pack()
#define MPT_EVENT_EVENT_CHANGE (0x0000000a)
/**
* SCSI IO Request
*/
#pragma pack(1)
typedef struct MptSCSIIORequest
{
/** Target ID */
/** Bus number */
/** Chain offset */
/** Function number. */
/** CDB length. */
/** Sense buffer length. */
/** Rserved */
/** Message flags. */
/** Message context ID. */
/** LUN */
/** Control values. */
/** The CDB. */
/** Data length. */
/** Sense buffer low 32bit address. */
#pragma pack()
#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE (0x0)
#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE (0x1)
#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ (0x2)
/**
* SCSI IO error reply.
*/
#pragma pack(1)
typedef struct MptSCSIIOErrorReply
{
/** Target ID */
/** Bus number */
/** Message length. */
/** Function number. */
/** CDB length */
/** Sense buffer length */
/** Reserved */
/** Message flags */
/** Message context ID */
/** SCSI status. */
/** SCSI state */
/** IO controller status */
/** IO controller log information */
/** Transfer count */
/** Sense count */
/** Response information */
#pragma pack()
#define MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID (0x01)
#define MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED (0x08)
/**
* IOC status codes sepcific to the SCSI I/O error reply.
*/
#define MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS (0x0041)
#define MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID (0x0042)
#define MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE (0x0043)
/**
* SCSI task management request.
*/
#pragma pack(1)
typedef struct MptSCSITaskManagementRequest
{
/** Target ID */
/** Bus number */
/** Chain offset */
/** Function number */
/** Reserved */
/** Task type */
/** Reserved */
/** Message flags */
/** Message context ID */
/** LUN */
/** Reserved */
/** Task message context ID. */
#pragma pack()
/**
* SCSI task management reply.
*/
#pragma pack(1)
typedef struct MptSCSITaskManagementReply
{
/** Target ID */
/** Bus number */
/** Message length */
/** Function number */
/** Reserved */
/** Task type */
/** Reserved */
/** Message flags */
/** Message context ID */
/** Reserved */
/** IO controller status */
/** IO controller log information */
/** Termination count */
#pragma pack()
/**
* Configuration request
*/
#pragma pack(1)
typedef struct MptConfigurationRequest
{
/** Action code. */
/** Reserved. */
/** Chain offset. */
/** Function number. */
/** Reserved. */
/** Message flags. */
/** Message context ID. */
/** Reserved. */
/** Version number of the page. */
/** Length of the page in 32bit Dwords. */
/** Page number to access. */
/** Type of the page beeing accessed. */
/** Page type dependent address. */
union
{
/** 32bit view. */
struct
{
/** Port number to get the configuration page for. */
/** Reserved. */
struct
{
/** Target ID to get the configuration page for. */
/** Bus number to get the configuration page for. */
/** Reserved. */
} u;
#pragma pack()
/** Possible action codes. */
#define MPT_CONFIGURATION_REQUEST_ACTION_HEADER (0x00)
#define MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT (0x01)
#define MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT (0x02)
#define MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT (0x03)
#define MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT (0x04)
#define MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM (0x05)
#define MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM (0x06)
/** Page type codes. */
#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_IO_UNIT (0x00)
#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_IOC (0x01)
#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_BIOS (0x02)
#define MPT_CONFIGURATION_REQUEST_PAGE_TYPE_SCSI_PORT (0x03)
/**
* Configuration reply.
*/
#pragma pack(1)
typedef struct MptConfigurationReply
{
/** Action code. */
/** Reserved. */
/** Message length. */
/** Function number. */
/** Reserved. */
/** Message flags. */
/** Message context ID. */
/** Reserved. */
/** I/O controller status. */
/** I/O controller log information. */
/** Version number of the page. */
/** Length of the page in 32bit Dwords. */
/** Page number to access. */
/** Type of the page beeing accessed. */
#pragma pack()
/** Additional I/O controller status codes for the configuration reply. */
#define MPT_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
#define MPT_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
#define MPT_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
#define MPT_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
#define MPT_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
#define MPT_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
/**
* Union of all possible request messages.
*/
typedef union MptRequestUnion
{
/**
* Union of all possible reply messages.
*/
typedef union MptReplyUnion
{
/** 16bit view. */
/**
* Configuration Page attributes.
*/
#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY (0x00)
#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE (0x10)
#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT (0x20)
#define MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY (0x30)
/**
* Configuration Page types.
*/
#define MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT (0x00)
#define MPT_CONFIGURATION_PAGE_TYPE_IOC (0x01)
#define MPT_CONFIGURATION_PAGE_TYPE_BIOS (0x02)
#define MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT (0x03)
#define MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE (0x04)
#define MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING (0x09)
/**
* Configuration Page header - Common to all pages.
*/
#pragma pack(1)
typedef struct MptConfigurationPageHeader
{
/** Version of the page. */
/** The length of the page in 32bit D-Words. */
/** Number of the page. */
/** Type of the page. */
#pragma pack()
/**
* Manufacturing page 0. - Readonly.
*/
#pragma pack(1)
typedef struct MptConfigurationPageManufacturing0
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Name of the chip. */
/** Chip revision. */
/** Board name. */
/** Board assembly. */
/** Board tracer number. */
} fields;
} u;
#pragma pack()
/**
* Manufacturing page 1. - Readonly Persistent.
*/
#pragma pack(1)
typedef struct MptConfigurationPageManufacturing1
{
/** The omnipresent header. */
/** VPD info - don't know what belongs here so all zero. */
#pragma pack()
/**
* Manufacturing page 2. - Readonly.
*/
#pragma pack(1)
typedef struct MptConfigurationPageManufacturing2
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** PCI Device ID. */
/** PCI Revision ID. */
/** Reserved. */
/** Hardware specific settings... */
} fields;
} u;
#pragma pack()
/**
* Manufacturing page 3. - Readonly.
*/
#pragma pack(1)
typedef struct MptConfigurationPageManufacturing3
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** PCI Device ID. */
/** PCI Revision ID. */
/** Reserved. */
/** Chip specific settings... */
} fields;
} u;
#pragma pack()
/**
* Manufacturing page 4. - Readonly.
*/
#pragma pack(1)
typedef struct MptConfigurationPageManufacturing4
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Reserved. */
/** InfoOffset0. */
/** Info size. */
/** InfoOffset1. */
/** Info size. */
/** Size of the inquiry data. */
/** Reserved. */
/** Inquiry data. */
/** IS volume settings. */
/** IME volume settings. */
/** IM volume settings. */
} fields;
} u;
#pragma pack()
/**
* IO Unit page 0. - Readonly.
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOUnit0
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** A unique identifier. */
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOUnit1
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Flag whether this is a single function PCI device. */
unsigned fSingleFunction: 1;
/** Flag whether all possible paths to a device are mapped. */
unsigned fAllPathsMapped: 1;
/** Reserved. */
unsigned u4Reserved: 4;
/** Flag whether all RAID functionality is disabled. */
unsigned fIntegratedRAIDDisabled: 1;
/** Flag whether 32bit PCI accesses are forced. */
unsigned f32BitAccessForced: 1;
/** Reserved. */
unsigned abReserved: 24;
} fields;
} u;
#pragma pack()
/**
* Adapter Ordering.
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOUnit2AdapterOrdering
{
/** PCI bus number. */
unsigned u8PCIBusNumber: 8;
/** PCI device and function number. */
unsigned u8PCIDevFn: 8;
/** Flag whether the adapter is embedded. */
unsigned fAdapterEmbedded: 1;
/** Flag whether the adapter is enabled. */
unsigned fAdapterEnabled: 1;
/** Reserved. */
unsigned u6Reserved: 6;
/** Reserved. */
unsigned u8Reserved: 8;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOUnit2
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Reserved. */
unsigned fReserved: 1;
/** Flag whether Pause on error is enabled. */
unsigned fPauseOnError: 1;
/** Flag whether verbose mode is enabled. */
unsigned fVerboseModeEnabled: 1;
/** Set to disable color video. */
unsigned fDisableColorVideo: 1;
/** Flag whether int 40h is hooked. */
unsigned fNotHookInt40h: 1;
/** Reserved. */
unsigned u3Reserved: 3;
/** Reserved. */
unsigned abReserved: 24;
/** BIOS version. */
/** Adapter ordering. */
} fields;
} u;
#pragma pack()
/*
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOUnit3
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Number of GPIO values. */
/** Reserved. */
} fields;
} u;
#pragma pack()
/**
* IOC page 0. - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC0
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Total ammount of NV memory in bytes. */
/** Number of free bytes in the NV store. */
/** PCI vendor ID. */
/** PCI device ID. */
/** PCI revision ID. */
/** Reserved. */
/** PCI class code. */
/** Subsystem vendor Id. */
/** Subsystem Id. */
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC1
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Flag whether reply coalescing is enabled. */
unsigned fReplyCoalescingEnabled: 1;
/** Reserved. */
unsigned u31Reserved: 31;
/** Coalescing Timeout in microseconds. */
unsigned u32CoalescingTimeout: 32;
/** Coalescing depth. */
unsigned u8CoalescingDepth: 8;
/** Reserved. */
unsigned u8Reserved0: 8;
unsigned u8Reserved1: 8;
unsigned u8Reserved2: 8;
} fields;
} u;
#pragma pack()
/**
* IOC page 2. - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC2
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Flag whether striping is supported. */
unsigned fStripingSupported: 1;
/** Flag whether enhanced mirroring is supported. */
unsigned fEnhancedMirroringSupported: 1;
/** Flag whether mirroring is supported. */
unsigned fMirroringSupported: 1;
/** Reserved. */
unsigned u26Reserved: 26;
/** Flag whether SES is supported. */
unsigned fSESSupported: 1;
/** Flag whether SAF-TE is supported. */
unsigned fSAFTESupported: 1;
/** Flag whether cross channel volumes are supported. */
unsigned fCrossChannelVolumesSupported: 1;
/** Number of active integrated RAID volumes. */
unsigned u8NumActiveVolumes: 8;
/** Maximum number of integrated RAID volumes supported. */
unsigned u8MaxVolumes: 8;
/** Number of active integrated RAID physical disks. */
unsigned u8NumActivePhysDisks: 8;
/** Maximum number of integrated RAID physical disks supported. */
unsigned u8MaxPhysDisks: 8;
/** RAID volumes... - not supported. */
} fields;
} u;
#pragma pack()
/**
* IOC page 3. - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC3
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Number of active integrated RAID physical disks. */
/** Reserved. */
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC4
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Number of SEP entries in this page. */
/** Maximum number of SEp entries supported. */
/** Reserved. */
/** SEP entries... - not supported. */
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageIOC6
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
} fields;
} u;
#pragma pack()
/**
* SCSI-SPI port page 0. - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIPort0
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Flag whether this port is information unit trnafsers capable. */
unsigned fInformationUnitTransfersCapable: 1;
/** Flag whether the port is DT (Dual Transfer) capable. */
unsigned fDTCapable: 1;
/** Flag whether the port is QAS (Quick Arbitrate and Select) capable. */
unsigned fQASCapable: 1;
/** Reserved. */
unsigned u5Reserved1: 5;
/** Minimum Synchronous transfer period. */
unsigned u8MinimumSynchronousTransferPeriod: 8;
/** Maximum synchronous offset. */
unsigned u8MaximumSynchronousOffset: 8;
/** Reserved. */
unsigned u5Reserved2: 5;
/** Flag whether indicating the width of the bus - 0 narrow and 1 for wide. */
unsigned fWide: 1;
/** Reserved */
unsigned fReserved: 1;
/** Flag whether the port is AIP (Asynchronous Information Protection) capable. */
unsigned fAIPCapable: 1;
/** Signaling Type. */
unsigned u2SignalingType: 2;
/** Reserved. */
unsigned u30Reserved: 30;
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIPort1
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** The SCSI ID of the port. */
/** Reserved. */
/** Port response IDs Bit mask field. */
/** Value for the on BUS timer. */
} fields;
} u;
#pragma pack()
/**
* Device settings for one device.
*/
#pragma pack(1)
typedef struct MptDeviceSettings
{
/** Timeout for I/O in seconds. */
unsigned u8Timeout: 8;
/** Minimum synchronous factor. */
unsigned u8SyncFactor: 8;
/** Flag whether disconnect is enabled. */
unsigned fDisconnectEnable: 1;
/** Flag whether Scan ID is enabled. */
unsigned fScanIDEnable: 1;
/** Flag whether Scan LUNs is enabled. */
unsigned fScanLUNEnable: 1;
/** Flag whether tagged queuing is enabled. */
unsigned fTaggedQueuingEnabled: 1;
/** Flag whether wide is enabled. */
unsigned fWideDisable: 1;
/** Flag whether this device is bootable. */
unsigned fBootChoice: 1;
/** Reserved. */
unsigned u10Reserved: 10;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIPort2
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Flag indicating the bus scan order. */
unsigned fBusScanOrderHighToLow: 1;
/** Reserved. */
unsigned fReserved: 1;
/** Flag whether SCSI Bus resets are avoided. */
unsigned fAvoidSCSIBusResets: 1;
/** Flag whether alternate CHS is used. */
unsigned fAlternateCHS: 1;
/** Flag whether termination is disabled. */
unsigned fTerminationDisabled: 1;
/** Reserved. */
unsigned u27Reserved: 27;
/** Host SCSI ID. */
unsigned u4HostSCSIID: 4;
/** Initialize HBA. */
unsigned u2InitializeHBA: 2;
/** Removeable media setting. */
unsigned u2RemovableMediaSetting: 2;
/** Spinup delay. */
unsigned u4SpinupDelay: 4;
/** Negotiating settings. */
unsigned u2NegotitatingSettings: 2;
/** Reserved. */
unsigned u18Reserved: 18;
/** Device Settings. */
} fields;
} u;
#pragma pack()
/**
* SCSI-SPI device page 0. - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIDevice0
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Negotiated Parameters. */
/** Information Units enabled. */
unsigned fInformationUnitsEnabled: 1;
/** Dual Transfers Enabled. */
unsigned fDTEnabled: 1;
/** QAS enabled. */
unsigned fQASEnabled: 1;
/** Reserved. */
unsigned u5Reserved1: 5;
/** Synchronous Transfer period. */
unsigned u8NegotiatedSynchronousTransferPeriod: 8;
/** Synchronous offset. */
unsigned u8NegotiatedSynchronousOffset: 8;
/** Reserved. */
unsigned u5Reserved2: 5;
/** Width - 0 for narrow and 1 for wide. */
unsigned fWide: 1;
/** Reserved. */
unsigned fReserved: 1;
/** AIP enabled. */
unsigned fAIPEnabled: 1;
/** Flag whether negotiation occurred. */
unsigned fNegotationOccured: 1;
/** Flag whether a SDTR message was rejected. */
unsigned fSDTRRejected: 1;
/** Flag whether a WDTR message was rejected. */
unsigned fWDTRRejected: 1;
/** Flag whether a PPR message was rejected. */
unsigned fPPRRejected: 1;
/** Reserved. */
unsigned u28Reserved: 28;
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIDevice1
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Requested Parameters. */
/** Information Units enable. */
bool fInformationUnitsEnable: 1;
/** Dual Transfers Enable. */
bool fDTEnable: 1;
/** QAS enable. */
bool fQASEnable: 1;
/** Reserved. */
unsigned u5Reserved1: 5;
/** Synchronous Transfer period. */
unsigned u8NegotiatedSynchronousTransferPeriod: 8;
/** Synchronous offset. */
unsigned u8NegotiatedSynchronousOffset: 8;
/** Reserved. */
unsigned u5Reserved2: 5;
/** Width - 0 for narrow and 1 for wide. */
bool fWide: 1;
/** Reserved. */
bool fReserved1: 1;
/** AIP enable. */
bool fAIPEnable: 1;
/** Reserved. */
bool fReserved2: 1;
/** WDTR disallowed. */
bool fWDTRDisallowed: 1;
/** SDTR disallowed. */
bool fSDTRDisallowed: 1;
/** Reserved. */
unsigned u29Reserved: 29;
} fields;
} u;
#pragma pack()
/**
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIDevice2
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Reserved. */
unsigned u4Reserved: 4;
/** ISI enable. */
unsigned fISIEnable: 1;
/** Secondary driver enable. */
unsigned fSecondaryDriverEnable: 1;
/** Reserved. */
unsigned fReserved: 1;
/** Slew reate controler. */
unsigned u3SlewRateControler: 3;
/** Primary drive strength controler. */
unsigned u3PrimaryDriveStrengthControl: 3;
/** Secondary drive strength controler. */
unsigned u3SecondaryDriveStrengthControl: 3;
/** Reserved. */
unsigned u12Reserved: 12;
/** XCLKH_ST. */
unsigned fXCLKH_ST: 1;
/** XCLKS_ST. */
unsigned fXCLKS_ST: 1;
/** XCLKH_DT. */
unsigned fXCLKH_DT: 1;
/** XCLKS_DT. */
unsigned fXCLKS_DT: 1;
/** Parity pipe select. */
unsigned u2ParityPipeSelect: 2;
/** Reserved. */
unsigned u30Reserved: 30;
/** Data bit pipeline select. */
unsigned u32DataPipelineSelect: 32;
} fields;
} u;
#pragma pack()
/**
* SCSI-SPI device page 3 (Revision G). - Readonly
*/
#pragma pack(1)
typedef struct MptConfigurationPageSCSISPIDevice3
{
/** Union. */
union
{
/** Byte view. */
/** Field view. */
struct
{
/** The omnipresent header. */
/** Number of times the IOC rejected a message because it doesn't support the operation. */
/** Number of times the SCSI bus entered an invalid operation state. */
/** Number of parity errors. */
/** Reserved. */
} fields;
} u;
#pragma pack()
/**
* Structure of all supported pages.
*/
typedef struct MptConfigurationPagesSupported
{
struct
{
struct
{
struct
{
/**
* Possible SG element types.
*/
enum MPTSGENTRYTYPE
{
MPTSGENTRYTYPE_SIMPLE = 0x01,
MPTSGENTRYTYPE_CHAIN = 0x03
};
/**
* Reply data.
*/
typedef struct LSILOGICSCSIREPLY
{
/** Lower 32 bits of the reply address in memory. */
/** Full address of the reply in guest memory. */
/** Size of the reply. */
/** Different views to the reply depending on the request type. */
/*
* State of a device attached to the buslogic host adapter.
*/
typedef struct LSILOGICDEVICE
{
/** Pointer to the owning lsilogic device instance. - R3 pointer */
/** Pointer to the owning lsilogic device instance. - R0 pointer */
/** Pointer to the owning lsilogic device instance. - RC pointer */
/** LUN of the device. */
/** Number of outstanding tasks on the port. */
volatile uint32_t cOutstandingRequests;
#if HC_ARCH_BITS == 64
#endif
/** Our base interace. */
/** SCSI port interface. */
/** Led interface. */
/** Pointer to the attached driver's base interface. */
/** Pointer to the underlying SCSI connector interface. */
/** The status LED state for this device. */
/**
* Defined states that the SCSI controller can have.
*/
typedef enum LSILOGICSTATE
{
/** Reset state. */
LSILOGICSTATE_RESET = 0x00,
/** Ready state. */
LSILOGICSTATE_READY = 0x01,
/** Operational state. */
LSILOGICSTATE_OPERATIONAL = 0x02,
/** Fault state. */
LSILOGICSTATE_FAULT = 0x04,
/** 32bit size hack */
LSILOGICSTATE_32BIT_HACK = 0x7fffffff
/**
* Which entity needs to initialize the controller
* to get into the operational state.
*/
typedef enum LSILOGICWHOINIT
{
/** Not initialized. */
LSILOGICWHOINIT_NOT_INITIALIZED = 0x00,
/** System BIOS. */
LSILOGICWHOINIT_SYSTEM_BIOS = 0x01,
/** ROM Bios. */
LSILOGICWHOINIT_ROM_BIOS = 0x02,
/** PCI Peer. */
LSILOGICWHOINIT_PCI_PEER = 0x03,
/** Host driver. */
LSILOGICWHOINIT_HOST_DRIVER = 0x04,
/** Manufacturing. */
LSILOGICWHOINIT_MANUFACTURING = 0x05,
/** 32bit size hack. */
LSILOGICWHOINIT_32BIT_HACK = 0x7fffffff
/**
* IOC status codes.
*/
#define LSILOGIC_IOCSTATUS_SUCCESS 0x0000
#define LSILOGIC_IOCSTATUS_INVALID_FUNCTION 0x0001
#define LSILOGIC_IOCSTATUS_BUSY 0x0002
#define LSILOGIC_IOCSTATUS_INVALID_SGL 0x0003
#define LSILOGIC_IOCSTATUS_INTERNAL_ERROR 0x0004
#define LSILOGIC_IOCSTATUS_RESERVED 0x0005
#define LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES 0x0006
#define LSILOGIC_IOCSTATUS_INVALID_FIELD 0x0007
#define LSILOGIC_IOCSTATUS_INVALID_STATE 0x0008
#define LSILOGIC_IOCSTATUS_OP_STATE_NOT_SUPPOTED 0x0009
/**
* Device instance data for the emulated
* SCSI controller.
*/
typedef struct LSILOGICSCSI
{
/** PCI device structure. */
/** Pointer to the device instance. - R3 ptr. */
/** Pointer to the device instance. - R0 ptr. */
/** Pointer to the device instance. - RC ptr. */
/** Flag whether the GC part of the device is enabled. */
bool fGCEnabled;
/** Flag whether the R0 part of the device is enabled. */
bool fR0Enabled;
/** The state the controller is currently in. */
/** Who needs to init the driver to get into operational state. */
/** Flag whether we are in doorbell function. */
bool fDoorbellInProgress;
/** Flag whether diagnostic access is enabled. */
bool fDiagnosticEnabled;
/** Flag whether a notification was send to R3. */
bool fNotificationSend;
/** Flag whether the guest enabled event notification from the IOC. */
#if HC_ARCH_BITS == 64
#endif
/** Queue to send tasks to R3. - R3 ptr */
/** Queue to send tasks to R3. - R0 ptr */
/** Queue to send tasks to R3. - RC ptr */
#if HC_ARCH_BITS == 64
#endif
/** States for attached devices. */
/** MMIO address the device is mapped to. */
/** I/O port address the device is mapped to. */
/** Interrupt mask. */
volatile uint32_t uInterruptMask;
/** Interrupt status register. */
volatile uint32_t uInterruptStatus;
/** Buffer for messages which are passed
* through the doorbell using the
* handshake method. */
/** Actual position in the buffer. */
/** Size of the message which is given in the doorbell message in dwords. */
/** Reply buffer. */
/** Next entry to read. */
/** Size of the reply in the buffer in 16bit words. */
/** The fault code of the I/O controller if we are in the fault state. */
/** Upper 32 bits of the moessage frame address to locate requests in guest memory. */
/** Upper 32 bits of the sense buffer address. */
/** Maximum number of devices the driver reported he can handle. */
/** Maximum number of buses the driver reported he can handle. */
/** Current size of reply message frames in the guest. */
/** Next key to write in the sequence to get access
* to diagnostic memory. */
/** Number entries allocated for the reply queue. */
/** Number entries allocated for the outstanding request queue. */
#if HC_ARCH_BITS == 64
#endif
/** Critical section protecting the reply post queue. */
/** Critical section protecting the reply free queue. */
/** Pointer to the start of the reply free queue - R3. */
/** Pointer to the start of the reply post queue - R3. */
/** Pointer to the start of the request queue - R3. */
/** Pointer to the start of the reply queue - R0. */
/** Pointer to the start of the reply queue - R0. */
/** Pointer to the start of the request queue - R0. */
/** Pointer to the start of the reply queue - RC. */
/** Pointer to the start of the reply queue - RC. */
/** Pointer to the start of the request queue - RC. */
/** Next free entry in the reply queue the guest can write a address to. */
volatile uint32_t uReplyFreeQueueNextEntryFreeWrite;
/** Next valid entry the controller can read a valid address for reply frames from. */
volatile uint32_t uReplyFreeQueueNextAddressRead;
/** Next free entry in the reply queue the guest can write a address to. */
volatile uint32_t uReplyPostQueueNextEntryFreeWrite;
/** Next valid entry the controller can read a valid address for reply frames from. */
volatile uint32_t uReplyPostQueueNextAddressRead;
/** Next free entry the guest can write a address to a request frame to. */
volatile uint32_t uRequestQueueNextEntryFreeWrite;
/** Next valid entry the controller can read a valid address for request frames from. */
volatile uint32_t uRequestQueueNextAddressRead;
/** Configuration pages. */
/** BIOS emulation. */
/** Cache for allocated tasks. */
/** The base interface */
/** Status Port - Leds interface. */
/** Partner of ILeds. */
} LSILOGISCSI, *PLSILOGICSCSI;
#define LSILOGIC_PCI_SPACE_IO_SIZE 256
#define LSILOGIC_REG_DOORBELL 0x00
#define LSILOGIC_REG_WRITE_SEQUENCE 0x04
#define LSILOGIC_REG_HOST_DIAGNOSTIC 0x08
#define LSILOGIC_REG_TEST_BASE_ADDRESS 0x0c
#define LSILOGIC_REG_DIAG_RW_DATA 0x10
#define LSILOGIC_REG_DIAG_RW_ADDRESS 0x14
#define LSILOGIC_REG_HOST_INTR_STATUS 0x30
# define LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL (RT_BIT(0))
#define LSILOGIC_REG_HOST_INTR_MASK 0x34
# define LSILOGIC_REG_HOST_INTR_MASK_DOORBELL RT_BIT(0)
#define LSILOGIC_REG_REQUEST_QUEUE 0x40
#define LSILOGIC_REG_REPLY_QUEUE 0x44
/* Functions which can be passed through the system doorbell. */
#define LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET 0x40
#define LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET 0x41
#define LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE 0x42
#define LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL 0x43
/**
* Scatter gather list entry data.
*/
typedef struct LSILOGICTASKSTATESGENTRY
{
/** Flag whether the buffer in the list is from the guest or an
* allocated temporary buffer because the segments in the guest
* are not sector aligned.
*/
bool fGuestMemory;
/** Flag whether the buffer contains data or is the destination for the transfer. */
bool fBufferContainsData;
/** Pointer to the start of the buffer. */
void *pvBuf;
/** Size of the buffer. */
/** Flag dependent data. */
union
{
/** Data to handle direct mappings of guest buffers. */
/** The segment in the guest which is not sector aligned. */
} u;
/**
* Task state object which holds all neccessary data while
* processing the request from the guest.
*/
typedef struct LSILOGICTASKSTATE
{
/** Target device. */
/** The message request from the guest. */
/** Reply message if the request produces one. */
/** SCSI request structure for the SCSI driver. */
/** Address of the message request frame in guests memory.
* Used to read the S/G entries in the second step. */
/** Number of scatter gather list entries. */
/** How many entries would fit into the sg list. */
/** How many times the list was too big. */
/** Pointer to the first entry of the scatter gather list. */
/** How many entries would fit into the sg info list. */
/** Number of entries for the information entries. */
/** How many times the list was too big. */
/** Pointer to the first mapping information entry. */
/** Size of the temporary buffer for unaligned guest segments. */
/** Pointer to the temporary buffer. */
void *pvBufferUnaligned;
/** Pointer to the sense buffer. */
/** Flag whether the request was issued from the BIOS. */
bool fBIOS;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#ifdef IN_RING3
static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
#endif
#define PDMIBASE_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, IBase)) )
#define PDMISCSIPORT_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ISCSIPort)) )
#define PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ILed)) )
#define PDMIBASE_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, IBase)) )
#define PDMILEDPORTS_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, ILeds)) )
/** Key sequence the guest has to write to enable access
* to diagnostic memory. */
/**
* Updates the status of the interrupt pin of the device.
*
* @returns nothing.
* @param pThis Pointer to the device instance data.
*/
{
LogFlowFunc(("Updating interrupts\n"));
/* Mask out doorbell status so that it does not affect interrupt updating. */
uIntSts = (ASMAtomicReadU32(&pThis->uInterruptStatus) & ~LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS);
/* Check maskable interrupts. */
if (uIntSts)
{
LogFlowFunc(("Setting interrupt\n"));
}
else
{
LogFlowFunc(("Clearing interrupt\n"));
}
}
/**
* Sets a given interrupt status bit in the status register and
* updates the interupt status.
*
* @returns nothing.
* @param pLsiLogic Pointer to the device instance.
* @param uStatus The status bit to set.
*/
{
}
/**
* Clears a given interrupt status bit in the status register and
* updates the interupt status.
*
* @returns nothing.
* @param pLsiLogic Pointer to the device instance.
* @param uStatus The status bit to set.
*/
{
}
/**
* Sets the I/O controller into fault state and sets the fault code.
*
* @returns nothing
* @param pLsiLogic Pointer to the controller device instance.
* @param uIOCFaultCode Fault code to set.
*/
{
{
Log(("%s: Setting I/O controller into FAULT state: uIOCFaultCode=%u\n", __FUNCTION__, uIOCFaultCode));
}
else
{
Log(("%s: We are already in FAULT state\n"));
}
}
#ifdef IN_RING3
/**
* Performs a hard reset on the controller.
*
* @returns VBox status code.
* @param pThis Pointer to the device instance to initialize.
*/
{
/* The interrupts are masked out. */
/* Reset interrupt states. */
pThis->uInterruptStatus = 0;
/* Reset the queues. */
/* Disable diagnostic access. */
pThis->iDiagnosticAccess = 0;
/* Set default values. */
/* @todo: Put stuff to reset here. */
/* Mark that we finished performing the reset. */
return VINF_SUCCESS;
}
/**
* Finishes a context reply.
*
* @returns nothing
* @param pLsiLogic Pointer to the device instance
* @param u32MessageContext The message context ID to post.
*/
{
int rc;
/* Write message context ID into reply post queue. */
#if 0
/* Check for a entry in the queue. */
if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
{
/* Set error code. */
return;
}
#endif
/* We have a context reply. */
ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite], u32MessageContext);
/* Set interrupt. */
}
#endif /* IN_RING3 */
/**
* Takes neccessary steps to finish a reply frame.
*
* @returns nothing
* @param pLsiLogic Pointer to the device instance
* @param pReply Pointer to the reply message.
* @param fForceReplyFifo Flag whether the use of the reply post fifo is forced.
*/
static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion pReply, bool fForceReplyFifo)
{
/*
* If we are in a doorbell function we set the reply size now and
* set the system doorbell status interrupt to notify the guest that
* we are ready to send the reply.
*/
{
/* Set size of the reply in 16bit words. The size in the reply is in 32bit dwords. */
pLsiLogic->uNextReplyEntryRead = 0;
}
else
{
/*
* The reply queues are only used if the request was fetched from the request queue.
* Requests from the request queue are always transferred to R3. So it is not possible
* that this case happens in R0 or GC.
*/
#ifdef IN_RING3
int rc;
/* Grab a free reply message from the queue. */
#if 0
/* Check for a free reply frame. */
if (RT_UNLIKELY(pLsiLogic->uReplyFreeQueueNextAddressRead != pLsiLogic->uReplyFreeQueueNextEntryFreeWrite))
{
/* Set error code. */
return;
}
#endif
uint32_t u32ReplyFrameAddressLow = pLsiLogic->CTX_SUFF(pReplyFreeQueueBase)[pLsiLogic->uReplyFreeQueueNextAddressRead];
/* Build 64bit physical address. */
RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pLsiLogic->u32HostMFAHighAddr, u32ReplyFrameAddressLow);
size_t cbReplyCopied = (pLsiLogic->cbReplyFrame < sizeof(MptReplyUnion)) ? pLsiLogic->cbReplyFrame : sizeof(MptReplyUnion);
/* Write reply to guest memory. */
/* Write low 32bits of reply frame into post reply queue. */
#if 0
/* Check for a entry in the queue. */
if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
{
/* Set error code. */
return;
}
#endif
/* We have a address reply. Set the 31th bit to indicate that. */
ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite],
if (fForceReplyFifo)
{
pLsiLogic->fDoorbellInProgress = false;
}
/* Set interrupt. */
#else
AssertMsgFailed(("This is not allowed to happen.\n"));
#endif
}
}
#ifdef IN_RING3
/**
* Processes a given Request from the guest
*
* @returns VBox status code.
* @param pLsiLogic Pointer to the device instance.
* @param pMessageHdr Pointer to the message header of the request.
* @param pReply Pointer to the reply.
*/
static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pMessageHdr, PMptReplyUnion pReply)
{
int rc = VINF_SUCCESS;
bool fForceReplyPostFifo = false;
#ifdef DEBUG
else
Log(("Message request function: <unknown>\n"));
#endif
switch (pMessageHdr->u8Function)
{
{
//AssertMsgFailed(("todo\n"));
fForceReplyPostFifo = true;
break;
}
{
/*
* This request sets the I/O controller to the
* operational state.
*/
/* Update configuration values. */
{
}
/* Return reply. */
break;
}
{
pReply->IOCFacts.u8BlockSize = 12; /* Block size in 32bit dwords. This is the largest request we can get (SCSI I/O). */
pReply->IOCFacts.u8Flags = 0; /* Bit 0 is set if the guest must upload the FW prior to using the controller. Obviously not needed here. */
pReply->IOCFacts.u16ReplyQueueDepth = pLsiLogic->cReplyQueueEntries - 1; /* One entry is always free. */
pReply->IOCFacts.u16GlobalCredits = pLsiLogic->cRequestQueueEntries - 1; /* One entry is always free. */
break;
}
{
/* This controller only supports one bus with bus number 0. */
if (pPortFactsReq->u8PortNumber != 0)
{
}
else
{
pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
}
break;
}
{
/*
* The port enable request notifies the IOC to make the port available and perform
* appropriate discovery on the associated link.
*/
break;
}
{
pLsiLogic->fEventNotificationEnabled = true;
else
pLsiLogic->fEventNotificationEnabled = false;
break;
}
{
AssertMsgFailed(("todo"));
break;
}
{
break;
}
case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: /* Should be handled already. */
default:
}
/* Copy common bits from request message frame to reply. */
return rc;
}
#endif
/**
* Writes a value to a register at a given offset.
*
* @returns VBox status code.
* @param pThis Pointer to the LsiLogic SCSI controller instance data.
* @param uOffset Offset of the register to write.
* @param pv Pointer to the value to write
* @param cb Number of bytes to write.
*/
{
switch (uOffset)
{
case LSILOGIC_REG_REPLY_QUEUE:
{
/* Add the entry to the reply free queue. */
ASMAtomicWriteU32(&pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextEntryFreeWrite], u32);
break;
}
{
ASMAtomicWriteU32(&pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextEntryFreeWrite], u32);
/* Send notification to R3 if there is not one send already. */
{
}
break;
}
case LSILOGIC_REG_DOORBELL:
{
/*
* When the guest writes to this register a real device would set the
* doorbell status bit in the interrupt status register to indicate that the IOP
* has still to process the message.
* The guest needs to wait with posting new messages here until the bit is cleared.
* Because the guest is not continuing execution while we are here we can skip this.
*/
if (!pThis->fDoorbellInProgress)
{
switch (uFunction)
{
{
/* Reset interrupt states. */
pThis->uInterruptMask = 0;
pThis->uInterruptStatus = 0;
/* Reset the queues. */
break;
}
{
AssertMsgFailed(("todo\n"));
break;
}
{
pThis->fDoorbellInProgress = true;
/* Update the interrupt status to notify the guest that a doorbell function was started. */
break;
}
{
AssertMsgFailed(("todo\n"));
break;
}
default:
}
}
else
{
/*
* We are already performing a doorbell function.
* Get the remaining parameters.
*/
AssertMsg(pThis->iMessage < RT_ELEMENTS(pThis->aMessage), ("Message is too big to fit into the buffer\n"));
/*
* If the last byte of the message is written, force a switch to R3 because some requests might force
* a reply through the FIFO which cannot be handled in GC or R0.
*/
#ifndef IN_RING3
return VINF_IOM_HC_MMIO_WRITE;
#endif
#ifdef IN_RING3
{
int rc = lsilogicProcessMessageRequest(pThis, (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer);
}
#endif
}
break;
}
{
/*
* Clear the bits the guest wants except the system doorbell interrupt and the IO controller
* status bit.
* The former bit is always cleared no matter what the guest writes to the register and
* the latter one is read only.
*/
/*
* Check if there is still a doorbell function in progress. Set the
* system doorbell interrupt bit again if it is.
* We do not use lsilogicSetInterrupt here because the interrupt status
* is updated afterwards anyway.
*/
if ( (pThis->fDoorbellInProgress)
{
{
/* Reply finished. Reset doorbell in progress status. */
pThis->fDoorbellInProgress = false;
}
}
break;
}
{
break;
}
{
if (pThis->fDiagnosticEnabled)
{
/* Any value will cause a reset and disabling access. */
pThis->fDiagnosticEnabled = false;
pThis->iDiagnosticAccess = 0;
}
{
{
/*
* Key sequence successfully written. Enable access to diagnostic
* memory and register.
*/
pThis->fDiagnosticEnabled = true;
}
}
else
{
/* Wrong value written - reset to beginning. */
pThis->iDiagnosticAccess = 0;
}
break;
}
default: /* Ignore. */
{
break;
}
}
return VINF_SUCCESS;
}
/**
* Reads the content of a register at a given offset.
*
* @returns VBox status code.
* @param pThis Pointer to the LsiLogic SCSI controller instance data.
* @param uOffset Offset of the register to read.
* @param pv Where to store the content of the register.
* @param cb Number of bytes to read.
*/
{
switch (uOffset)
{
case LSILOGIC_REG_REPLY_QUEUE:
{
{
}
else
{
/* The reply post queue is empty. Reset interrupt. */
}
break;
}
case LSILOGIC_REG_DOORBELL:
{
/*
* If there is a doorbell function in progress we pass the return value
* instead of the status code. We transfer 16bit of the reply
* during one read.
*/
if (pThis->fDoorbellInProgress)
{
/* Return next 16bit value. */
}
else
{
/* We return the status code of the I/O controller. */
}
break;
}
{
break;
}
{
break;
}
{
//AssertMsgFailed(("todo\n"));
break;
}
{
AssertMsgFailed(("todo\n"));
break;
}
{
AssertMsgFailed(("todo\n"));
break;
}
{
AssertMsgFailed(("todo\n"));
break;
}
default: /* Ignore. */
{
break;
}
}
return VINF_SUCCESS;
}
{
if (rc == VINF_IOM_HC_MMIO_WRITE)
return rc;
}
{
}
{
}
{
}
{
LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
return VINF_SUCCESS;
}
{
LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
return VINF_SUCCESS;
}
#ifdef IN_RING3
/**
* Copies a contigous buffer into the scatter gather list provided by the guest.
*
* @returns nothing
* @param pTaskState Pointer to the task state which contains the SGL.
* @param pvBuf Pointer to the buffer to copy.
* @param cbCopy Number of bytes to copy.
*/
static void lsilogicScatterGatherListCopyFromBuffer(PLSILOGICTASKSTATE pTaskState, void *pvBuf, size_t cbCopy)
{
unsigned cSGEntry = 0;
{
/* We finished. */
if (!cbCopy)
break;
/* Advance the buffer. */
/* Go to the next entry in the list. */
pSGEntry++;
cSGEntry++;
}
}
/**
* Copy a temporary buffer into a part of the guest scatter gather list
* described by the given descriptor entry.
*
* @returns nothing.
* @param pDevIns Pointer to the device instance data.
* @param pSGInfo Pointer to the segment info structure which describes the guest segments
* to write to which are unaligned.
*/
{
/* Copy into SG entry. */
}
/**
* Copy a part of the guest scatter gather list into a temporary buffer.
*
* @returns nothing.
* @param pDevIns Pointer to the device instance data.
* @param pSGInfo Pointer to the segment info structure which describes the guest segments
* to read from which are unaligned.
*/
{
/* Copy into temporary buffer. */
}
static int lsilogicScatterGatherListAllocate(PLSILOGICTASKSTATE pTaskState, uint32_t cSGList, uint32_t cSGInfo, uint32_t cbUnaligned)
{
{
/* The entries are not allocated yet or the number is too small. */
if (pTaskState->cSGListSize)
/* Allocate R3 scatter gather list. */
if (!pTaskState->pSGListHead)
return VERR_NO_MEMORY;
/* Reset usage statistics. */
pTaskState->cSGListTooBig = 0;
}
{
/*
* The list is too big. Increment counter.
* So that the destroying function can free
* the list if it is too big too many times
* in a row.
*/
}
else
{
/*
* Needed entries matches current size.
* Reset counter.
*/
pTaskState->cSGListTooBig = 0;
}
{
/* The entries are not allocated yet or the number is too small. */
if (pTaskState->cSGInfoSize)
pTaskState->paSGEntries = (PLSILOGICTASKSTATESGENTRY)RTMemAllocZ(cSGInfo * sizeof(LSILOGICTASKSTATESGENTRY));
if (!pTaskState->paSGEntries)
return VERR_NO_MEMORY;
/* Reset usage statistics. */
pTaskState->cSGInfoTooBig = 0;
}
{
/*
* The list is too big. Increment counter.
* So that the destroying function can free
* the list if it is too big too many times
* in a row.
*/
}
else
{
/*
* Needed entries matches current size.
* Reset counter.
*/
pTaskState->cSGInfoTooBig = 0;
}
{
if (pTaskState->pvBufferUnaligned)
if (!pTaskState->pvBufferUnaligned)
return VERR_NO_MEMORY;
}
/* Make debugging easier. */
#ifdef DEBUG
if (pTaskState->pvBufferUnaligned)
#endif
return VINF_SUCCESS;
}
/**
* Destroy a scatter gather list.
*
* @returns nothing.
* @param pLsiLogic Pointer to the LsiLogic SCSI controller.
* @param pTaskState Pointer to the task state.
*/
static void lsilogicScatterGatherListDestroy(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
{
for (unsigned i = 0; i < pTaskState->cSGInfoEntries; i++)
{
if (pSGInfoCurr->fGuestMemory)
{
/* Release the lock. */
}
else if (!pSGInfoCurr->fBufferContainsData)
{
/* Copy the data into the guest segments now. */
}
pSGInfoCurr++;
}
/* Free allocated memory if the list was too big too many times. */
{
if (pTaskState->pvBufferUnaligned)
pTaskState->cSGListSize = 0;
pTaskState->cSGInfoSize = 0;
pTaskState->cSGInfoEntries = 0;
pTaskState->cSGListTooBig = 0;
pTaskState->cbBufferUnaligned = 0;
}
}
#ifdef DEBUG
/**
* Dump an SG entry.
*
* @returns nothing.
* @param pSGEntry Pointer to the SG entry to dump
*/
{
{
case MPTSGENTRYTYPE_SIMPLE:
{
Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
{
Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh));
((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32) | pSGEntry->Simple64.u32DataBufferAddressLow));
}
else
break;
}
case MPTSGENTRYTYPE_CHAIN:
{
else
break;
}
}
}
#endif
/**
* Create scatter gather list descriptors.
*
* @returns VBox status code.
* @param pLsiLogic Pointer to the LsiLogic SCSI controller.
* @param pTaskState Pointer to the task state.
* @param GCPhysSGLStart Guest physical address of the first SG entry.
* @param uChainOffset Offset in bytes from the beginning of the SGL segment to the chain element.
* @thread EMT
*/
{
int rc = VINF_SUCCESS;
bool fUnaligned; /* Flag whether the current buffer is unaligned. */
uint32_t cSGEntriesR3 = 0;
bool fDoMapping = false;
bool fEndOfList;
/*
* Two passes - one to count needed scatter gather list entries and needed unaligned
* buffers and one to actually map the SG list into R3.
*/
for (int i = 0; i < 2; i++)
{
fUnaligned = false;
cbUnaligned = 0;
fEndOfList = false;
if (fDoMapping)
{
/* The number of needed SG entries in R3 is known. Allocate needed memory. */
/* We are now able to map the pages into R3. */
/* Initialize first segment to remove the need for additional if checks later in the code. */
pSGInfoCurr->fGuestMemory= false;
}
/* Go through the list until we reach the end. */
while (!fEndOfList)
{
bool fEndOfSegment = false;
while (!fEndOfSegment)
{
/* Read the entry. */
#ifdef DEBUG
#endif
/* Check if this is a zero element. */
{
pTaskState->cSGListEntries = 0;
pTaskState->cSGInfoEntries = 0;
return VINF_SUCCESS;
}
{
GCPhysSGEntryNext += sizeof(MptSGEntrySimple64);
}
else
GCPhysSGEntryNext += sizeof(MptSGEntrySimple32);
if (fDoMapping)
{
pSGInfoCurr->fGuestMemory = false;
if (fBufferContainsData)
pSGInfoCurr++;
}
else
{
cSGInfo++;
}
/* Check if we reached the end of the list. */
{
/* We finished. */
fEndOfSegment = true;
fEndOfList = true;
}
{
fEndOfSegment = true;
}
} /* while (!fEndOfSegment) */
/* Get next chain element. */
if (uChainOffsetNext)
{
PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + uChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
/* Set the next address now. */
}
} /* while (!fEndOfList) */
fDoMapping = true;
if (fUnaligned)
}
/* Initialize first entry. */
pSGInfoCurr++;
cSGEntries = 1;
/* Construct the scatter gather list. */
{
{
("Buffer ist not sector aligned but the buffer addresses are not adjacent\n"));
}
else
{
{
}
else
{
pSGEntryCurr++;
cSGEntries++;
}
}
pSGInfoCurr++;
}
return rc;
}
/*
* Disabled because the sense buffer provided by the LsiLogic driver for Windows XP
* crosses page boundaries.
*/
#if 0
/**
* Free the sense buffer.
*
* @returns nothing.
* @param pTaskState Pointer to the task state.
*/
{
}
/**
* Map the sense buffer into R3.
*
* @returns VBox status code.
* @param pTaskState Pointer to the task state.
* @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary.
*/
{
int rc = VINF_SUCCESS;
#ifdef RT_STRICT
#endif
("Impossible GCPhysAddrSenseBuffer < GCPhysAddrSenseBufferBase\n"));
/* Sanity checks for the assumption. */
("Sense buffer crosses page boundary\n"));
rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrSenseBufferBase, (void **)&pTaskState->pbSenseBuffer, &pTaskState->PageLockSense);
/* Correct start address of the sense buffer. */
return rc;
}
#endif
#ifdef DEBUG
{
Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
}
#endif
/**
* Processes a SCSI I/O request by setting up the request
* and sending it to the underlying SCSI driver.
* Steps needed to complete request are done in the
* callback called by the driver below upon completion of
* the request.
*
* @returns VBox status code.
* @param pLsiLogic Pointer to the device instance which sends the request.
* @param pTaskState Pointer to the task state data.
*/
{
int rc = VINF_SUCCESS;
#ifdef DEBUG
#endif
pTaskState->fBIOS = false;
if (uChainOffset)
/* Create Scatter gather list. */
#if 0
/* Map sense buffer. */
#endif
{
if (pTargetDevice->pDrvBase)
{
/* Setup the SCSI request. */
uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pTaskState->GuestRequest.SCSIIO.u32Control);
else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ)
rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest);
return VINF_SUCCESS;
}
else
{
/* Device is not present report SCSI selection timeout. */
}
}
else
{
/* Report out of bounds target ID or bus. */
else
}
/* The rest is equal to both errors. */
pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext;
return rc;
}
/**
* Called upon completion of the request from the SCSI driver below.
* This function frees all allocated ressources and notifies the guest
* that the process finished by asserting an interrupt.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface the called funtion belongs to.
* @param pSCSIRequest Pointer to the SCSI request which finished.
*/
static DECLCALLBACK(int) lsilogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, int rcCompletion)
{
{
}
else
{
#if 0
#else
/* Copy the sense buffer over. */
RT_UNLIKELY(pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength < pTaskState->PDMScsiRequest.cbSenseBuffer)
#endif
else
{
/* The SCSI target encountered an error during processing post a reply. */
pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext;
}
}
return VINF_SUCCESS;
}
/**
* Return the configuration page header and data
* which matches the given page type and number.
*
* @returns VINF_SUCCESS if successful
* VERR_NOT_FOUND if the requested page could be found.
* @param u8PageNumber Number of the page to get.
* @param ppPageHeader Where to store the pointer to the page header.
* @param ppbPageData Where to store the pointer to the page data.
*/
static int lsilogicConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pLsiLogic, uint8_t u8PageNumber,
{
int rc = VINF_SUCCESS;
switch(u8PageNumber)
{
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
default:
rc = VERR_NOT_FOUND;
}
return rc;
}
/**
* Return the configuration page header and data
* which matches the given page type and number.
*
* @returns VINF_SUCCESS if successful
* VERR_NOT_FOUND if the requested page could be found.
* @param u8PageNumber Number of the page to get.
* @param ppPageHeader Where to store the pointer to the page header.
* @param ppbPageData Where to store the pointer to the page data.
*/
{
int rc = VINF_SUCCESS;
switch(u8PageNumber)
{
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 6:
break;
default:
rc = VERR_NOT_FOUND;
}
return rc;
}
/**
* Return the configuration page header and data
* which matches the given page type and number.
*
* @returns VINF_SUCCESS if successful
* VERR_NOT_FOUND if the requested page could be found.
* @param u8PageNumber Number of the page to get.
* @param ppPageHeader Where to store the pointer to the page header.
* @param ppbPageData Where to store the pointer to the page data.
*/
static int lsilogicConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pLsiLogic, uint8_t u8PageNumber,
{
int rc = VINF_SUCCESS;
switch(u8PageNumber)
{
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
default:
rc = VERR_NOT_FOUND;
}
return rc;
}
/**
* Return the configuration page header and data
* which matches the given page type and number.
*
* @returns VINF_SUCCESS if successful
* VERR_NOT_FOUND if the requested page could be found.
* @param u8PageNumber Number of the page to get.
* @param ppPageHeader Where to store the pointer to the page header.
* @param ppbPageData Where to store the pointer to the page data.
*/
static int lsilogicConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pLsiLogic, uint8_t u8Port,
{
int rc = VINF_SUCCESS;
return VERR_NOT_FOUND;
switch(u8PageNumber)
{
case 0:
break;
case 1:
break;
case 2:
break;
default:
rc = VERR_NOT_FOUND;
}
return rc;
}
/**
* Return the configuration page header and data
* which matches the given page type and number.
*
* @returns VINF_SUCCESS if successful
* VERR_NOT_FOUND if the requested page could be found.
* @param u8PageNumber Number of the page to get.
* @param ppPageHeader Where to store the pointer to the page header.
* @param ppbPageData Where to store the pointer to the page data.
*/
static int lsilogicConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pLsiLogic, uint8_t u8Bus,
{
int rc = VINF_SUCCESS;
return VERR_NOT_FOUND;
return VERR_NOT_FOUND;
switch(u8PageNumber)
{
case 0:
*ppPageHeader = &pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
*ppbPageData = pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
*pcbPage = sizeof(pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0);
break;
case 1:
*ppPageHeader = &pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
*ppbPageData = pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
*pcbPage = sizeof(pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1);
break;
case 2:
*ppPageHeader = &pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
*ppbPageData = pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
*pcbPage = sizeof(pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2);
break;
case 3:
*ppPageHeader = &pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
*ppbPageData = pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
*pcbPage = sizeof(pLsiLogic->ConfigurationPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3);
break;
default:
rc = VERR_NOT_FOUND;
}
return rc;
}
/**
* Processes a Configuration request.
*
* @returns VBox status code.
* @param pLsiLogic Pointer to the device instance which sends the request.
* @param pConfigurationReq Pointer to the request structure.
* @param pReply Pointer to the reply message frame
*/
static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
{
int rc = VINF_SUCCESS;
/* Copy common bits from the request into the reply. */
switch (u8PageType)
{
{
/* Get the page data. */
break;
}
{
/* Get the page data. */
break;
}
{
/* Get the page data. */
break;
}
{
/* Get the page data. */
break;
}
{
/* Get the page data. */
break;
}
default:
rc = VERR_NOT_FOUND;
}
if (rc == VERR_NOT_FOUND)
{
//AssertMsgFailed(("todo\n"));
return VINF_SUCCESS;
}
for (int i = 0; i < pReply->u8PageLength; i++)
/*
* Don't use the scatter gather handling code as the configuration request always have only one
* simple element.
*/
switch (pConfigurationReq->u8Action)
{
case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT: /* Nothing to do. We are always using the defaults. */
{
/* Already copied above nothing to do. */
break;
}
{
if (cbBuffer != 0)
{
GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
}
break;
}
{
if (cbBuffer != 0)
{
GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
}
break;
}
default:
AssertMsgFailed(("todo\n"));
}
return VINF_SUCCESS;
}
/**
* Initializes the configuration pages.
*
* @returns nothing
* @param pLsiLogic Pointer to the Lsilogic SCSI instance.
*/
{
/* Clear everything first. */
/* Manufacturing Page 0. */
pPages->ManufacturingPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY
pPages->ManufacturingPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageManufacturing0) / 4;
/* Manufacturing Page 1 - I don't know what this contains so we leave it 0 for now. */
/* Manufacturing Page 2. */
pPages->ManufacturingPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageManufacturing2) / 4;
/* Hardware specific settings - everything 0 for now. */
/* Manufacturing Page 3. */
pPages->ManufacturingPage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageManufacturing3) / 4;
/* Chip specific settings - everything 0 for now. */
/* Manufacturing Page 4 - I don't know what this contains so we leave it 0 for now. */
pPages->ManufacturingPage4.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY
pPages->ManufacturingPage4.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageManufacturing4) / 4;
/* I/O Unit page 0. */
/* I/O Unit page 1. */
/* I/O Unit page 2. */
/* I/O Unit page 3. */
/* IOC page 0. */
/* IOC page 1. */
/* IOC page 2. */
/* Everything else here is 0. */
/* IOC page 3. */
/* Everything else here is 0. */
/* IOC page 4. */
/* Everything else here is 0. */
/* IOC page 6. */
/* Everything else here is 0. */
{
/* SCSI-SPI port page 0. */
pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
/* SCSI-SPI port page 1. */
pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
/* SCSI-SPI port page 2. */
pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
for (unsigned iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++)
{
}
/* Everything else 0 for now. */
}
{
for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
{
/* SCSI-SPI device page 0. */
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
/* Everything else 0 for now. */
/* SCSI-SPI device page 1. */
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
/* Everything else 0 for now. */
/* SCSI-SPI device page 2. */
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
/* Everything else 0 for now. */
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
/* Everything else 0 for now. */
}
}
}
/**
* Transmit queue consumer
* Queue a new async task.
*
* @returns Success indicator.
* If false the item will not be removed and the flushing will stop.
* @param pDevIns The device instance.
* @param pItem The item to consume. Upon return this item will be freed.
*/
{
int rc = VINF_SUCCESS;
/* Only process request which arrived before we received the notification. */
uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pLsiLogic->uRequestQueueNextEntryFreeWrite);
/* Reset notification event. */
/* Go through the messages now and process them. */
{
uint32_t u32RequestMessageFrameDesc = pLsiLogic->CTX_SUFF(pRequestQueueBase)[pLsiLogic->uRequestQueueNextAddressRead];
(u32RequestMessageFrameDesc & ~0x07));
/* Get new task state. */
/* Read the message header from the guest first. */
PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, sizeof(MptMessageHdr));
/* Determine the size of the request. */
{
cbRequest = sizeof(MptSCSIIORequest);
break;
cbRequest = sizeof(MptSCSITaskManagementRequest);
break;
cbRequest = sizeof(MptIOCInitRequest);
break;
cbRequest = sizeof(MptIOCFactsRequest);
break;
cbRequest = sizeof(MptConfigurationRequest);
break;
cbRequest = sizeof(MptPortFactsRequest);
break;
cbRequest = sizeof(MptPortEnableRequest);
break;
cbRequest = sizeof(MptEventNotificationRequest);
break;
AssertMsgFailed(("todo\n"));
//cbRequest = sizeof(MptEventAckRequest);
break;
AssertMsgFailed(("todo\n"));
break;
default:
}
if (cbRequest != 0)
{
/* Read the complete message frame from guest memory now. */
/* Handle SCSI I/O requests now. */
{
}
else
{
}
}
}
return true;
}
/**
* Port I/O Handler for IN operations - legacy port.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param uPort Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
{
int rc;
Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n",
return rc;
}
/**
* Prepares a request from the BIOS.
*
* @returns VBox status code.
* @param pLsiLogic Pointer to the LsiLogic device instance.
*/
{
int rc;
pTaskState->fBIOS = true;
{
/* Device is not present. */
("Device is not present but command is not inquiry\n"));
ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
}
else
{
rc = pTaskState->pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->pTargetDevice->pDrvSCSIConnector,
}
return rc;
}
/**
* Port I/O Handler for OUT operations - legacy port.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param uPort Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
{
int rc;
Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n",
if (rc == VERR_MORE_DATA)
{
}
else if (RT_FAILURE(rc))
return VINF_SUCCESS;
}
/**
* Port I/O Handler for primary port range OUT string operations.
* @see FNIOMIOPORTOUTSTRING for details.
*/
static DECLCALLBACK(int) lsilogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
{
int rc;
Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
if (rc == VERR_MORE_DATA)
{
}
else if (RT_FAILURE(rc))
return rc;
}
/**
* Port I/O Handler for primary port range IN string operations.
* @see FNIOMIOPORTINSTRING for details.
*/
static DECLCALLBACK(int) lsilogicIsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
{
LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
}
{
int rc = VINF_SUCCESS;
("PCI region type and size do not match\n"));
{
/* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
if (RT_FAILURE(rc))
return rc;
if (pThis->fR0Enabled)
{
if (RT_FAILURE(rc))
return rc;
}
if (pThis->fGCEnabled)
{
if (RT_FAILURE(rc))
return rc;
}
}
{
/* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
if (RT_FAILURE(rc))
return rc;
if (pThis->fR0Enabled)
{
if (RT_FAILURE(rc))
return rc;
}
if (pThis->fGCEnabled)
{
if (RT_FAILURE(rc))
return rc;
}
}
else if (enmType == PCI_ADDRESS_SPACE_IO)
{
if (RT_FAILURE(rc))
return rc;
if (pThis->fR0Enabled)
{
if (RT_FAILURE(rc))
return rc;
}
if (pThis->fGCEnabled)
{
if (RT_FAILURE(rc))
return rc;
}
}
else
return rc;
}
/**
* Waits until all I/O operations on all devices are complete.
*
* @retruns Flag which indicates if all I/O completed in the given timeout.
* @param pLsiLogic Pointer to the dveice instance to check.
* @param cMillis Timeout in milliseconds to wait.
*/
{
bool fIdle;
/*
* Wait for any pending async operation to finish
*/
u64Start = RTTimeMilliTS();
do
{
fIdle = true;
/* Check every port. */
{
{
fIdle = false;
break;
}
}
break;
/* Sleep for a bit. */
RTThreadSleep(100);
} while (!fIdle);
return fIdle;
}
{
/* Wait that no task is pending on any device. */
{
AssertLogRelMsgFailed(("LsiLogic: There are still tasks outstanding\n"));
return VERR_TIMEOUT;
}
return VINF_SUCCESS;
}
{
/* Every device first. */
{
("There are still outstanding requests on this device\n"));
}
/* Now the main device state. */
/* Now the data for the BIOS interface. */
return SSMR3PutU32(pSSM, ~0);
}
static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
/* We support saved states only from this and older versions. */
/* Every device first. */
{
("There are still outstanding requests on this device\n"));
}
/* Now the main device state. */
/* Now the data for the BIOS interface. */
{
{
LogRel(("LsiLogic: Out of memory during restore.\n"));
N_("LsiLogic: Out of memory during restore\n"));
}
}
if (RT_FAILURE(rc))
return rc;
return VINF_SUCCESS;
}
/**
* Gets the pointer to the status LED of a device - called from the SCSi driver.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param iLUN The unit which status LED we desire. Always 0 here as the driver
* doesn't know about other LUN's.
* @param ppLed Where to store the LED pointer.
*/
static DECLCALLBACK(int) lsilogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
{
if (iLUN == 0)
{
return VINF_SUCCESS;
}
return VERR_PDM_LUN_NOT_FOUND;
}
/**
* Queries an interface to the driver.
*
* @returns Pointer to interface.
* @returns NULL if the interface was not supported by the device.
* @param pInterface Pointer to LSILOGICDEVICE::IBase.
* @param enmInterface The requested interface identification.
*/
static DECLCALLBACK(void *) lsilogicDeviceQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
{
switch (enmInterface)
{
case PDMINTERFACE_SCSI_PORT:
case PDMINTERFACE_LED_PORTS:
default:
return NULL;
}
}
/**
* Gets the pointer to the status LED of a unit.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param iLUN The unit which status LED we desire.
* @param ppLed Where to store the LED pointer.
*/
static DECLCALLBACK(int) lsilogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
{
if (iLUN < LSILOGIC_DEVICES_MAX)
{
return VINF_SUCCESS;
}
return VERR_PDM_LUN_NOT_FOUND;
}
/**
* Queries an interface to the driver.
*
* @returns Pointer to interface.
* @returns NULL if the interface was not supported by the device.
* @param pInterface Pointer to ATADevState::IBase.
* @param enmInterface The requested interface identification.
*/
static DECLCALLBACK(void *) lsilogicStatusQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
{
switch (enmInterface)
{
case PDMINTERFACE_BASE:
case PDMINTERFACE_LED_PORTS:
default:
return NULL;
}
}
/**
* Detach notification.
*
* One harddisk at one port has been unplugged.
* The VM is suspended at this point.
*
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*/
{
("LsiLogic: Device does not support hotplugging\n"));
/*
* Zero some important members.
*/
}
/**
* Attach command.
*
* This is called when we change block driver.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*/
{
int rc;
("LsiLogic: Device does not support hotplugging\n"),
/* the usual paranoia */
/*
* Try attach the block device and get the interfaces,
* required as well as optional.
*/
if (RT_SUCCESS(rc))
{
/* Get SCSI connector interface. */
pDevice->pDrvSCSIConnector = (PPDMISCSICONNECTOR)pDevice->pDrvBase->pfnQueryInterface(pDevice->pDrvBase, PDMINTERFACE_SCSI_CONNECTOR);
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
}
else
if (RT_FAILURE(rc))
{
}
return rc;
}
/**
* @copydoc FNPDMDEVPOWEROFF
*/
{
}
/**
* @copydoc FNPDMDEVSUSPEND
*/
{
}
/**
* @copydoc FNPDMDEVRESET
*/
{
int rc;
}
/**
* @copydoc FNPDMDEVRELOCATE
*/
{
/* Relocate queues. */
}
/**
* @copydoc FNPDMDEVDESTRUCT
*/
{
int rc = VINF_SUCCESS;
/* Destroy task cache. */
if (pThis->pTaskCache)
return rc;
}
/**
* @copydoc FNPDMDEVCONSTRUCT
*/
{
int rc = VINF_SUCCESS;
/*
* Validate and read configuration.
*/
"R0Enabled\0"
"ReplyQueueDepth\0"
"RequestQueueDepth\0");
if (RT_FAILURE(rc))
N_("LsiLogic configuration error: unknown option specified"));
if (RT_FAILURE(rc))
N_("LsiLogic configuration error: failed to read GCEnabled as boolean"));
if (RT_FAILURE(rc))
N_("LsiLogic configuration error: failed to read R0Enabled as boolean"));
if (RT_FAILURE(rc))
N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
if (RT_FAILURE(rc))
N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
/* Init static parts. */
/*
* Register the PCI device, it's I/O regions.
*/
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicMap);
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
if (RT_FAILURE(rc))
return rc;
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
if (RT_FAILURE(rc))
return rc;
/* Intialize task queue. */
if (RT_FAILURE(rc))
return rc;
/*
* We need one entry free in the queue.
*/
/*
* Allocate memory for the queues.
*/
(void **)&pThis->pReplyFreeQueueBaseR3);
if (RT_FAILURE(rc))
return VERR_NO_MEMORY;
/*
* Create critical sections protecting the reply post and free queues.
*/
if (RT_FAILURE(rc))
N_("LsiLogic: cannot create critical section for reply free queue"));
if (RT_FAILURE(rc))
N_("LsiLogic: cannot create critical section for reply post queue"));
/*
* Allocate task cache.
*/
if (RT_FAILURE(rc))
N_("Cannot create task cache"));
/* Initialize per device state. */
{
char szName[24];
/* Initialize static parts of the device. */
/* Attach SCSI driver. */
if (RT_SUCCESS(rc))
{
/* Get SCSI connector interface. */
pDevice->pDrvSCSIConnector = (PPDMISCSICONNECTOR)pDevice->pDrvBase->pfnQueryInterface(pDevice->pDrvBase, PDMINTERFACE_SCSI_CONNECTOR);
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
rc = VINF_SUCCESS;
}
else
{
return rc;
}
}
/*
* Attach status driver (optional).
*/
if (RT_SUCCESS(rc))
pThis->pLedsConnector = (PDMILEDCONNECTORS *)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
{
}
/* Initialize the SCSI emulation for the BIOS. */
/* Register I/O port space in ISA region for BIOS access. */
"LsiLogic BIOS");
if (RT_FAILURE(rc))
/* Register save state handlers. */
if (RT_FAILURE(rc))
/* Perform hard reset. */
return rc;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceLsiLogicSCSI =
{
/* u32Version */
/* szDeviceName */
"lsilogicscsi",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"LSI Logic 53c1030 SCSI controller.\n",
/* fFlags */
/* fClass */
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(LSILOGICSCSI),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
/* pfnSuspend */
/* pfnResume */
NULL,
/* pfnAttach */
/* pfnDetach */
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */