DevLsiLogicSCSI.cpp revision b983e853ab932523e352309e70047689a7540823
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * VBox storage devices: LsiLogic LSI53c1030 SCSI controller.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Copyright (C) 2006-2012 Oracle Corporation
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * General Public License (GPL) as published by the Free Software
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync//#define DEBUG
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** The current saved state version. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync/** The saved state version used by VirtualBox before SAS support was added. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync/** The saved state version used by VirtualBox 3.0 and earlier. It does not
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * include the device config part. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** Maximum number of entries in the release log. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Reply data.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Lower 32 bits of the reply address in memory. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Full address of the reply in guest memory. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Size of the reply. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Different views to the reply depending on the request type. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * State of a device attached to the buslogic host adapter.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @implements PDMIBASE
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @implements PDMISCSIPORT
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @implements PDMILEDPORTS
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync /** Pointer to the owning lsilogic device instance. - R3 pointer */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync /** LUN of the device. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Number of outstanding tasks on the port. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Our base interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** SCSI port interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Led interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the attached driver's base interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the underlying SCSI connector interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** The status LED state for this device. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** Pointer to a task state. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsynctypedef struct LSILOGICTASKSTATE *PLSILOGICTASKSTATE;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Device instance data for the emulated
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * SCSI controller.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsynctypedef struct LSILOGICSCSI
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** PCI device structure. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the device instance. - R3 ptr. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the device instance. - R0 ptr. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the device instance. - RC ptr. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether the GC part of the device is enabled. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether the R0 part of the device is enabled. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** The state the controller is currently in. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Who needs to init the driver to get into operational state. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Flag whether we are in doorbell function. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Flag whether diagnostic access is enabled. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Flag whether a notification was send to R3. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Flag whether the guest enabled event notification from the IOC. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Queue to send tasks to R3. - R3 ptr */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Queue to send tasks to R3. - R0 ptr */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Queue to send tasks to R3. - RC ptr */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Number of device states allocated. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** States for attached devices. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** MMIO address the device is mapped to. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** I/O port address the device is mapped to. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Interrupt mask. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Interrupt status register. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Buffer for messages which are passed
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * through the doorbell using the
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * handshake method. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync uint32_t aMessage[sizeof(MptConfigurationRequest)];
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Actual position in the buffer. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Size of the message which is given in the doorbell message in dwords. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Reply buffer. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next entry to read. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Size of the reply in the buffer in 16bit words. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** The fault code of the I/O controller if we are in the fault state. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Upper 32 bits of the message frame address to locate requests in guest memory. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Upper 32 bits of the sense buffer address. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Maximum number of devices the driver reported he can handle. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Maximum number of buses the driver reported he can handle. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Current size of reply message frames in the guest. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next key to write in the sequence to get access
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * to diagnostic memory. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Number entries allocated for the reply queue. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Number entries allocated for the outstanding request queue. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Critical section protecting the reply post queue. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Critical section protecting the reply free queue. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the reply free queue - R3. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R3PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR3;
bd96e81081052c309669f3f9b183cfec4fffbefbvboxsync /** Pointer to the start of the reply post queue - R3. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R3PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR3;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the request queue - R3. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R3PTRTYPE(volatile uint32_t *) pRequestQueueBaseR3;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the reply queue - R0. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R0PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the reply queue - R0. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R0PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the request queue - R0. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R0PTRTYPE(volatile uint32_t *) pRequestQueueBaseR0;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the reply queue - RC. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RCPTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseRC;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the reply queue - RC. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RCPTRTYPE(volatile uint32_t *) pReplyPostQueueBaseRC;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the request queue - RC. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync RCPTRTYPE(volatile uint32_t *) pRequestQueueBaseRC;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next free entry in the reply queue the guest can write a address to. */
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync volatile uint32_t uReplyFreeQueueNextEntryFreeWrite;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next valid entry the controller can read a valid address for reply frames from. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next free entry in the reply queue the guest can write a address to. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync volatile uint32_t uReplyPostQueueNextEntryFreeWrite;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next valid entry the controller can read a valid address for reply frames from. */
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync /** Next free entry the guest can write a address to a request frame to. */
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsync /** Next valid entry the controller can read a valid address for request frames from. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Emulated controller type */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Handle counter */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Number of ports this controller has. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** BIOS emulation. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Cache for allocated tasks. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Status LUN: The base interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Status LUN: Leds interface. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Status LUN: Partner of ILeds. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the configuration page area. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R3PTRTYPE(PMptConfigurationPagesSupported) pConfigurationPages;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * a port is entering the idle state. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync bool volatile fSignalIdle;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether we have tasks which need to be processed again- */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync bool volatile fRedo;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** List of tasks which can be redone. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync R3PTRTYPE(volatile PLSILOGICTASKSTATE) pTasksRedoHead;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Scatter gather list entry data.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether the buffer in the list is from the guest or an
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * allocated temporary buffer because the segments in the guest
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * are not sector aligned.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether the buffer contains data or is the destination for the transfer. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the start of the buffer. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Size of the buffer. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag dependent data. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Data to handle direct mappings of guest buffers. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** The segment in the guest which is not sector aligned. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync} LSILOGICTASKSTATESGENTRY, *PLSILOGICTASKSTATESGENTRY;
5a2abb913df18ed4e588e179043708667f7bc1a1vboxsync * Task state object which holds all necessary data while
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync * processing the request from the guest.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Next in the redo list. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Target device. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** The message request from the guest. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Reply message if the request produces one. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** SCSI request structure for the SCSI driver. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Address of the message request frame in guests memory.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Used to read the S/G entries in the second step. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Number of scatter gather list entries. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** How many entries would fit into the sg list. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** How many times the list was too big. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Pointer to the first entry of the scatter gather list. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** How many entries would fit into the sg info list. */
574bc38df445ce8595342c92f4341545b5277048vboxsync /** Number of entries for the information entries. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** How many times the list was too big. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Pointer to the first mapping information entry. */
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /** Size of the temporary buffer for unaligned guest segments. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the temporary buffer. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Pointer to the sense buffer. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /** Flag whether the request was issued from the BIOS. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMIBASE_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, IBase)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMISCSIPORT_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ISCSIPort)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ILed)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define LSILOGIC_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMIBASE_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, IBase)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#define PDMILEDPORTS_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, ILeds)) )
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync/** Key sequence the guest has to write to enable access
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * to diagnostic memory. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic const uint8_t g_lsilogicDiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0d};
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Updates the status of the interrupt pin of the device.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns nothing.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pThis Pointer to the device instance data.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic void lsilogicUpdateInterrupt(PLSILOGICSCSI pThis)
uIntSts = (ASMAtomicReadU32(&pThis->uInterruptStatus) & ~LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS);
if (uIntSts)
Log(("%s: Setting I/O controller into FAULT state: uIOCFaultCode=%u\n", __FUNCTION__, uIOCFaultCode));
#ifdef IN_RING3
return VINF_SUCCESS;
while (pSASDeviceCurr)
int rc;
if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite], u32MessageContext);
return VINF_SUCCESS;
static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion pReply, bool fForceReplyFifo)
#ifdef IN_RING3
int rc;
if (RT_UNLIKELY(pLsiLogic->uReplyFreeQueueNextAddressRead != pLsiLogic->uReplyFreeQueueNextEntryFreeWrite))
uint32_t u32ReplyFrameAddressLow = pLsiLogic->CTX_SUFF(pReplyFreeQueueBase)[pLsiLogic->uReplyFreeQueueNextAddressRead];
RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pLsiLogic->u32HostMFAHighAddr, u32ReplyFrameAddressLow);
size_t cbReplyCopied = (pLsiLogic->cbReplyFrame < sizeof(MptReplyUnion)) ? pLsiLogic->cbReplyFrame : sizeof(MptReplyUnion);
if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite],
if (fForceReplyFifo)
#ifdef IN_RING3
static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pMessageHdr, PMptReplyUnion pReply)
bool fForceReplyPostFifo = false;
#ifdef DEBUG
fForceReplyPostFifo = true;
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. */
pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
return rc;
static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void const *pv, unsigned cb)
switch (uOffset)
case LSILOGIC_REG_REPLY_QUEUE:
ASMAtomicWriteU32(&pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextEntryFreeWrite], u32);
uNextWrite++;
case LSILOGIC_REG_DOORBELL:
switch (uFunction)
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
#ifndef IN_RING3
return VINF_IOM_R3_MMIO_WRITE;
#ifdef IN_RING3
int rc = lsilogicProcessMessageRequest(pThis, (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer);
#ifndef IN_RING3
return VINF_IOM_R3_IOPORT_WRITE;
return VINF_SUCCESS;
case LSILOGIC_REG_REPLY_QUEUE:
* Non 4-byte access may cause real strange behavior because the data is part of a physical guest address.
case LSILOGIC_REG_DOORBELL:
u32 = 0;
case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */
switch (cb)
return rc;
return rc;
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
static void lsilogicScatterGatherListCopyFromBuffer(PLSILOGICTASKSTATE pTaskState, void *pvBuf, size_t cbCopy)
unsigned cSGEntry = 0;
if (!cbCopy)
pSGEntry++;
cSGEntry++;
static int lsilogicScatterGatherListAllocate(PLSILOGICTASKSTATE pTaskState, uint32_t cSGList, uint32_t cSGInfo, uint32_t cbUnaligned)
return VERR_NO_MEMORY;
pTaskState->paSGEntries = (PLSILOGICTASKSTATESGENTRY)RTMemAllocZ(cSGInfo * sizeof(LSILOGICTASKSTATESGENTRY));
return VERR_NO_MEMORY;
return VERR_NO_MEMORY;
#ifdef DEBUG
return VINF_SUCCESS;
static void lsilogicScatterGatherListDestroy(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
pSGInfoCurr++;
#ifdef DEBUG
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));
case MPTSGENTRYTYPE_CHAIN:
bool fDoMapping = false;
bool fEndOfList;
fUnaligned = false;
cbUnaligned = 0;
fEndOfList = false;
if (fDoMapping)
while (!fEndOfList)
bool fEndOfSegment = false;
while (!fEndOfSegment)
#ifdef DEBUG
return VINF_SUCCESS;
if (fDoMapping)
if (fBufferContainsData)
pSGInfoCurr++;
cSGInfo++;
fEndOfSegment = true;
fEndOfList = true;
fEndOfSegment = true;
if (uChainOffsetNext)
PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + uChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
fDoMapping = true;
if (fUnaligned)
pSGInfoCurr++;
pSGEntryCurr++;
cSGEntries++;
pSGInfoCurr++;
return rc;
* @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary.
#ifdef RT_STRICT
rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrSenseBufferBase, (void **)&pTaskState->pbSenseBuffer, &pTaskState->PageLockSense);
return rc;
#ifdef DEBUG
Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevLsiLogic_DISKFULL",
N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevLsiLogic_FILETOOBIG",
N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
int rc;
rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevLsiLogic_ISCSIDOWN",
N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
int rc2;
LogRel(("LsiLogic#%d: Unknown but recoverable error has occurred (rc=%Rrc)\n", pDevIns->iInstance, rc));
rc2 = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevLsiLogic_UNKNOWN",
N_("An unknown but recoverable I/O error has occurred (rc=%Rrc). VM execution is suspended. You can resume when the error is fixed"), rc);
#ifdef DEBUG
if (uChainOffset)
uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pTaskState->GuestRequest.SCSIIO.u32Control);
rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest);
return VINF_SUCCESS;
static int g_cLogged = 0;
pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext;
return rc;
static DECLCALLBACK(int) lsilogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
if (fRedo)
RT_UNLIKELY(pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength < pTaskState->PDMScsiRequest.cbSenseBuffer)
pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext;
return VINF_SUCCESS;
static DECLCALLBACK(int) lsilogicQueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController,
return VINF_SUCCESS;
switch(u8PageNumber)
return rc;
switch(u8PageNumber)
return rc;
switch(u8PageNumber)
return rc;
switch(u8PageNumber)
return rc;
return VERR_NOT_FOUND;
switch(u8PageNumber)
return rc;
return VERR_NOT_FOUND;
return VERR_NOT_FOUND;
switch(u8PageNumber)
*ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
*ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
*ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
*ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
*ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
*ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
*ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
*ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
return rc;
switch(u8PageNumber)
return rc;
return VERR_NOT_FOUND;
return VERR_NOT_FOUND;
if (pPHYPages)
switch(u8PageNumber)
return rc;
if (uAddressForm == 0)
while ( pSASDevice
if (pSASDevice)
while ( pSASDevice
while ( pSASDevice
if (pSASDevice)
switch(u8PageNumber)
return rc;
static int lsilogicConfigurationPageGetExtended(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
return rc;
static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
switch (u8PageType)
return VINF_SUCCESS;
case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT: /* Nothing to do. We are always using the defaults. */
if (cbBuffer != 0)
GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
if (cbBuffer != 0)
GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
return VINF_SUCCESS;
AssertMsg(pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n"));
pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
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++)
for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
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;
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;
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;
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;
return u16Handle;
AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS, ("Controller is not the SAS SCSI one\n"));
PMptConfigurationPageManufacturing7 pManufacturingPage7 = (PMptConfigurationPageManufacturing7)RTMemAllocZ(pPages->cbManufacturingPage7);
PMptConfigurationPageSASIOUnit0 pSASPage0 = (PMptConfigurationPageSASIOUnit0)RTMemAllocZ(pPages->cbSASIOUnitPage0);
PMptConfigurationPageSASIOUnit1 pSASPage1 = (PMptConfigurationPageSASIOUnit1)RTMemAllocZ(pPages->cbSASIOUnitPage1);
pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit2) / 4;
pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit3) / 4;
pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY0) / 4;
pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY1) / 4;
pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice0) / 4;
pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice1) / 4;
pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice2) / 4;
PMptConfigurationPagesSupported pPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported));
uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pLsiLogic->uRequestQueueNextEntryFreeWrite);
uint32_t u32RequestMessageFrameDesc = pLsiLogic->CTX_SUFF(pRequestQueueBase)[pLsiLogic->uRequestQueueNextAddressRead];
PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, sizeof(MptMessageHdr));
if (cbRequest != 0)
return rc;
int rc;
return rc;
int rc;
rc = pTaskState->pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->pTargetDevice->pDrvSCSIConnector,
return VINF_SUCCESS;
ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
return rc;
int rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) lsilogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
int rc;
return rc;
static DECLCALLBACK(int) lsilogicIsaIOPortReadStr(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;
return rc;
return rc;
return rc;
bool fVerbose = false;
if (pszArgs)
pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextEntryFreeWrite=%u\n", pThis->uReplyFreeQueueNextEntryFreeWrite);
pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextAddressRead=%u\n", pThis->uReplyFreeQueueNextAddressRead);
pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextEntryFreeWrite=%u\n", pThis->uReplyPostQueueNextEntryFreeWrite);
pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextAddressRead=%u\n", pThis->uReplyPostQueueNextAddressRead);
pHlp->pfnPrintf(pHlp, "uRequestQueueNextEntryFreeWrite=%u\n", pThis->uRequestQueueNextEntryFreeWrite);
if (fVerbose)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
return VINF_SSM_DONT_CALL_AGAIN;
SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
while (pCurr)
return VINF_SUCCESS;
static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
int rc;
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
bool fPresent;
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
return VINF_SUCCESS;
return rc;
sizeof(MptConfigurationPagesSupported_SSM_V2));
pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
return VERR_SSM_LOAD_CONFIG_MISMATCH;
return VERR_SSM_LOAD_CONFIG_MISMATCH;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) lsilogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
if (iLUN == 0)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
return NULL;
static DECLCALLBACK(int) lsilogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
return NULL;
while (pTaskState)
int rc;
return VERR_PDM_LUN_NOT_FOUND;
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
return rc;
int rc;
return rc;
bool fBootable = true;
#ifdef VBOX_WITH_MSI_DEVICES
return rc;
#ifdef VBOX_WITH_MSI_DEVICES
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicMap);
return rc;
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
return rc;
rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
return rc;
lsilogicNotifyQueueConsumer, true,
return rc;
return rc;
pThis->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
return rc;
if (fBootable)
return rc;
sizeof(LSILOGICSCSI),
NULL,
NULL,
NULL,
NULL,
NULL,
sizeof(LSILOGICSCSI),
NULL,
NULL,
NULL,
NULL,
NULL,