VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp

Last change on this file was 104193, checked in by vboxsync, 2 months ago

DevLsiLogic: Converted diagnostic MMIO range to DWORD access, consistently return 'unused' as appropriate.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 242.0 KB
RevLine 
[21321]1/* $Id: DevLsiLogicSCSI.cpp 104193 2024-04-05 13:42:44Z vboxsync $ */
2/** @file
[44694]3 * DevLsiLogicSCSI - LsiLogic LSI53c1030 SCSI controller.
[21321]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[21321]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[21321]26 */
[24071]27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[21321]32#define LOG_GROUP LOG_GROUP_DEV_LSILOGICSCSI
[35346]33#include <VBox/vmm/pdmdev.h>
[59252]34#include <VBox/vmm/pdmstorageifs.h>
[35346]35#include <VBox/vmm/pdmqueue.h>
[46265]36#include <VBox/vmm/pdmthread.h>
[35346]37#include <VBox/vmm/pdmcritsect.h>
[81773]38#include <VBox/AssertGuest.h>
[21321]39#include <VBox/scsi.h>
[46265]40#include <VBox/sup.h>
[21321]41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/string.h>
[45970]44#include <iprt/list.h>
[21321]45#ifdef IN_RING3
[27302]46# include <iprt/memcache.h>
[25966]47# include <iprt/mem.h>
[21321]48# include <iprt/param.h>
[25966]49# include <iprt/uuid.h>
[30947]50# include <iprt/time.h>
[21321]51#endif
52
[25509]53#include "DevLsiLogicSCSI.h"
[21321]54#include "VBoxSCSI.h"
55
[35353]56#include "VBoxDD.h"
[21321]57
[44694]58
[57358]59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
[25587]62/** The current saved state version. */
[89193]63#define LSILOGIC_SAVED_STATE_VERSION 6
64/** The saved state version used by VirtualBox before removal of the
65 * VBoxSCSI BIOS interface. */
66#define LSILOGIC_SAVED_STATE_VERSION_PRE_VBOXSCSI_REMOVAL 5
[45970]67/** The saved state version used by VirtualBox before the diagnostic
68 * memory access was implemented. */
[89193]69#define LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM 4
[45789]70/** The saved state version used by VirtualBox before the doorbell status flag
71 * was changed from bool to a 32bit enum. */
[89193]72#define LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL 3
[25587]73/** The saved state version used by VirtualBox before SAS support was added. */
[89193]74#define LSILOGIC_SAVED_STATE_VERSION_PRE_SAS 2
[25587]75/** The saved state version used by VirtualBox 3.0 and earlier. It does not
76 * include the device config part. */
[89193]77#define LSILOGIC_SAVED_STATE_VERSION_VBOX_30 1
[25587]78
[30947]79/** Maximum number of entries in the release log. */
[81777]80#define MAX_REL_LOG_ERRORS 1024
[30947]81
[81777]82#define LSILOGIC_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
[44694]83
[45959]84/** Upper number a buffer is freed if it was too big before. */
[81777]85#define LSILOGIC_MAX_ALLOC_TOO_MUCH 20
[44694]86
[46253]87/** Maximum size of the memory regions (prevents teh guest from DOSing the host by
88 * allocating loadds of memory). */
[81777]89#define LSILOGIC_MEMORY_REGIONS_MAX _1M
[46253]90
[45789]91
[57358]92/*********************************************************************************************************************************
93* Structures and Typedefs *
94*********************************************************************************************************************************/
95
[81781]96/** Pointer to the shared instance data for the LsiLogic emulation. */
[64224]97typedef struct LSILOGICSCSI *PLSILOGICSCSI;
98
99#ifdef IN_RING3
[21321]100/**
[64224]101 * Memory buffer callback.
[45959]102 *
[81781]103 * @param pDevIns The device instance.
104 * @param GCPhys The guest physical address of the memory buffer.
105 * @param pSgBuf The pointer to the host R3 S/G buffer.
106 * @param cbCopy How many bytes to copy between the two buffers.
107 * @param pcbSkip Initially contains the amount of bytes to skip
108 * starting from the guest physical address before
109 * accessing the S/G buffer and start copying data.
110 * On return this contains the remaining amount if
111 * cbCopy < *pcbSkip or 0 otherwise.
[45959]112 */
[85121]113typedef DECLCALLBACKTYPE(void, FNLSILOGICR3MEMCOPYCALLBACK,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
114 PRTSGBUF pSgBuf, size_t cbCopy, size_t *pcbSkip));
[64224]115/** Pointer to a memory copy buffer callback. */
[85121]116typedef FNLSILOGICR3MEMCOPYCALLBACK *PFNLSILOGICR3MEMCOPYCALLBACK;
[64224]117#endif
[45959]118
119/**
[21321]120 * Reply data.
121 */
122typedef struct LSILOGICSCSIREPLY
123{
124 /** Lower 32 bits of the reply address in memory. */
[81777]125 uint32_t u32HostMFALowAddress;
[21321]126 /** Full address of the reply in guest memory. */
[81777]127 RTGCPHYS GCPhysReplyAddress;
[21321]128 /** Size of the reply. */
[81777]129 uint32_t cbReply;
[21321]130 /** Different views to the reply depending on the request type. */
[81777]131 MptReplyUnion Reply;
[44694]132} LSILOGICSCSIREPLY;
133/** Pointer to reply data. */
134typedef LSILOGICSCSIREPLY *PLSILOGICSCSIREPLY;
[21321]135
[25966]136/**
[45970]137 * Memory region of the IOC.
138 */
139typedef struct LSILOGICMEMREGN
140{
141 /** List node. */
[81777]142 RTLISTNODE NodeList;
[45970]143 /** 32bit address the region starts to describe. */
[81777]144 uint32_t u32AddrStart;
[45970]145 /** 32bit address the region ends (inclusive). */
[81777]146 uint32_t u32AddrEnd;
[45970]147 /** Data for this region - variable. */
[81777]148 uint32_t au32Data[1];
[45970]149} LSILOGICMEMREGN;
150/** Pointer to a memory region. */
151typedef LSILOGICMEMREGN *PLSILOGICMEMREGN;
152
153/**
[21321]154 * State of a device attached to the buslogic host adapter.
[25966]155 *
156 * @implements PDMIBASE
157 * @implements PDMISCSIPORT
158 * @implements PDMILEDPORTS
[21321]159 */
160typedef struct LSILOGICDEVICE
161{
[81781]162 /** Pointer to the owning lsilogic device instance - R3 pointer */
163 PPDMDEVINSR3 pDevIns;
[21321]164
165 /** LUN of the device. */
[81777]166 uint32_t iLUN;
[21321]167 /** Number of outstanding tasks on the port. */
[81777]168 volatile uint32_t cOutstandingRequests;
[21321]169
[33540]170 /** Our base interface. */
[81777]171 PDMIBASE IBase;
[64224]172 /** Media port interface. */
[81777]173 PDMIMEDIAPORT IMediaPort;
[64224]174 /** Extended media port interface. */
[81777]175 PDMIMEDIAEXPORT IMediaExPort;
[21321]176 /** Led interface. */
[81777]177 PDMILEDPORTS ILed;
[21321]178 /** Pointer to the attached driver's base interface. */
[81777]179 R3PTRTYPE(PPDMIBASE) pDrvBase;
[64224]180 /** Pointer to the attached driver's media interface. */
[81777]181 R3PTRTYPE(PPDMIMEDIA) pDrvMedia;
[64224]182 /** Pointer to the attached driver's extended media interface. */
[81777]183 R3PTRTYPE(PPDMIMEDIAEX) pDrvMediaEx;
[21321]184 /** The status LED state for this device. */
[81777]185 PDMLED Led;
[81781]186 /** Device name. */
187 char szName[16];
[44694]188} LSILOGICDEVICE;
189/** Pointer to a device state. */
190typedef LSILOGICDEVICE *PLSILOGICDEVICE;
[21321]191
[32983]192/** Pointer to a task state. */
[45959]193typedef struct LSILOGICREQ *PLSILOGICREQ;
[32983]194
[81777]195
[21321]196/**
[81777]197 * Shared instance data for the LsiLogic emulation.
[21321]198 */
199typedef struct LSILOGICSCSI
200{
201 /** The state the controller is currently in. */
[81777]202 LSILOGICSTATE enmState;
[21321]203 /** Who needs to init the driver to get into operational state. */
[81777]204 LSILOGICWHOINIT enmWhoInit;
[21321]205 /** Flag whether we are in doorbell function. */
[81777]206 LSILOGICDOORBELLSTATE enmDoorbellState;
[21321]207 /** Flag whether diagnostic access is enabled. */
[81777]208 bool fDiagnosticEnabled;
[21321]209 /** Flag whether a notification was send to R3. */
[81777]210 bool fNotificationSent;
[21321]211 /** Flag whether the guest enabled event notification from the IOC. */
[81777]212 bool fEventNotificationEnabled;
[45970]213 /** Flag whether the diagnostic address and RW registers are enabled. */
[81777]214 bool fDiagRegsEnabled;
[21321]215
[25675]216 /** Number of device states allocated. */
[81777]217 uint32_t cDeviceStates;
[81781]218 uint32_t u32Padding1;
[25677]219
[21321]220 /** Interrupt mask. */
[81777]221 volatile uint32_t uInterruptMask;
[21321]222 /** Interrupt status register. */
[81777]223 volatile uint32_t uInterruptStatus;
[21321]224
[45795]225 /** Buffer for messages which are passed through the doorbell using the
[21321]226 * handshake method. */
[81777]227 uint32_t aMessage[sizeof(MptConfigurationRequest)]; /** @todo r=bird: Looks like 4 times the required size? Please explain in comment if this correct... */
[21321]228 /** Actual position in the buffer. */
[81777]229 uint32_t iMessage;
[21321]230 /** Size of the message which is given in the doorbell message in dwords. */
[81777]231 uint32_t cMessage;
[21321]232
[45795]233 /** Reply buffer.
234 * @note 60 bytes */
[81777]235 MptReplyUnion ReplyBuffer;
[21321]236 /** Next entry to read. */
[81777]237 uint32_t uNextReplyEntryRead;
[21321]238 /** Size of the reply in the buffer in 16bit words. */
[81777]239 uint32_t cReplySize;
[21321]240
241 /** The fault code of the I/O controller if we are in the fault state. */
[81777]242 uint16_t u16IOCFaultCode;
[81781]243 uint16_t u16Padding2;
[21321]244
[25675]245 /** Upper 32 bits of the message frame address to locate requests in guest memory. */
[81777]246 uint32_t u32HostMFAHighAddr;
[21321]247 /** Upper 32 bits of the sense buffer address. */
[81777]248 uint32_t u32SenseBufferHighAddr;
[21321]249 /** Maximum number of devices the driver reported he can handle. */
[81777]250 uint8_t cMaxDevices;
251 /** Maximum number of buses the driver reported he can handle. */
252 uint8_t cMaxBuses;
[21321]253 /** Current size of reply message frames in the guest. */
[81777]254 uint16_t cbReplyFrame;
[21321]255
256 /** Next key to write in the sequence to get access
257 * to diagnostic memory. */
[81777]258 uint32_t iDiagnosticAccess;
[21321]259
[81751]260 /** Number entries configured for the reply queue. */
[81777]261 uint32_t cReplyQueueEntries;
[81751]262 /** Number entries configured for the outstanding request queue. */
[81777]263 uint32_t cRequestQueueEntries;
[21321]264
265 /** Critical section protecting the reply post queue. */
[81777]266 PDMCRITSECT ReplyPostQueueCritSect;
[21321]267 /** Critical section protecting the reply free queue. */
[81777]268 PDMCRITSECT ReplyFreeQueueCritSect;
[64808]269 /** Critical section protecting the request queue against
270 * concurrent access from the guest. */
[81777]271 PDMCRITSECT RequestQueueCritSect;
[64808]272 /** Critical section protecting the reply free queue against
273 * concurrent write access from the guest. */
[81777]274 PDMCRITSECT ReplyFreeQueueWriteCritSect;
[21321]275
[81751]276 /** The reply free qeueue (only the first cReplyQueueEntries are used). */
[81777]277 uint32_t volatile aReplyFreeQueue[LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX];
[81751]278 /** The reply post qeueue (only the first cReplyQueueEntries are used). */
[81777]279 uint32_t volatile aReplyPostQueue[LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX];
[81751]280 /** The request qeueue (only the first cRequestQueueEntries are used). */
[81777]281 uint32_t volatile aRequestQueue[LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MAX];
[21321]282
283 /** Next free entry in the reply queue the guest can write a address to. */
[81777]284 volatile uint32_t uReplyFreeQueueNextEntryFreeWrite;
[21321]285 /** Next valid entry the controller can read a valid address for reply frames from. */
[81777]286 volatile uint32_t uReplyFreeQueueNextAddressRead;
[21321]287
288 /** Next free entry in the reply queue the guest can write a address to. */
[81777]289 volatile uint32_t uReplyPostQueueNextEntryFreeWrite;
[21321]290 /** Next valid entry the controller can read a valid address for reply frames from. */
[81777]291 volatile uint32_t uReplyPostQueueNextAddressRead;
[21321]292
293 /** Next free entry the guest can write a address to a request frame to. */
[81777]294 volatile uint32_t uRequestQueueNextEntryFreeWrite;
[21321]295 /** Next valid entry the controller can read a valid address for request frames from. */
[81777]296 volatile uint32_t uRequestQueueNextAddressRead;
[21321]297
[81781]298 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
299 * a port is entering the idle state. */
300 bool volatile fSignalIdle;
301 /** Flag whether the worker thread is sleeping. */
302 volatile bool fWrkThreadSleeping;
[89193]303 bool afPadding3[2];
[81781]304
305 /** Current address to read from or write to in the diagnostic memory region. */
306 uint32_t u32DiagMemAddr;
307
[25587]308 /** Emulated controller type */
[81777]309 LSILOGICCTRLTYPE enmCtrlType;
[25587]310 /** Handle counter */
[81777]311 uint16_t u16NextHandle;
[25509]312
[25675]313 /** Number of ports this controller has. */
[81777]314 uint8_t cPorts;
[81781]315 uint8_t afPadding4;
[25675]316
[81781]317 /** The event semaphore the processing thread waits on. */
318 SUPSEMEVENT hEvtProcess;
[45795]319
[81781]320 /** PCI Region \#0: I/O ports register access. */
321 IOMIOPORTHANDLE hIoPortsReg;
322 /** PCI Region \#1: MMIO register access. */
323 IOMMMIOHANDLE hMmioReg;
324 /** PCI Region \#2: MMIO diag. */
325 IOMMMIOHANDLE hMmioDiag;
326 /** ISA Ports for the BIOS (when booting is configured). */
327 IOMIOPORTHANDLE hIoPortsBios;
328} LSILOGICSCSI;
329AssertCompileMemberAlignment(LSILOGICSCSI, ReplyPostQueueCritSect, 8);
330
331/**
332 * Ring-3 instance data for the LsiLogic emulation.
333 */
334typedef struct LSILOGICSCSIR3
335{
336 /** States for attached devices. */
337 R3PTRTYPE(PLSILOGICDEVICE) paDeviceStates;
[25966]338 /** Status LUN: The base interface. */
[81777]339 PDMIBASE IBase;
[25966]340 /** Status LUN: Leds interface. */
[81777]341 PDMILEDPORTS ILeds;
[25966]342 /** Status LUN: Partner of ILeds. */
[81777]343 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
[64409]344 /** Status LUN: Media Notifys. */
[81777]345 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify;
[29609]346 /** Pointer to the configuration page area. */
347 R3PTRTYPE(PMptConfigurationPagesSupported) pConfigurationPages;
[29610]348
[46253]349 /** Current size of the memory regions. */
[81777]350 uint32_t cbMemRegns;
351 uint32_t u32Padding3;
[45970]352
[88530]353 /** Critical section protecting the memory regions. */
354 RTCRITSECT CritSectMemRegns;
[81781]355 /** List of memory regions - PLSILOGICMEMREGN. */
356 RTLISTANCHORR3 ListMemRegns;
[46265]357
358 /** Worker thread. */
[81777]359 R3PTRTYPE(PPDMTHREAD) pThreadWrk;
[46265]360
[81781]361 /** The device instace - only for getting bearings in interface methods. */
362 PPDMDEVINSR3 pDevIns;
363} LSILOGICSCSIR3;
364/** Pointer to the ring-3 instance data for the LsiLogic emulation. */
365typedef LSILOGICSCSIR3 *PLSILOGICSCSIR3;
[21321]366
[81777]367
[21321]368/**
[81781]369 * Ring-0 instance data for the LsiLogic emulation.
370 */
371typedef struct LSILOGICSCSIR0
372{
373 uint64_t u64Unused;
374} LSILOGICSCSIR0;
375/** Pointer to the ring-0 instance data for the LsiLogic emulation. */
376typedef LSILOGICSCSIR0 *PLSILOGICSCSIR0;
377
378
379/**
380 * Raw-mode instance data for the LsiLogic emulation.
381 */
382typedef struct LSILOGICSCSIRC
383{
384 uint64_t u64Unused;
385} LSILOGICSCSIRC;
386/** Pointer to the raw-mode instance data for the LsiLogic emulation. */
387typedef LSILOGICSCSIRC *PLSILOGICSCSIRC;
388
389
390/** The current context instance data for the LsiLogic emulation. */
391typedef CTX_SUFF(LSILOGICSCSI) LSILOGICSCSICC;
392/** Pointer to the current context instance data for the LsiLogic emulation. */
393typedef CTX_SUFF(PLSILOGICSCSI) PLSILOGICSCSICC;
394
395
396/**
[33540]397 * Task state object which holds all necessary data while
[21321]398 * processing the request from the guest.
399 */
[45959]400typedef struct LSILOGICREQ
[21321]401{
[64224]402 /** I/O request handle. */
[81777]403 PDMMEDIAEXIOREQ hIoReq;
[32983]404 /** Next in the redo list. */
[81777]405 PLSILOGICREQ pRedoNext;
[21321]406 /** Target device. */
[81777]407 PLSILOGICDEVICE pTargetDevice;
[21321]408 /** The message request from the guest. */
[81777]409 MptRequestUnion GuestRequest;
[21321]410 /** Address of the message request frame in guests memory.
411 * Used to read the S/G entries in the second step. */
[81777]412 RTGCPHYS GCPhysMessageFrameAddr;
[45959]413 /** Physical start address of the S/G list. */
[81777]414 RTGCPHYS GCPhysSgStart;
[45959]415 /** Chain offset */
[81777]416 uint32_t cChainOffset;
[21321]417 /** Pointer to the sense buffer. */
[81777]418 uint8_t abSenseBuffer[18];
[64224]419 /** SCSI status code. */
[81777]420 uint8_t u8ScsiSts;
[45959]421} LSILOGICREQ;
[21321]422
[44694]423
[21321]424#ifndef VBOX_DEVICE_STRUCT_TESTCASE
425
[57358]426
427/*********************************************************************************************************************************
428* Internal Functions *
429*********************************************************************************************************************************/
[21321]430RT_C_DECLS_BEGIN
431#ifdef IN_RING3
[81781]432static void lsilogicR3InitializeConfigurationPages(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC);
433static void lsilogicR3ConfigurationPagesFree(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC);
434static int lsilogicR3ProcessConfigurationRequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
435 PMptConfigurationRequest pConfigurationReq, PMptConfigurationReply pReply);
[21321]436#endif
437RT_C_DECLS_END
438
439
[57358]440/*********************************************************************************************************************************
441* Global Variables *
442*********************************************************************************************************************************/
[21321]443/** Key sequence the guest has to write to enable access
444 * to diagnostic memory. */
445static const uint8_t g_lsilogicDiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0d};
446
447/**
448 * Updates the status of the interrupt pin of the device.
449 *
[81781]450 * @param pDevIns The device instance.
451 * @param pThis Pointer to the shared LsiLogic device state.
[21321]452 */
[81781]453static void lsilogicUpdateInterrupt(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis)
[21321]454{
455 uint32_t uIntSts;
456
457 LogFlowFunc(("Updating interrupts\n"));
458
459 /* Mask out doorbell status so that it does not affect interrupt updating. */
460 uIntSts = (ASMAtomicReadU32(&pThis->uInterruptStatus) & ~LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS);
461 /* Check maskable interrupts. */
[29827]462 uIntSts &= ~(ASMAtomicReadU32(&pThis->uInterruptMask) & ~LSILOGIC_REG_HOST_INTR_MASK_IRQ_ROUTING);
[21321]463
464 if (uIntSts)
465 {
466 LogFlowFunc(("Setting interrupt\n"));
[81781]467 PDMDevHlpPCISetIrq(pDevIns, 0, 1);
[21321]468 }
469 else
470 {
471 LogFlowFunc(("Clearing interrupt\n"));
[81781]472 PDMDevHlpPCISetIrq(pDevIns, 0, 0);
[21321]473 }
474}
475
476/**
477 * Sets a given interrupt status bit in the status register and
[33540]478 * updates the interrupt status.
[21321]479 *
[81781]480 * @param pDevIns The device instance.
481 * @param pThis Pointer to the shared LsiLogic device state.
[44694]482 * @param uStatus The status bit to set.
[21321]483 */
[81781]484DECLINLINE(void) lsilogicSetInterrupt(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, uint32_t uStatus)
[21321]485{
[44694]486 ASMAtomicOrU32(&pThis->uInterruptStatus, uStatus);
[81781]487 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]488}
489
490/**
491 * Clears a given interrupt status bit in the status register and
[33540]492 * updates the interrupt status.
[21321]493 *
[81781]494 * @param pDevIns The device instance.
495 * @param pThis Pointer to the shared LsiLogic device state.
[44694]496 * @param uStatus The status bit to set.
[21321]497 */
[81781]498DECLINLINE(void) lsilogicClearInterrupt(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, uint32_t uStatus)
[21321]499{
[44694]500 ASMAtomicAndU32(&pThis->uInterruptStatus, ~uStatus);
[81781]501 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]502}
503
[63480]504
505#ifdef IN_RING3
[21321]506/**
507 * Sets the I/O controller into fault state and sets the fault code.
508 *
[81781]509 * @param pThis Pointer to the shared LsiLogic device state.
[44694]510 * @param uIOCFaultCode Fault code to set.
[21321]511 */
[44694]512DECLINLINE(void) lsilogicSetIOCFaultCode(PLSILOGICSCSI pThis, uint16_t uIOCFaultCode)
[21321]513{
[44694]514 if (pThis->enmState != LSILOGICSTATE_FAULT)
[21321]515 {
[56992]516 LogFunc(("Setting I/O controller into FAULT state: uIOCFaultCode=%u\n", uIOCFaultCode));
[44694]517 pThis->enmState = LSILOGICSTATE_FAULT;
518 pThis->u16IOCFaultCode = uIOCFaultCode;
[21321]519 }
520 else
[56992]521 LogFunc(("We are already in FAULT state\n"));
[21321]522}
[63480]523#endif /* IN_RING3 */
[21321]524
[63480]525
[45970]526/**
527 * Returns the number of frames in the reply free queue.
528 *
529 * @returns Number of frames in the reply free queue.
[81781]530 * @param pThis Pointer to the shared LsiLogic device state.
[45970]531 */
532DECLINLINE(uint32_t) lsilogicReplyFreeQueueGetFrameCount(PLSILOGICSCSI pThis)
533{
534 uint32_t cReplyFrames = 0;
535
536 if (pThis->uReplyFreeQueueNextAddressRead <= pThis->uReplyFreeQueueNextEntryFreeWrite)
537 cReplyFrames = pThis->uReplyFreeQueueNextEntryFreeWrite - pThis->uReplyFreeQueueNextAddressRead;
538 else
539 cReplyFrames = pThis->cReplyQueueEntries - pThis->uReplyFreeQueueNextAddressRead + pThis->uReplyFreeQueueNextEntryFreeWrite;
540
541 return cReplyFrames;
542}
543
[63480]544#ifdef IN_RING3
545
[45970]546/**
547 * Returns the number of free entries in the reply post queue.
548 *
549 * @returns Number of frames in the reply free queue.
[81781]550 * @param pThis Pointer to the shared LsiLogic device state.
[45970]551 */
552DECLINLINE(uint32_t) lsilogicReplyPostQueueGetFrameCount(PLSILOGICSCSI pThis)
553{
554 uint32_t cReplyFrames = 0;
555
556 if (pThis->uReplyPostQueueNextAddressRead <= pThis->uReplyPostQueueNextEntryFreeWrite)
557 cReplyFrames = pThis->cReplyQueueEntries - pThis->uReplyPostQueueNextEntryFreeWrite + pThis->uReplyPostQueueNextAddressRead;
558 else
559 cReplyFrames = pThis->uReplyPostQueueNextEntryFreeWrite - pThis->uReplyPostQueueNextAddressRead;
560
561 return cReplyFrames;
562}
563
[44694]564
[21321]565/**
566 * Performs a hard reset on the controller.
567 *
568 * @returns VBox status code.
[81781]569 * @param pDevIns The device instance.
570 * @param pThis Pointer to the shared LsiLogic device state.
571 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[21321]572 */
[81781]573static int lsilogicR3HardReset(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
[21321]574{
575 pThis->enmState = LSILOGICSTATE_RESET;
[45789]576 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
[21321]577
578 /* The interrupts are masked out. */
[44695]579 pThis->uInterruptMask |= LSILOGIC_REG_HOST_INTR_MASK_DOORBELL
580 | LSILOGIC_REG_HOST_INTR_MASK_REPLY;
[21321]581 /* Reset interrupt states. */
582 pThis->uInterruptStatus = 0;
[81781]583 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]584
585 /* Reset the queues. */
586 pThis->uReplyFreeQueueNextEntryFreeWrite = 0;
[25587]587 pThis->uReplyFreeQueueNextAddressRead = 0;
[21321]588 pThis->uReplyPostQueueNextEntryFreeWrite = 0;
[25587]589 pThis->uReplyPostQueueNextAddressRead = 0;
590 pThis->uRequestQueueNextEntryFreeWrite = 0;
591 pThis->uRequestQueueNextAddressRead = 0;
[21321]592
593 /* Disable diagnostic access. */
[45970]594 pThis->iDiagnosticAccess = 0;
595 pThis->fDiagnosticEnabled = false;
596 pThis->fDiagRegsEnabled = false;
[21321]597
598 /* Set default values. */
[45970]599 pThis->cMaxDevices = pThis->cDeviceStates;
600 pThis->cMaxBuses = 1;
[63562]601 pThis->cbReplyFrame = 128; /** @todo Figure out where it is needed. */
[45970]602 pThis->u16NextHandle = 1;
603 pThis->u32DiagMemAddr = 0;
[21321]604
[81781]605 lsilogicR3InitializeConfigurationPages(pDevIns, pThis, pThisCC);
[21321]606
607 /* Mark that we finished performing the reset. */
608 pThis->enmState = LSILOGICSTATE_READY;
609 return VINF_SUCCESS;
610}
611
612/**
[88530]613 * Allocates the configuration pages based on the device.
614 *
[99739]615 * @returns VBox status code.
[88530]616 * @param pThis Pointer to the shared LsiLogic device state.
617 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
618 */
619static int lsilogicR3ConfigurationPagesAlloc(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
620{
621 pThisCC->pConfigurationPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported));
622 if (!pThisCC->pConfigurationPages)
623 return VERR_NO_MEMORY;
624
625 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
626 {
627 PMptConfigurationPagesSas pPages = &pThisCC->pConfigurationPages->u.SasPages;
628
629 pPages->cbManufacturingPage7 = LSILOGICSCSI_MANUFACTURING7_GET_SIZE(pThis->cPorts);
630 PMptConfigurationPageManufacturing7 pManufacturingPage7 = (PMptConfigurationPageManufacturing7)RTMemAllocZ(pPages->cbManufacturingPage7);
631 AssertPtrReturn(pManufacturingPage7, VERR_NO_MEMORY);
632 pPages->pManufacturingPage7 = pManufacturingPage7;
633
634 /* SAS I/O unit page 0 - Port specific information. */
635 pPages->cbSASIOUnitPage0 = LSILOGICSCSI_SASIOUNIT0_GET_SIZE(pThis->cPorts);
636 PMptConfigurationPageSASIOUnit0 pSASPage0 = (PMptConfigurationPageSASIOUnit0)RTMemAllocZ(pPages->cbSASIOUnitPage0);
637 AssertPtrReturn(pSASPage0, VERR_NO_MEMORY);
638 pPages->pSASIOUnitPage0 = pSASPage0;
639
640 /* SAS I/O unit page 1 - Port specific settings. */
641 pPages->cbSASIOUnitPage1 = LSILOGICSCSI_SASIOUNIT1_GET_SIZE(pThis->cPorts);
642 PMptConfigurationPageSASIOUnit1 pSASPage1 = (PMptConfigurationPageSASIOUnit1)RTMemAllocZ(pPages->cbSASIOUnitPage1);
643 AssertPtrReturn(pSASPage1, VERR_NO_MEMORY);
644 pPages->pSASIOUnitPage1 = pSASPage1;
645
646 pPages->cPHYs = pThis->cPorts;
647 pPages->paPHYs = (PMptPHY)RTMemAllocZ(pPages->cPHYs * sizeof(MptPHY));
648 AssertPtrReturn(pPages->paPHYs, VERR_NO_MEMORY);
649
650 /* Initialize the PHY configuration */
651 for (unsigned i = 0; i < pThis->cPorts; i++)
652 {
653 /* Settings for present devices. */
654 if (pThisCC->paDeviceStates[i].pDrvBase)
655 {
656 PMptSASDevice pSASDevice = (PMptSASDevice)RTMemAllocZ(sizeof(MptSASDevice));
657 AssertPtrReturn(pSASDevice, VERR_NO_MEMORY);
658
659 /* Link into device list. */
660 if (!pPages->cDevices)
661 {
662 pPages->pSASDeviceHead = pSASDevice;
663 pPages->pSASDeviceTail = pSASDevice;
664 pPages->cDevices = 1;
665 }
666 else
667 {
668 pSASDevice->pPrev = pPages->pSASDeviceTail;
669 pPages->pSASDeviceTail->pNext = pSASDevice;
670 pPages->pSASDeviceTail = pSASDevice;
671 pPages->cDevices++;
672 }
673 }
674 }
675 }
676
677 return VINF_SUCCESS;
678}
679
680/**
[25588]681 * Frees the configuration pages if allocated.
682 *
[81781]683 * @param pThis Pointer to the shared LsiLogic device state.
684 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[25588]685 */
[81781]686static void lsilogicR3ConfigurationPagesFree(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
[25588]687{
688
[81781]689 if (pThisCC->pConfigurationPages)
[25588]690 {
691 /* Destroy device list if we emulate a SAS controller. */
692 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
693 {
[81781]694 PMptConfigurationPagesSas pSasPages = &pThisCC->pConfigurationPages->u.SasPages;
[25697]695 PMptSASDevice pSASDeviceCurr = pSasPages->pSASDeviceHead;
[25588]696
697 while (pSASDeviceCurr)
698 {
699 PMptSASDevice pFree = pSASDeviceCurr;
700
701 pSASDeviceCurr = pSASDeviceCurr->pNext;
702 RTMemFree(pFree);
703 }
[25697]704 if (pSasPages->paPHYs)
705 RTMemFree(pSasPages->paPHYs);
706 if (pSasPages->pManufacturingPage7)
707 RTMemFree(pSasPages->pManufacturingPage7);
708 if (pSasPages->pSASIOUnitPage0)
709 RTMemFree(pSasPages->pSASIOUnitPage0);
710 if (pSasPages->pSASIOUnitPage1)
711 RTMemFree(pSasPages->pSASIOUnitPage1);
[88530]712
713 pSasPages->pSASDeviceHead = NULL;
714 pSasPages->paPHYs = NULL;
715 pSasPages->pManufacturingPage7 = NULL;
716 pSasPages->pSASIOUnitPage0 = NULL;
717 pSasPages->pSASIOUnitPage1 = NULL;
[25588]718 }
719
[81781]720 RTMemFree(pThisCC->pConfigurationPages);
[88530]721 pThisCC->pConfigurationPages = NULL;
[25588]722 }
723}
724
725/**
[21321]726 * Finishes a context reply.
727 *
[81781]728 * @param pDevIns The device instance.
729 * @param pThis Pointer to the shared LsiLogic device state.
[44694]730 * @param u32MessageContext The message context ID to post.
[21321]731 */
[81781]732static void lsilogicR3FinishContextReply(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, uint32_t u32MessageContext)
[21321]733{
[44694]734 LogFlowFunc(("pThis=%#p u32MessageContext=%#x\n", pThis, u32MessageContext));
[29588]735
[45789]736 AssertMsg(pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_NOT_IN_USE, ("We are in a doorbell function\n"));
[21321]737
738 /* Write message context ID into reply post queue. */
[90445]739 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->ReplyPostQueueCritSect, VINF_SUCCESS);
740 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->ReplyPostQueueCritSect, rc);
[21321]741
742 /* Check for a entry in the queue. */
[45970]743 if (!lsilogicReplyPostQueueGetFrameCount(pThis))
[21321]744 {
745 /* Set error code. */
[44694]746 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
[81781]747 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyPostQueueCritSect);
[21321]748 return;
749 }
750
751 /* We have a context reply. */
[81751]752 ASMAtomicWriteU32(&pThis->aReplyPostQueue[pThis->uReplyPostQueueNextEntryFreeWrite], u32MessageContext);
[44694]753 ASMAtomicIncU32(&pThis->uReplyPostQueueNextEntryFreeWrite);
754 pThis->uReplyPostQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries;
[21321]755
[28570]756 /* Set interrupt. */
[81781]757 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
[29827]758
[81781]759 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyPostQueueCritSect);
[21321]760}
[28412]761
[21321]762
763/**
[33540]764 * Takes necessary steps to finish a reply frame.
[21321]765 *
[81781]766 * @param pDevIns The device instance.
767 * @param pThis Pointer to the shared LsiLogic device state.
[21321]768 * @param pReply Pointer to the reply message.
769 * @param fForceReplyFifo Flag whether the use of the reply post fifo is forced.
770 */
[81781]771static void lsilogicFinishAddressReply(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PMptReplyUnion pReply, bool fForceReplyFifo)
[21321]772{
773 /*
774 * If we are in a doorbell function we set the reply size now and
775 * set the system doorbell status interrupt to notify the guest that
776 * we are ready to send the reply.
777 */
[45789]778 if (pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_NOT_IN_USE && !fForceReplyFifo)
[21321]779 {
780 /* Set size of the reply in 16bit words. The size in the reply is in 32bit dwords. */
[44694]781 pThis->cReplySize = pReply->Header.u8MessageLength * 2;
782 Log(("%s: cReplySize=%u\n", __FUNCTION__, pThis->cReplySize));
783 pThis->uNextReplyEntryRead = 0;
[81781]784 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[21321]785 }
786 else
787 {
788 /*
789 * The reply queues are only used if the request was fetched from the request queue.
790 * Requests from the request queue are always transferred to R3. So it is not possible
791 * that this case happens in R0 or GC.
792 */
[63218]793# ifdef IN_RING3
[21321]794 /* Grab a free reply message from the queue. */
[90445]795 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->ReplyFreeQueueCritSect, VINF_SUCCESS);
796 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->ReplyFreeQueueCritSect, rc);
[21321]797
798 /* Check for a free reply frame. */
[45970]799 if (!lsilogicReplyFreeQueueGetFrameCount(pThis))
[21321]800 {
801 /* Set error code. */
[44694]802 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
[81781]803 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyFreeQueueCritSect);
[21321]804 return;
805 }
806
[81751]807 uint32_t u32ReplyFrameAddressLow = pThis->aReplyFreeQueue[pThis->uReplyFreeQueueNextAddressRead];
[21321]808
[44694]809 pThis->uReplyFreeQueueNextAddressRead++;
810 pThis->uReplyFreeQueueNextAddressRead %= pThis->cReplyQueueEntries;
[21321]811
[81781]812 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyFreeQueueCritSect);
[21321]813
814 /* Build 64bit physical address. */
[44694]815 RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr, u32ReplyFrameAddressLow);
816 size_t cbReplyCopied = (pThis->cbReplyFrame < sizeof(MptReplyUnion)) ? pThis->cbReplyFrame : sizeof(MptReplyUnion);
[21321]817
818 /* Write reply to guest memory. */
[84504]819 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysReplyMessage, pReply, cbReplyCopied);
[21321]820
821 /* Write low 32bits of reply frame into post reply queue. */
[81781]822 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->ReplyPostQueueCritSect, VINF_SUCCESS);
[90445]823 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->ReplyPostQueueCritSect, rc);
[21321]824
825 /* Check for a entry in the queue. */
[45970]826 if (!lsilogicReplyPostQueueGetFrameCount(pThis))
[21321]827 {
828 /* Set error code. */
[44694]829 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
[81781]830 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyPostQueueCritSect);
[21321]831 return;
832 }
833
834 /* We have a address reply. Set the 31th bit to indicate that. */
[81751]835 ASMAtomicWriteU32(&pThis->aReplyPostQueue[pThis->uReplyPostQueueNextEntryFreeWrite],
[21321]836 RT_BIT(31) | (u32ReplyFrameAddressLow >> 1));
[44694]837 ASMAtomicIncU32(&pThis->uReplyPostQueueNextEntryFreeWrite);
838 pThis->uReplyPostQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries;
[21321]839
840 if (fForceReplyFifo)
841 {
[45789]842 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
[81781]843 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[21321]844 }
845
846 /* Set interrupt. */
[81781]847 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
[29827]848
[81781]849 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyPostQueueCritSect);
[63218]850# else
[21321]851 AssertMsgFailed(("This is not allowed to happen.\n"));
[63218]852# endif
[21321]853 }
854}
855
[45970]856
[45789]857/**
[45970]858 * Tries to find a memory region which covers the given address.
[45789]859 *
[45970]860 * @returns Pointer to memory region or NULL if not found.
[81781]861 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]862 * @param u32Addr The 32bit address to search for.
[45789]863 */
[81781]864static PLSILOGICMEMREGN lsilogicR3MemRegionFindByAddr(PLSILOGICSCSICC pThisCC, uint32_t u32Addr)
[45789]865{
[45970]866 PLSILOGICMEMREGN pRegion = NULL;
[45789]867
[64766]868 PLSILOGICMEMREGN pIt;
[81781]869 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
[45970]870 {
871 if ( u32Addr >= pIt->u32AddrStart
872 && u32Addr <= pIt->u32AddrEnd)
873 {
874 pRegion = pIt;
875 break;
876 }
877 }
878
879 return pRegion;
880}
881
882/**
883 * Frees all allocated memory regions.
884 *
[81781]885 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]886 */
[81781]887static void lsilogicR3MemRegionsFree(PLSILOGICSCSICC pThisCC)
[45970]888{
889 PLSILOGICMEMREGN pItNext;
890
[64766]891 PLSILOGICMEMREGN pIt;
[81781]892 RTListForEachSafe(&pThisCC->ListMemRegns, pIt, pItNext, LSILOGICMEMREGN, NodeList)
[45970]893 {
894 RTListNodeRemove(&pIt->NodeList);
895 RTMemFree(pIt);
896 }
[81781]897 pThisCC->cbMemRegns = 0;
[45970]898}
899
900/**
901 * Inserts a given memory region into the list.
902 *
[81781]903 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]904 * @param pRegion The region to insert.
905 */
[81781]906static void lsilogicR3MemRegionInsert(PLSILOGICSCSICC pThisCC, PLSILOGICMEMREGN pRegion)
[45970]907{
908 bool fInserted = false;
909
910 /* Insert at the right position. */
[64766]911 PLSILOGICMEMREGN pIt;
[81781]912 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
[45970]913 {
914 if (pRegion->u32AddrEnd < pIt->u32AddrStart)
915 {
916 RTListNodeInsertBefore(&pIt->NodeList, &pRegion->NodeList);
917 fInserted = true;
918 break;
919 }
920 }
921 if (!fInserted)
[81781]922 RTListAppend(&pThisCC->ListMemRegns, &pRegion->NodeList);
[45970]923}
924
925/**
926 * Count number of memory regions.
927 *
928 * @returns Number of memory regions.
[81781]929 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]930 */
[81781]931static uint32_t lsilogicR3MemRegionsCount(PLSILOGICSCSICC pThisCC)
[45970]932{
933 uint32_t cRegions = 0;
[64766]934
[45970]935 PLSILOGICMEMREGN pIt;
[81781]936 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
[45970]937 {
938 cRegions++;
939 }
940
941 return cRegions;
942}
943
944/**
945 * Handles a write to the diagnostic data register.
946 *
[81781]947 * @param pThis Pointer to the shared LsiLogic device state.
948 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]949 * @param u32Data Data to write.
950 */
[81781]951static void lsilogicR3DiagRegDataWrite(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC, uint32_t u32Data)
[45970]952{
[88530]953 RTCritSectEnter(&pThisCC->CritSectMemRegns);
954
[81781]955 PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThisCC, pThis->u32DiagMemAddr);
[45970]956 if (pRegion)
957 {
958 uint32_t offRegion = pThis->u32DiagMemAddr - pRegion->u32AddrStart;
959
960 AssertMsg( offRegion % 4 == 0
961 && pThis->u32DiagMemAddr <= pRegion->u32AddrEnd,
962 ("Region offset not on a word boundary or crosses memory region\n"));
963
964 offRegion /= 4;
965 pRegion->au32Data[offRegion] = u32Data;
966 }
[45789]967 else
[45970]968 {
969 pRegion = NULL;
970
971 /* Create new region, first check whether we can extend another region. */
[64766]972 PLSILOGICMEMREGN pIt;
[81781]973 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
[45970]974 {
975 if (pThis->u32DiagMemAddr == pIt->u32AddrEnd + sizeof(uint32_t))
976 {
977 pRegion = pIt;
978 break;
979 }
980 }
981
982 if (pRegion)
983 {
984 /* Reallocate. */
985 RTListNodeRemove(&pRegion->NodeList);
986
987 uint32_t cRegionSizeOld = (pRegion->u32AddrEnd - pRegion->u32AddrStart) / 4 + 1;
988 uint32_t cRegionSizeNew = cRegionSizeOld + 512;
989
[81781]990 if (pThisCC->cbMemRegns + 512 * sizeof(uint32_t) < LSILOGIC_MEMORY_REGIONS_MAX)
[45970]991 {
[73097]992 PLSILOGICMEMREGN pRegionNew;
993 pRegionNew = (PLSILOGICMEMREGN)RTMemRealloc(pRegion, RT_UOFFSETOF_DYN(LSILOGICMEMREGN, au32Data[cRegionSizeNew]));
[46253]994 if (pRegionNew)
995 {
996 pRegion = pRegionNew;
997 memset(&pRegion->au32Data[cRegionSizeOld], 0, 512 * sizeof(uint32_t));
998 pRegion->au32Data[cRegionSizeOld] = u32Data;
999 pRegion->u32AddrEnd = pRegion->u32AddrStart + (cRegionSizeNew - 1) * sizeof(uint32_t);
[81781]1000 pThisCC->cbMemRegns += 512 * sizeof(uint32_t);
[46253]1001 }
1002 /* else: Silently fail, there is nothing we can do here and the guest might work nevertheless. */
1003
[81781]1004 lsilogicR3MemRegionInsert(pThisCC, pRegion);
[45970]1005 }
1006 }
1007 else
1008 {
[81781]1009 if (pThisCC->cbMemRegns + 512 * sizeof(uint32_t) < LSILOGIC_MEMORY_REGIONS_MAX)
[45970]1010 {
[46253]1011 /* Create completely new. */
1012 pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_OFFSETOF(LSILOGICMEMREGN, au32Data[512]));
1013 if (pRegion)
1014 {
1015 pRegion->u32AddrStart = pThis->u32DiagMemAddr;
1016 pRegion->u32AddrEnd = pRegion->u32AddrStart + (512 - 1) * sizeof(uint32_t);
1017 pRegion->au32Data[0] = u32Data;
[81781]1018 pThisCC->cbMemRegns += 512 * sizeof(uint32_t);
[45970]1019
[81781]1020 lsilogicR3MemRegionInsert(pThisCC, pRegion);
[46253]1021 }
1022 /* else: Silently fail, there is nothing we can do here and the guest might work nevertheless. */
[45970]1023 }
1024 }
1025
1026 }
1027
1028 /* Memory access is always 32bit big. */
1029 pThis->u32DiagMemAddr += sizeof(uint32_t);
[88530]1030 RTCritSectLeave(&pThisCC->CritSectMemRegns);
[45789]1031}
1032
[21321]1033/**
[45970]1034 * Handles a read from the diagnostic data register.
1035 *
[81781]1036 * @param pThis Pointer to the shared LsiLogic device state.
1037 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[45970]1038 * @param pu32Data Where to store the data.
1039 */
[81781]1040static void lsilogicR3DiagRegDataRead(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC, uint32_t *pu32Data)
[45970]1041{
[88530]1042 RTCritSectEnter(&pThisCC->CritSectMemRegns);
1043
[81781]1044 PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThisCC, pThis->u32DiagMemAddr);
[45970]1045 if (pRegion)
1046 {
1047 uint32_t offRegion = pThis->u32DiagMemAddr - pRegion->u32AddrStart;
1048
1049 AssertMsg( offRegion % 4 == 0
1050 && pThis->u32DiagMemAddr <= pRegion->u32AddrEnd,
1051 ("Region offset not on a word boundary or crosses memory region\n"));
1052
1053 offRegion /= 4;
1054 *pu32Data = pRegion->au32Data[offRegion];
1055 }
1056 else /* No region, default value 0. */
1057 *pu32Data = 0;
1058
1059 /* Memory access is always 32bit big. */
1060 pThis->u32DiagMemAddr += sizeof(uint32_t);
[88530]1061 RTCritSectLeave(&pThisCC->CritSectMemRegns);
[45970]1062}
1063
1064/**
1065 * Handles a write to the diagnostic memory address register.
1066 *
[81781]1067 * @param pThis Pointer to the shared LsiLogic device state.
[45970]1068 * @param u32Addr Address to write.
1069 */
1070static void lsilogicR3DiagRegAddressWrite(PLSILOGICSCSI pThis, uint32_t u32Addr)
1071{
1072 pThis->u32DiagMemAddr = u32Addr & ~UINT32_C(0x3); /* 32bit alignment. */
1073}
1074
1075/**
1076 * Handles a read from the diagnostic memory address register.
1077 *
[81781]1078 * @param pThis Pointer to the shared LsiLogic device state.
[45970]1079 * @param pu32Addr Where to store the current address.
1080 */
1081static void lsilogicR3DiagRegAddressRead(PLSILOGICSCSI pThis, uint32_t *pu32Addr)
1082{
1083 *pu32Addr = pThis->u32DiagMemAddr;
1084}
1085
1086/**
[21321]1087 * Processes a given Request from the guest
1088 *
1089 * @returns VBox status code.
[81781]1090 * @param pDevIns The device instance.
1091 * @param pThis Pointer to the shared LsiLogic device state.
1092 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[44694]1093 * @param pMessageHdr Pointer to the message header of the request.
1094 * @param pReply Pointer to the reply.
[21321]1095 */
[81781]1096static int lsilogicR3ProcessMessageRequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
1097 PMptMessageHdr pMessageHdr, PMptReplyUnion pReply)
[21321]1098{
1099 int rc = VINF_SUCCESS;
1100 bool fForceReplyPostFifo = false;
1101
[44694]1102# ifdef LOG_ENABLED
[21321]1103 if (pMessageHdr->u8Function < RT_ELEMENTS(g_apszMPTFunctionNames))
1104 Log(("Message request function: %s\n", g_apszMPTFunctionNames[pMessageHdr->u8Function]));
1105 else
1106 Log(("Message request function: <unknown>\n"));
[44694]1107# endif
[21321]1108
1109 memset(pReply, 0, sizeof(MptReplyUnion));
1110
1111 switch (pMessageHdr->u8Function)
1112 {
1113 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
1114 {
1115 PMptSCSITaskManagementRequest pTaskMgmtReq = (PMptSCSITaskManagementRequest)pMessageHdr;
1116
[29588]1117 LogFlow(("u8TaskType=%u\n", pTaskMgmtReq->u8TaskType));
1118 LogFlow(("u32TaskMessageContext=%#x\n", pTaskMgmtReq->u32TaskMessageContext));
1119
[21321]1120 pReply->SCSITaskManagement.u8MessageLength = 6; /* 6 32bit dwords. */
1121 pReply->SCSITaskManagement.u8TaskType = pTaskMgmtReq->u8TaskType;
1122 pReply->SCSITaskManagement.u32TerminationCount = 0;
1123 fForceReplyPostFifo = true;
1124 break;
1125 }
1126 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
1127 {
1128 /*
1129 * This request sets the I/O controller to the
1130 * operational state.
1131 */
1132 PMptIOCInitRequest pIOCInitReq = (PMptIOCInitRequest)pMessageHdr;
1133
1134 /* Update configuration values. */
[44694]1135 pThis->enmWhoInit = (LSILOGICWHOINIT)pIOCInitReq->u8WhoInit;
1136 pThis->cbReplyFrame = pIOCInitReq->u16ReplyFrameSize;
1137 pThis->cMaxBuses = pIOCInitReq->u8MaxBuses;
1138 pThis->cMaxDevices = pIOCInitReq->u8MaxDevices;
1139 pThis->u32HostMFAHighAddr = pIOCInitReq->u32HostMfaHighAddr;
1140 pThis->u32SenseBufferHighAddr = pIOCInitReq->u32SenseBufferHighAddr;
[21321]1141
[44694]1142 if (pThis->enmState == LSILOGICSTATE_READY)
[21321]1143 {
[44694]1144 pThis->enmState = LSILOGICSTATE_OPERATIONAL;
[21321]1145 }
1146
1147 /* Return reply. */
1148 pReply->IOCInit.u8MessageLength = 5;
[44694]1149 pReply->IOCInit.u8WhoInit = pThis->enmWhoInit;
1150 pReply->IOCInit.u8MaxDevices = pThis->cMaxDevices;
1151 pReply->IOCInit.u8MaxBuses = pThis->cMaxBuses;
[21321]1152 break;
1153 }
1154 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
1155 {
1156 pReply->IOCFacts.u8MessageLength = 15; /* 15 32bit dwords. */
[25587]1157
[44694]1158 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]1159 {
1160 pReply->IOCFacts.u16MessageVersion = 0x0102; /* Version from the specification. */
[44694]1161 pReply->IOCFacts.u8NumberOfPorts = pThis->cPorts;
[25587]1162 }
[44694]1163 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]1164 {
1165 pReply->IOCFacts.u16MessageVersion = 0x0105; /* Version from the specification. */
[44694]1166 pReply->IOCFacts.u8NumberOfPorts = pThis->cPorts;
[25587]1167 }
1168 else
[44694]1169 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
[25587]1170
[21321]1171 pReply->IOCFacts.u8IOCNumber = 0; /* PCI function number. */
1172 pReply->IOCFacts.u16IOCExceptions = 0;
1173 pReply->IOCFacts.u8MaxChainDepth = LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH;
[44694]1174 pReply->IOCFacts.u8WhoInit = pThis->enmWhoInit;
[21321]1175 pReply->IOCFacts.u8BlockSize = 12; /* Block size in 32bit dwords. This is the largest request we can get (SCSI I/O). */
1176 pReply->IOCFacts.u8Flags = 0; /* Bit 0 is set if the guest must upload the FW prior to using the controller. Obviously not needed here. */
[44694]1177 pReply->IOCFacts.u16ReplyQueueDepth = pThis->cReplyQueueEntries - 1; /* One entry is always free. */
[63562]1178 pReply->IOCFacts.u16RequestFrameSize = 128; /** @todo Figure out where it is needed. */
[44694]1179 pReply->IOCFacts.u32CurrentHostMFAHighAddr = pThis->u32HostMFAHighAddr;
1180 pReply->IOCFacts.u16GlobalCredits = pThis->cRequestQueueEntries - 1; /* One entry is always free. */
[25587]1181
[21321]1182 pReply->IOCFacts.u8EventState = 0; /* Event notifications not enabled. */
[44694]1183 pReply->IOCFacts.u32CurrentSenseBufferHighAddr = pThis->u32SenseBufferHighAddr;
1184 pReply->IOCFacts.u16CurReplyFrameSize = pThis->cbReplyFrame;
1185 pReply->IOCFacts.u8MaxDevices = pThis->cMaxDevices;
1186 pReply->IOCFacts.u8MaxBuses = pThis->cMaxBuses;
[45970]1187
[87164]1188 pReply->IOCFacts.u16ProductID = 0xcafe; /* Our own product ID :) */
1189 pReply->IOCFacts.u32FwImageSize = 0; /* No image needed. */
1190 pReply->IOCFacts.u32FWVersion = 0;
1191
1192 /* Check for a valid firmware image in the IOC memory which was downloaded by the guest earlier and use that. */
[88530]1193 RTCritSectEnter(&pThisCC->CritSectMemRegns);
[81781]1194 PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThisCC, LSILOGIC_FWIMGHDR_LOAD_ADDRESS);
[45970]1195 if (pRegion)
1196 {
[87164]1197 uint32_t offImgHdr = (LSILOGIC_FWIMGHDR_LOAD_ADDRESS - pRegion->u32AddrStart);
1198 if (pRegion->u32AddrEnd - offImgHdr + 1 >= sizeof(FwImageHdr)) /* End address is inclusive. */
[45970]1199 {
[87164]1200 PFwImageHdr pFwImgHdr = (PFwImageHdr)&pRegion->au32Data[offImgHdr / 4];
[45970]1201
[87164]1202 /* Check for the signature. */
1203 /** @todo Checksum validation. */
1204 if ( pFwImgHdr->u32Signature1 == LSILOGIC_FWIMGHDR_SIGNATURE1
1205 && pFwImgHdr->u32Signature2 == LSILOGIC_FWIMGHDR_SIGNATURE2
1206 && pFwImgHdr->u32Signature3 == LSILOGIC_FWIMGHDR_SIGNATURE3)
1207 {
1208 LogFlowFunc(("IOC Facts: Found valid firmware image header in memory, using version (%#x), size (%d) and product ID (%#x) from there\n",
1209 pFwImgHdr->u32FwVersion, pFwImgHdr->u32ImageSize, pFwImgHdr->u16ProductId));
1210
1211 pReply->IOCFacts.u16ProductID = pFwImgHdr->u16ProductId;
1212 pReply->IOCFacts.u32FwImageSize = pFwImgHdr->u32ImageSize;
1213 pReply->IOCFacts.u32FWVersion = pFwImgHdr->u32FwVersion;
1214 }
[45970]1215 }
1216 }
[88530]1217 RTCritSectLeave(&pThisCC->CritSectMemRegns);
[21321]1218 break;
1219 }
1220 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
1221 {
1222 PMptPortFactsRequest pPortFactsReq = (PMptPortFactsRequest)pMessageHdr;
1223
1224 pReply->PortFacts.u8MessageLength = 10;
1225 pReply->PortFacts.u8PortNumber = pPortFactsReq->u8PortNumber;
1226
[44694]1227 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[21321]1228 {
[25587]1229 /* This controller only supports one bus with bus number 0. */
[44694]1230 if (pPortFactsReq->u8PortNumber >= pThis->cPorts)
[25587]1231 {
1232 pReply->PortFacts.u8PortType = 0; /* Not existant. */
1233 }
1234 else
1235 {
1236 pReply->PortFacts.u8PortType = 0x01; /* SCSI Port. */
[25675]1237 pReply->PortFacts.u16MaxDevices = LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
[25587]1238 pReply->PortFacts.u16ProtocolFlags = RT_BIT(3) | RT_BIT(0); /* SCSI initiator and LUN supported. */
1239 pReply->PortFacts.u16PortSCSIID = 7; /* Default */
1240 pReply->PortFacts.u16MaxPersistentIDs = 0;
1241 pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
1242 pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */
1243 }
[21321]1244 }
[44694]1245 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[21321]1246 {
[44694]1247 if (pPortFactsReq->u8PortNumber >= pThis->cPorts)
[25587]1248 {
1249 pReply->PortFacts.u8PortType = 0; /* Not existant. */
1250 }
1251 else
1252 {
1253 pReply->PortFacts.u8PortType = 0x30; /* SAS Port. */
[44694]1254 pReply->PortFacts.u16MaxDevices = pThis->cPorts;
[25587]1255 pReply->PortFacts.u16ProtocolFlags = RT_BIT(3) | RT_BIT(0); /* SCSI initiator and LUN supported. */
[44694]1256 pReply->PortFacts.u16PortSCSIID = pThis->cPorts;
[25587]1257 pReply->PortFacts.u16MaxPersistentIDs = 0;
1258 pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
1259 pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */
1260 }
[21321]1261 }
[25587]1262 else
[44694]1263 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
[21321]1264 break;
1265 }
1266 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
1267 {
1268 /*
1269 * The port enable request notifies the IOC to make the port available and perform
1270 * appropriate discovery on the associated link.
1271 */
1272 PMptPortEnableRequest pPortEnableReq = (PMptPortEnableRequest)pMessageHdr;
1273
1274 pReply->PortEnable.u8MessageLength = 5;
1275 pReply->PortEnable.u8PortNumber = pPortEnableReq->u8PortNumber;
1276 break;
1277 }
1278 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
1279 {
1280 PMptEventNotificationRequest pEventNotificationReq = (PMptEventNotificationRequest)pMessageHdr;
1281
1282 if (pEventNotificationReq->u8Switch)
[44694]1283 pThis->fEventNotificationEnabled = true;
[21321]1284 else
[44694]1285 pThis->fEventNotificationEnabled = false;
[21321]1286
1287 pReply->EventNotification.u16EventDataLength = 1; /* 1 32bit D-Word. */
1288 pReply->EventNotification.u8MessageLength = 8;
1289 pReply->EventNotification.u8MessageFlags = (1 << 7);
1290 pReply->EventNotification.u8AckRequired = 0;
1291 pReply->EventNotification.u32Event = MPT_EVENT_EVENT_CHANGE;
1292 pReply->EventNotification.u32EventContext = 0;
[44694]1293 pReply->EventNotification.u32EventData = pThis->fEventNotificationEnabled ? 1 : 0;
[21321]1294
1295 break;
1296 }
1297 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
1298 {
1299 AssertMsgFailed(("todo"));
1300 break;
1301 }
1302 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
1303 {
1304 PMptConfigurationRequest pConfigurationReq = (PMptConfigurationRequest)pMessageHdr;
1305
[81781]1306 rc = lsilogicR3ProcessConfigurationRequest(pDevIns, pThis, pThisCC, pConfigurationReq, &pReply->Configuration);
[21321]1307 AssertRC(rc);
1308 break;
1309 }
[33115]1310 case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
1311 {
1312 PMptFWUploadRequest pFWUploadReq = (PMptFWUploadRequest)pMessageHdr;
1313
1314 pReply->FWUpload.u8ImageType = pFWUploadReq->u8ImageType;
1315 pReply->FWUpload.u8MessageLength = 6;
1316 pReply->FWUpload.u32ActualImageSize = 0;
1317 break;
1318 }
1319 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
1320 {
1321 //PMptFWDownloadRequest pFWDownloadReq = (PMptFWDownloadRequest)pMessageHdr;
1322
1323 pReply->FWDownload.u8MessageLength = 5;
[45970]1324 LogFlowFunc(("FW Download request issued\n"));
[33115]1325 break;
1326 }
[21321]1327 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: /* Should be handled already. */
1328 default:
1329 AssertMsgFailed(("Invalid request function %#x\n", pMessageHdr->u8Function));
1330 }
1331
1332 /* Copy common bits from request message frame to reply. */
1333 pReply->Header.u8Function = pMessageHdr->u8Function;
1334 pReply->Header.u32MessageContext = pMessageHdr->u32MessageContext;
1335
[81781]1336 lsilogicFinishAddressReply(pDevIns, pThis, pReply, fForceReplyPostFifo);
[21321]1337 return rc;
1338}
[45970]1339
[44694]1340#endif /* IN_RING3 */
[21321]1341
1342/**
1343 * Writes a value to a register at a given offset.
1344 *
[81773]1345 * @returns Strict VBox status code.
1346 * @param pDevIns The devie instance.
[81781]1347 * @param pThis Pointer to the shared LsiLogic device state.
[44696]1348 * @param offReg Offset of the register to write.
1349 * @param u32 The value being written.
[21321]1350 */
[81773]1351static VBOXSTRICTRC lsilogicRegisterWrite(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, uint32_t offReg, uint32_t u32)
[21321]1352{
[44696]1353 LogFlowFunc(("pThis=%#p offReg=%#x u32=%#x\n", pThis, offReg, u32));
1354 switch (offReg)
[21321]1355 {
1356 case LSILOGIC_REG_REPLY_QUEUE:
1357 {
[81773]1358 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->ReplyFreeQueueWriteCritSect, VINF_IOM_R3_MMIO_WRITE);
[64808]1359 if (rc != VINF_SUCCESS)
1360 return rc;
[21321]1361 /* Add the entry to the reply free queue. */
[81751]1362 ASMAtomicWriteU32(&pThis->aReplyFreeQueue[pThis->uReplyFreeQueueNextEntryFreeWrite], u32);
[21321]1363 pThis->uReplyFreeQueueNextEntryFreeWrite++;
1364 pThis->uReplyFreeQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries;
[81773]1365 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyFreeQueueWriteCritSect);
[21321]1366 break;
1367 }
1368 case LSILOGIC_REG_REQUEST_QUEUE:
1369 {
[81773]1370 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->RequestQueueCritSect, VINF_IOM_R3_MMIO_WRITE);
[64808]1371 if (rc != VINF_SUCCESS)
1372 return rc;
1373
[30975]1374 uint32_t uNextWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite);
[21321]1375
[81751]1376 ASMAtomicWriteU32(&pThis->aRequestQueue[uNextWrite], u32);
[30975]1377
1378 /*
1379 * Don't update the value in place. It can happen that we get preempted
1380 * after the increment but before the modulo.
1381 * Another EMT will read the wrong value when processing the queues
1382 * and hang in an endless loop creating thousands of requests.
1383 */
1384 uNextWrite++;
1385 uNextWrite %= pThis->cRequestQueueEntries;
1386 ASMAtomicWriteU32(&pThis->uRequestQueueNextEntryFreeWrite, uNextWrite);
[81773]1387 PDMDevHlpCritSectLeave(pDevIns, &pThis->RequestQueueCritSect);
[30975]1388
[53341]1389 /* Send notification to R3 if there is not one sent already. Do this
1390 * only if the worker thread is not sleeping or might go sleeping. */
[53343]1391 if (!ASMAtomicXchgBool(&pThis->fNotificationSent, true))
[21321]1392 {
[53343]1393 if (ASMAtomicReadBool(&pThis->fWrkThreadSleeping))
[53341]1394 {
1395 LogFlowFunc(("Signal event semaphore\n"));
[81773]1396 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
[53341]1397 AssertRC(rc);
1398 }
[21321]1399 }
1400 break;
1401 }
1402 case LSILOGIC_REG_DOORBELL:
1403 {
1404 /*
1405 * When the guest writes to this register a real device would set the
1406 * doorbell status bit in the interrupt status register to indicate that the IOP
1407 * has still to process the message.
1408 * The guest needs to wait with posting new messages here until the bit is cleared.
1409 * Because the guest is not continuing execution while we are here we can skip this.
1410 */
[45789]1411 if (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_NOT_IN_USE)
[21321]1412 {
1413 uint32_t uFunction = LSILOGIC_REG_DOORBELL_GET_FUNCTION(u32);
1414
1415 switch (uFunction)
1416 {
[45789]1417 case LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET:
[21321]1418 case LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET:
1419 {
[45789]1420 /*
1421 * The I/O unit reset does much more on real hardware like
1422 * reloading the firmware, nothing we need to do here,
1423 * so this is like the IOC message unit reset.
1424 */
[21321]1425 pThis->enmState = LSILOGICSTATE_RESET;
1426
[30128]1427 /* Reset interrupt status. */
[21321]1428 pThis->uInterruptStatus = 0;
[81781]1429 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]1430
1431 /* Reset the queues. */
1432 pThis->uReplyFreeQueueNextEntryFreeWrite = 0;
1433 pThis->uReplyFreeQueueNextAddressRead = 0;
1434 pThis->uReplyPostQueueNextEntryFreeWrite = 0;
1435 pThis->uReplyPostQueueNextAddressRead = 0;
1436 pThis->uRequestQueueNextEntryFreeWrite = 0;
1437 pThis->uRequestQueueNextAddressRead = 0;
[45789]1438
1439 /* Only the IOC message unit reset transisionts to the ready state. */
1440 if (uFunction == LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET)
1441 pThis->enmState = LSILOGICSTATE_READY;
[21321]1442 break;
1443 }
1444 case LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE:
1445 {
1446 pThis->cMessage = LSILOGIC_REG_DOORBELL_GET_SIZE(u32);
1447 pThis->iMessage = 0;
[85101]1448
1449 /* This is not supposed to happen and the result is undefined, just stay in the current state. */
1450 AssertMsgReturn(pThis->cMessage <= RT_ELEMENTS(pThis->aMessage),
1451 ("Message doesn't fit into the buffer, cMessage=%u", pThis->cMessage),
1452 VINF_SUCCESS);
1453
[45789]1454 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE;
[21321]1455 /* Update the interrupt status to notify the guest that a doorbell function was started. */
[81781]1456 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[21321]1457 break;
1458 }
1459 case LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL:
1460 {
[45789]1461 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW;
1462 /* Update the interrupt status to notify the guest that a doorbell function was started. */
[81781]1463 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[21321]1464 break;
1465 }
1466 default:
1467 AssertMsgFailed(("Unknown function %u to perform\n", uFunction));
1468 }
1469 }
[45789]1470 else if (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_FN_HANDSHAKE)
[21321]1471 {
1472 /*
1473 * We are already performing a doorbell function.
[85134]1474 * Get the remaining parameters, ignore any excess writes.
[21321]1475 */
[85134]1476 AssertMsgReturn(pThis->iMessage < pThis->cMessage,
1477 ("Guest is trying to write more than was indicated in the handshake\n"),
1478 VINF_SUCCESS);
1479
[21321]1480 /*
1481 * If the last byte of the message is written, force a switch to R3 because some requests might force
1482 * a reply through the FIFO which cannot be handled in GC or R0.
1483 */
1484#ifndef IN_RING3
1485 if (pThis->iMessage == pThis->cMessage - 1)
[40280]1486 return VINF_IOM_R3_MMIO_WRITE;
[21321]1487#endif
1488 pThis->aMessage[pThis->iMessage++] = u32;
1489#ifdef IN_RING3
1490 if (pThis->iMessage == pThis->cMessage)
1491 {
[81781]1492 int rc = lsilogicR3ProcessMessageRequest(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC),
1493 (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer);
[21321]1494 AssertRC(rc);
1495 }
1496#endif
1497 }
1498 break;
1499 }
1500 case LSILOGIC_REG_HOST_INTR_STATUS:
1501 {
1502 /*
1503 * Clear the bits the guest wants except the system doorbell interrupt and the IO controller
1504 * status bit.
1505 * The former bit is always cleared no matter what the guest writes to the register and
1506 * the latter one is read only.
1507 */
[29827]1508 ASMAtomicAndU32(&pThis->uInterruptStatus, ~LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[21321]1509
1510 /*
1511 * Check if there is still a doorbell function in progress. Set the
1512 * system doorbell interrupt bit again if it is.
1513 * We do not use lsilogicSetInterrupt here because the interrupt status
1514 * is updated afterwards anyway.
1515 */
[45789]1516 if ( (pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_FN_HANDSHAKE)
[21321]1517 && (pThis->cMessage == pThis->iMessage))
1518 {
1519 if (pThis->uNextReplyEntryRead == pThis->cReplySize)
1520 {
1521 /* Reply finished. Reset doorbell in progress status. */
1522 Log(("%s: Doorbell function finished\n", __FUNCTION__));
[45789]1523 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
[21321]1524 }
1525 ASMAtomicOrU32(&pThis->uInterruptStatus, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1526 }
[45789]1527 else if ( pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_NOT_IN_USE
1528 && pThis->enmDoorbellState != LSILOGICDOORBELLSTATE_FN_HANDSHAKE)
1529 {
1530 /* Reply frame removal, check whether the reply free queue is empty. */
1531 if ( pThis->uReplyFreeQueueNextAddressRead == pThis->uReplyFreeQueueNextEntryFreeWrite
1532 && pThis->enmDoorbellState == LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW)
1533 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
1534 ASMAtomicOrU32(&pThis->uInterruptStatus, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1535 }
[21321]1536
[81781]1537 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]1538 break;
1539 }
1540 case LSILOGIC_REG_HOST_INTR_MASK:
1541 {
[29827]1542 ASMAtomicWriteU32(&pThis->uInterruptMask, u32 & LSILOGIC_REG_HOST_INTR_MASK_W_MASK);
[81781]1543 lsilogicUpdateInterrupt(pDevIns, pThis);
[21321]1544 break;
1545 }
1546 case LSILOGIC_REG_WRITE_SEQUENCE:
1547 {
1548 if (pThis->fDiagnosticEnabled)
1549 {
1550 /* Any value will cause a reset and disabling access. */
1551 pThis->fDiagnosticEnabled = false;
1552 pThis->iDiagnosticAccess = 0;
[45970]1553 pThis->fDiagRegsEnabled = false;
[21321]1554 }
1555 else if ((u32 & 0xf) == g_lsilogicDiagnosticAccess[pThis->iDiagnosticAccess])
1556 {
1557 pThis->iDiagnosticAccess++;
1558 if (pThis->iDiagnosticAccess == RT_ELEMENTS(g_lsilogicDiagnosticAccess))
1559 {
1560 /*
1561 * Key sequence successfully written. Enable access to diagnostic
1562 * memory and register.
1563 */
1564 pThis->fDiagnosticEnabled = true;
1565 }
1566 }
1567 else
1568 {
1569 /* Wrong value written - reset to beginning. */
1570 pThis->iDiagnosticAccess = 0;
1571 }
1572 break;
1573 }
[25487]1574 case LSILOGIC_REG_HOST_DIAGNOSTIC:
1575 {
[45970]1576 if (pThis->fDiagnosticEnabled)
1577 {
[25487]1578#ifndef IN_RING3
[45970]1579 return VINF_IOM_R3_MMIO_WRITE;
[25487]1580#else
[45970]1581 if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER)
[81781]1582 lsilogicR3HardReset(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC));
[45970]1583 else if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE)
1584 pThis->fDiagRegsEnabled = true;
1585#endif
1586 }
1587 break;
1588 }
1589 case LSILOGIC_REG_DIAG_RW_DATA:
1590 {
1591 if (pThis->fDiagRegsEnabled)
[25487]1592 {
[45970]1593#ifndef IN_RING3
1594 return VINF_IOM_R3_MMIO_WRITE;
1595#else
[81781]1596 lsilogicR3DiagRegDataWrite(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC), u32);
[45970]1597#endif
[25487]1598 }
1599 break;
[45970]1600 }
1601 case LSILOGIC_REG_DIAG_RW_ADDRESS:
1602 {
1603 if (pThis->fDiagRegsEnabled)
1604 {
1605#ifndef IN_RING3
1606 return VINF_IOM_R3_MMIO_WRITE;
1607#else
1608 lsilogicR3DiagRegAddressWrite(pThis, u32);
[25487]1609#endif
[45970]1610 }
1611 break;
[25487]1612 }
[21321]1613 default: /* Ignore. */
1614 {
1615 break;
1616 }
1617 }
1618 return VINF_SUCCESS;
1619}
1620
1621/**
1622 * Reads the content of a register at a given offset.
1623 *
1624 * @returns VBox status code.
[81773]1625 * @param pDevIns The device instance.
[81781]1626 * @param pThis Pointer to the shared LsiLogic device state.
[44695]1627 * @param offReg Offset of the register to read.
1628 * @param pu32 Where to store the content of the register.
[21321]1629 */
[81773]1630static VBOXSTRICTRC lsilogicRegisterRead(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, uint32_t offReg, uint32_t *pu32)
[21321]1631{
[29827]1632 int rc = VINF_SUCCESS;
[25380]1633 uint32_t u32 = 0;
[44695]1634 Assert(!(offReg & 3));
[21321]1635
[25732]1636 /* Align to a 4 byte offset. */
[44695]1637 switch (offReg)
[21321]1638 {
1639 case LSILOGIC_REG_REPLY_QUEUE:
1640 {
[81773]1641 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->ReplyPostQueueCritSect, VINF_IOM_R3_MMIO_READ);
[29827]1642 if (rc != VINF_SUCCESS)
1643 break;
1644
1645 uint32_t idxReplyPostQueueWrite = ASMAtomicUoReadU32(&pThis->uReplyPostQueueNextEntryFreeWrite);
1646 uint32_t idxReplyPostQueueRead = ASMAtomicUoReadU32(&pThis->uReplyPostQueueNextAddressRead);
1647
1648 if (idxReplyPostQueueWrite != idxReplyPostQueueRead)
[21321]1649 {
[81751]1650 u32 = pThis->aReplyPostQueue[idxReplyPostQueueRead];
[29827]1651 idxReplyPostQueueRead++;
1652 idxReplyPostQueueRead %= pThis->cReplyQueueEntries;
1653 ASMAtomicWriteU32(&pThis->uReplyPostQueueNextAddressRead, idxReplyPostQueueRead);
[21321]1654 }
1655 else
1656 {
1657 /* The reply post queue is empty. Reset interrupt. */
[25380]1658 u32 = UINT32_C(0xffffffff);
[81781]1659 lsilogicClearInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
[21321]1660 }
[81773]1661 PDMDevHlpCritSectLeave(pDevIns, &pThis->ReplyPostQueueCritSect);
[29827]1662
[25380]1663 Log(("%s: Returning address %#x\n", __FUNCTION__, u32));
[21321]1664 break;
1665 }
1666 case LSILOGIC_REG_DOORBELL:
1667 {
[25380]1668 u32 = LSILOGIC_REG_DOORBELL_SET_STATE(pThis->enmState);
[45789]1669 u32 |= LSILOGIC_REG_DOORBELL_SET_USED(pThis->enmDoorbellState);
[25380]1670 u32 |= LSILOGIC_REG_DOORBELL_SET_WHOINIT(pThis->enmWhoInit);
[21321]1671 /*
1672 * If there is a doorbell function in progress we pass the return value
1673 * instead of the status code. We transfer 16bit of the reply
1674 * during one read.
1675 */
[45789]1676 switch (pThis->enmDoorbellState)
[21321]1677 {
[45789]1678 case LSILOGICDOORBELLSTATE_NOT_IN_USE:
1679 /* We return the status code of the I/O controller. */
1680 u32 |= pThis->u16IOCFaultCode;
1681 break;
1682 case LSILOGICDOORBELLSTATE_FN_HANDSHAKE:
1683 /* Return next 16bit value. */
[65445]1684 if (pThis->uNextReplyEntryRead < pThis->cReplySize)
1685 u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++];
[81781]1686 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[45789]1687 break;
1688 case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW:
1689 {
1690 uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis);
1691
1692 u32 |= cReplyFrames & UINT32_C(0xffff);
1693 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH;
[81781]1694 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[45789]1695 break;
1696 }
1697 case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH:
1698 {
1699 uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis);
1700
1701 u32 |= cReplyFrames >> 16;
1702 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW;
[81781]1703 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[45789]1704 break;
1705 }
1706 case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW:
1707 if (pThis->uReplyFreeQueueNextEntryFreeWrite != pThis->uReplyFreeQueueNextAddressRead)
1708 {
[81751]1709 u32 |= pThis->aReplyFreeQueue[pThis->uReplyFreeQueueNextAddressRead] & UINT32_C(0xffff);
[45789]1710 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH;
[81781]1711 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[45789]1712 }
1713 break;
1714 case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH:
[81751]1715 u32 |= pThis->aReplyFreeQueue[pThis->uReplyFreeQueueNextAddressRead] >> 16;
[45789]1716 pThis->uReplyFreeQueueNextAddressRead++;
1717 pThis->uReplyFreeQueueNextAddressRead %= pThis->cReplyQueueEntries;
1718 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW;
[81781]1719 lsilogicSetInterrupt(pDevIns, pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
[45789]1720 break;
1721 default:
1722 AssertMsgFailed(("Invalid doorbell state %d\n", pThis->enmDoorbellState));
[21321]1723 }
[45789]1724
[21321]1725 break;
1726 }
1727 case LSILOGIC_REG_HOST_INTR_STATUS:
1728 {
[29827]1729 u32 = ASMAtomicReadU32(&pThis->uInterruptStatus);
[21321]1730 break;
1731 }
1732 case LSILOGIC_REG_HOST_INTR_MASK:
1733 {
[29827]1734 u32 = ASMAtomicReadU32(&pThis->uInterruptMask);
[21321]1735 break;
1736 }
[25487]1737 case LSILOGIC_REG_HOST_DIAGNOSTIC:
1738 {
1739 if (pThis->fDiagnosticEnabled)
[45970]1740 u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
1741 if (pThis->fDiagRegsEnabled)
1742 u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE;
[25487]1743 break;
1744 }
[25380]1745 case LSILOGIC_REG_DIAG_RW_DATA:
[45970]1746 {
1747 if (pThis->fDiagRegsEnabled)
1748 {
1749#ifndef IN_RING3
1750 return VINF_IOM_R3_MMIO_READ;
1751#else
[81781]1752 lsilogicR3DiagRegDataRead(pThis, PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC), &u32);
[45970]1753#endif
1754 }
1755 }
[69046]1756 RT_FALL_THRU();
[25380]1757 case LSILOGIC_REG_DIAG_RW_ADDRESS:
[45970]1758 {
1759 if (pThis->fDiagRegsEnabled)
1760 {
1761#ifndef IN_RING3
1762 return VINF_IOM_R3_MMIO_READ;
1763#else
1764 lsilogicR3DiagRegAddressRead(pThis, &u32);
1765#endif
1766 }
1767 }
[69046]1768 RT_FALL_THRU();
[45970]1769 case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */
[25380]1770 default: /* Ignore. */
[21321]1771 {
[44696]1772 /** @todo LSILOGIC_REG_DIAG_* should return all F's when accessed by MMIO. We
1773 * return 0. Likely to apply to undefined offsets as well. */
[21321]1774 break;
1775 }
[25380]1776 }
1777
[44695]1778 *pu32 = u32;
1779 LogFlowFunc(("pThis=%#p offReg=%#x u32=%#x\n", pThis, offReg, u32));
[29827]1780 return rc;
[21321]1781}
1782
[44696]1783/**
[81773]1784 * @callback_method_impl{FNIOMIOPORTNEWOUT}
[44696]1785 */
[81773]1786static DECLCALLBACK(VBOXSTRICTRC)
1787lsilogicIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
[21321]1788{
[81591]1789 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[81773]1790 VBOXSTRICTRC rcStrict;
[62632]1791 RT_NOREF2(pvUser, cb);
[21321]1792
[81773]1793 if (!(offPort & 3))
[44696]1794 {
[81773]1795 rcStrict = lsilogicRegisterWrite(pDevIns, pThis, offPort, u32);
1796 if (rcStrict == VINF_IOM_R3_MMIO_WRITE)
1797 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
[44696]1798 }
1799 else
1800 {
[81773]1801 Log(("lsilogicIOPortWrite: Ignoring misaligned write - offPort=%#x u32=%#x cb=%#x\n", offPort, u32, cb));
1802 rcStrict = VINF_SUCCESS;
[44696]1803 }
[21321]1804
[81773]1805 return rcStrict;
[21321]1806}
1807
[44695]1808/**
[81773]1809 * @callback_method_impl{FNIOMIOPORTNEWIN}
[44695]1810 */
[81773]1811static DECLCALLBACK(VBOXSTRICTRC)
1812lsilogicIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
[21321]1813{
[81591]1814 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[62618]1815 RT_NOREF_PV(pvUser);
1816 RT_NOREF_PV(cb);
[21321]1817
[81773]1818 VBOXSTRICTRC rcStrict = lsilogicRegisterRead(pDevIns, pThis, offPort & ~(uint32_t)3, pu32);
1819 if (rcStrict == VINF_IOM_R3_MMIO_READ)
1820 rcStrict = VINF_IOM_R3_IOPORT_READ;
[29827]1821
[81773]1822 return rcStrict;
[21321]1823}
1824
[44696]1825/**
[81773]1826 * @callback_method_impl{FNIOMMMIONEWWRITE}
[44696]1827 */
[81773]1828static DECLCALLBACK(VBOXSTRICTRC) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
[21321]1829{
[81591]1830 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[44696]1831 uint32_t u32;
[62618]1832 RT_NOREF_PV(pvUser);
[21321]1833
[81773]1834 /* See comments in lsilogicR3Construct regarding size and alignment. */
[44696]1835 if (cb == 4)
1836 u32 = *(uint32_t const *)pv;
1837 else
1838 {
1839 if (cb > 4)
1840 u32 = *(uint32_t const *)pv;
1841 else if (cb >= 2)
1842 u32 = *(uint16_t const *)pv;
1843 else
1844 u32 = *(uint8_t const *)pv;
[81773]1845 Log(("lsilogicMMIOWrite: Non-DWORD write access - off=%#RGp u32=%#x cb=%#x\n", off, u32, cb));
[44696]1846 }
1847
[81773]1848 VBOXSTRICTRC rcStrict;
1849 if (!(off & 3))
1850 rcStrict = lsilogicRegisterWrite(pDevIns, pThis, (uint32_t)off, u32);
[44696]1851 else
1852 {
[81773]1853 Log(("lsilogicMMIOWrite: Ignoring misaligned write - off=%#RGp u32=%#x cb=%#x\n", off, u32, cb));
1854 rcStrict = VINF_SUCCESS;
[44696]1855 }
[81773]1856 return rcStrict;
[21321]1857}
1858
[44695]1859/**
[81773]1860 * @callback_method_impl{FNIOMMMIONEWREAD}
[44695]1861 */
[81773]1862static DECLCALLBACK(VBOXSTRICTRC) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
[21321]1863{
[81591]1864 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[81773]1865 Assert(!(off & 3)); Assert(cb == 4); /* If any of these trigger you've changed the registration flags or IOM is busted. */
[62632]1866 RT_NOREF2(pvUser, cb);
[21321]1867
[81773]1868 return lsilogicRegisterRead(pDevIns, pThis, off, (uint32_t *)pv);
[21321]1869}
1870
[81773]1871/**
1872 * @callback_method_impl{FNIOMMMIONEWWRITE}
1873 */
1874static DECLCALLBACK(VBOXSTRICTRC)
1875lsilogicDiagnosticWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
[21321]1876{
[81773]1877 RT_NOREF(pDevIns, pvUser, off, pv, cb);
1878 LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI), off, pv, cb, pv, cb));
[104193]1879 return VINF_IOM_MMIO_UNUSED_FF;
[21321]1880}
1881
[81773]1882/**
1883 * @callback_method_impl{FNIOMMMIONEWREAD}
1884 */
1885static DECLCALLBACK(VBOXSTRICTRC) lsilogicDiagnosticRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
[21321]1886{
[81773]1887 RT_NOREF(pDevIns, pvUser, off, pv, cb);
1888 LogFlowFunc(("pThis=%#p off=%RGp pv=%#p{%.*Rhxs} cb=%u\n", PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI), off, pv, cb, pv, cb));
[21321]1889 return VINF_SUCCESS;
1890}
1891
1892#ifdef IN_RING3
1893
[44694]1894# ifdef LOG_ENABLED
[21321]1895/**
1896 * Dump an SG entry.
1897 *
1898 * @param pSGEntry Pointer to the SG entry to dump
1899 */
1900static void lsilogicDumpSGEntry(PMptSGEntryUnion pSGEntry)
1901{
[44694]1902 if (LogIsEnabled())
[21321]1903 {
[44694]1904 switch (pSGEntry->Simple32.u2ElementType)
[21321]1905 {
[44694]1906 case MPTSGENTRYTYPE_SIMPLE:
[21321]1907 {
[44694]1908 Log(("%s: Dumping info for SIMPLE SG entry:\n", __FUNCTION__));
1909 Log(("%s: u24Length=%u\n", __FUNCTION__, pSGEntry->Simple32.u24Length));
1910 Log(("%s: fEndOfList=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfList));
1911 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.f64BitAddress));
1912 Log(("%s: fBufferContainsData=%d\n", __FUNCTION__, pSGEntry->Simple32.fBufferContainsData));
1913 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.fLocalAddress));
1914 Log(("%s: fEndOfBuffer=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfBuffer));
1915 Log(("%s: fLastElement=%d\n", __FUNCTION__, pSGEntry->Simple32.fLastElement));
1916 Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1917 if (pSGEntry->Simple32.f64BitAddress)
1918 {
1919 Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh));
1920 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__,
1921 ((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32)
1922 | pSGEntry->Simple64.u32DataBufferAddressLow));
1923 }
1924 else
1925 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1926
1927 break;
[21321]1928 }
[44694]1929 case MPTSGENTRYTYPE_CHAIN:
1930 {
1931 Log(("%s: Dumping info for CHAIN SG entry:\n", __FUNCTION__));
1932 Log(("%s: u16Length=%u\n", __FUNCTION__, pSGEntry->Chain.u16Length));
1933 Log(("%s: u8NExtChainOffset=%d\n", __FUNCTION__, pSGEntry->Chain.u8NextChainOffset));
1934 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Chain.f64BitAddress));
1935 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Chain.fLocalAddress));
1936 Log(("%s: u32SegmentAddressLow=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1937 Log(("%s: u32SegmentAddressHigh=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressHigh));
1938 if (pSGEntry->Chain.f64BitAddress)
1939 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__,
1940 ((uint64_t)pSGEntry->Chain.u32SegmentAddressHigh << 32) | pSGEntry->Chain.u32SegmentAddressLow));
1941 else
1942 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1943 break;
1944 }
[21321]1945 }
1946 }
1947}
[44694]1948# endif /* LOG_ENABLED */
[21321]1949
[45970]1950/**
[64224]1951 * Copy from guest to host memory worker.
1952 *
[85121]1953 * @copydoc FNLSILOGICR3MEMCOPYCALLBACK
[64224]1954 */
[81781]1955static DECLCALLBACK(void) lsilogicR3CopyBufferFromGuestWorker(PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
1956 PRTSGBUF pSgBuf, size_t cbCopy, size_t *pcbSkip)
[64224]1957{
1958 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
1959 cbCopy -= cbSkipped;
1960 GCPhys += cbSkipped;
1961 *pcbSkip -= cbSkipped;
1962
1963 while (cbCopy)
1964 {
1965 size_t cbSeg = cbCopy;
1966 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
1967
1968 AssertPtr(pvSeg);
[86483]1969 PDMDevHlpPCIPhysReadUser(pDevIns, GCPhys, pvSeg, cbSeg);
[64224]1970 GCPhys += cbSeg;
1971 cbCopy -= cbSeg;
1972 }
1973}
1974
1975/**
1976 * Copy from host to guest memory worker.
1977 *
[85121]1978 * @copydoc FNLSILOGICR3MEMCOPYCALLBACK
[64224]1979 */
[81781]1980static DECLCALLBACK(void) lsilogicR3CopyBufferToGuestWorker(PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
1981 PRTSGBUF pSgBuf, size_t cbCopy, size_t *pcbSkip)
[64224]1982{
1983 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
1984 cbCopy -= cbSkipped;
1985 GCPhys += cbSkipped;
1986 *pcbSkip -= cbSkipped;
1987
1988 while (cbCopy)
1989 {
1990 size_t cbSeg = cbCopy;
1991 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
1992
1993 AssertPtr(pvSeg);
[84504]1994 PDMDevHlpPCIPhysWriteUser(pDevIns, GCPhys, pvSeg, cbSeg);
[64224]1995 GCPhys += cbSeg;
1996 cbCopy -= cbSeg;
1997 }
1998}
1999
2000/**
[45970]2001 * Walks the guest S/G buffer calling the given copy worker for every buffer.
2002 *
[64224]2003 * @returns The amout of bytes actually copied.
[81781]2004 * @param pDevIns The device instance.
2005 * @param pLsiReq LSI request state.
2006 * @param pfnCopyWorker The copy method to apply for each guest buffer.
2007 * @param pSgBuf The host S/G buffer.
2008 * @param cbSkip How many bytes to skip in advance before starting to
2009 * copy.
2010 * @param cbCopy How many bytes to copy.
[45970]2011 */
[81781]2012static size_t lsilogicSgBufWalker(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq,
[85121]2013 PFNLSILOGICR3MEMCOPYCALLBACK pfnCopyWorker,
[64224]2014 PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
[21321]2015{
[45959]2016 bool fEndOfList = false;
2017 RTGCPHYS GCPhysSgEntryNext = pLsiReq->GCPhysSgStart;
2018 RTGCPHYS GCPhysSegmentStart = pLsiReq->GCPhysSgStart;
2019 uint32_t cChainOffsetNext = pLsiReq->cChainOffset;
[64224]2020 size_t cbCopied = 0;
[21321]2021
[64224]2022 /*
2023 * Add the amount to skip to the host buffer size to avoid a
2024 * few conditionals later on.
2025 */
2026 cbCopy += cbSkip;
2027
[45959]2028 /* Go through the list until we reach the end. */
2029 while ( !fEndOfList
2030 && cbCopy)
[21321]2031 {
[45959]2032 bool fEndOfSegment = false;
[21321]2033
[45959]2034 while ( !fEndOfSegment
2035 && cbCopy)
[21321]2036 {
[45959]2037 MptSGEntryUnion SGEntry;
[21321]2038
[45959]2039 Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSgEntryNext));
[21321]2040
[45959]2041 /* Read the entry. */
[86483]2042 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysSgEntryNext, &SGEntry, sizeof(MptSGEntryUnion));
[21321]2043
[44694]2044# ifdef LOG_ENABLED
[45959]2045 lsilogicDumpSGEntry(&SGEntry);
[44694]2046# endif
[21321]2047
[45959]2048 AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n"));
[21321]2049
[45959]2050 /* Check if this is a zero element and abort. */
2051 if ( !SGEntry.Simple32.u24Length
2052 && SGEntry.Simple32.fEndOfList
2053 && SGEntry.Simple32.fEndOfBuffer)
[64224]2054 return cbCopied - RT_MIN(cbSkip, cbCopied);
[21321]2055
[85102]2056 size_t cbCopyThis = RT_MIN(SGEntry.Simple32.u24Length, cbCopy);
[45959]2057 RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow;
[21321]2058
[45959]2059 if (SGEntry.Simple32.f64BitAddress)
2060 {
2061 GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32;
2062 GCPhysSgEntryNext += sizeof(MptSGEntrySimple64);
2063 }
2064 else
2065 GCPhysSgEntryNext += sizeof(MptSGEntrySimple32);
[21321]2066
[81781]2067 pfnCopyWorker(pDevIns, GCPhysAddrDataBuffer, pSgBuf, cbCopyThis, &cbSkip);
[45970]2068 cbCopy -= cbCopyThis;
[64224]2069 cbCopied += cbCopyThis;
[21321]2070
[45959]2071 /* Check if we reached the end of the list. */
2072 if (SGEntry.Simple32.fEndOfList)
[21321]2073 {
[45959]2074 /* We finished. */
2075 fEndOfSegment = true;
2076 fEndOfList = true;
2077 }
2078 else if (SGEntry.Simple32.fLastElement)
2079 fEndOfSegment = true;
2080 } /* while (!fEndOfSegment) */
[21321]2081
[45959]2082 /* Get next chain element. */
2083 if (cChainOffsetNext)
2084 {
2085 MptSGEntryChain SGEntryChain;
[21321]2086
[86483]2087 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysSegmentStart + cChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
[21321]2088
[45959]2089 AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n"));
[21321]2090
[45959]2091 /* Set the next address now. */
2092 GCPhysSgEntryNext = SGEntryChain.u32SegmentAddressLow;
2093 if (SGEntryChain.f64BitAddress)
2094 GCPhysSgEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32;
[21321]2095
[45959]2096 GCPhysSegmentStart = GCPhysSgEntryNext;
2097 cChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t);
2098 }
2099 } /* while (!fEndOfList) */
[21321]2100
[64224]2101 return cbCopied - RT_MIN(cbSkip, cbCopied);
[45959]2102}
[21321]2103
[45959]2104/**
[64224]2105 * Copies a data buffer into the S/G buffer set up by the guest.
[45959]2106 *
[64224]2107 * @returns Amount of bytes copied to the guest.
[81781]2108 * @param pDevIns The device instance.
2109 * @param pReq Request structure.
2110 * @param pSgBuf The S/G buffer to copy from.
2111 * @param cbSkip How many bytes to skip in advance before starting to copy.
2112 * @param cbCopy How many bytes to copy.
[45959]2113 */
[81781]2114static size_t lsilogicR3CopySgBufToGuest(PPDMDEVINS pDevIns, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
[64224]2115 size_t cbSkip, size_t cbCopy)
[45959]2116{
[81781]2117 return lsilogicSgBufWalker(pDevIns, pReq, lsilogicR3CopyBufferToGuestWorker, pSgBuf, cbSkip, cbCopy);
[45959]2118}
[21321]2119
[45959]2120/**
[64224]2121 * Copies the guest S/G buffer into a host data buffer.
[45959]2122 *
[64224]2123 * @returns Amount of bytes copied from the guest.
[81781]2124 * @param pDevIns The device instance.
2125 * @param pReq Request structure.
2126 * @param pSgBuf The S/G buffer to copy into.
2127 * @param cbSkip How many bytes to skip in advance before starting to copy.
2128 * @param cbCopy How many bytes to copy.
[45959]2129 */
[81781]2130static size_t lsilogicR3CopySgBufFromGuest(PPDMDEVINS pDevIns, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
[64224]2131 size_t cbSkip, size_t cbCopy)
[45959]2132{
[81781]2133 return lsilogicSgBufWalker(pDevIns, pReq, lsilogicR3CopyBufferFromGuestWorker, pSgBuf, cbSkip, cbCopy);
[45959]2134}
2135
[64224]2136#if 0 /* unused */
[45959]2137/**
[64224]2138 * Copy a simple memory buffer to the guest memory buffer.
[45959]2139 *
[64224]2140 * @returns Amount of bytes copied to the guest.
2141 * @param pThis The LsiLogic controller device instance.
2142 * @param pReq Request structure.
2143 * @param pvSrc The buffer to copy from.
2144 * @param cbSrc How many bytes to copy.
2145 * @param cbSkip How many bytes to skip initially.
[45959]2146 */
[64224]2147static size_t lsilogicR3CopyBufferToGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, const void *pvSrc,
2148 size_t cbSrc, size_t cbSkip)
[45959]2149{
[64224]2150 RTSGSEG Seg;
2151 RTSGBUF SgBuf;
2152 Seg.pvSeg = (void *)pvSrc;
2153 Seg.cbSeg = cbSrc;
2154 RTSgBufInit(&SgBuf, &Seg, 1);
2155 return lsilogicR3CopySgBufToGuest(pThis, pReq, &SgBuf, cbSkip, cbSrc);
[21321]2156}
2157
2158/**
[64224]2159 * Copy a guest memry buffe into simple host memory buffer.
[21321]2160 *
[64224]2161 * @returns Amount of bytes copied to the guest.
2162 * @param pThis The LsiLogic controller device instance.
2163 * @param pReq Request structure.
2164 * @param pvSrc The buffer to copy from.
2165 * @param cbSrc How many bytes to copy.
2166 * @param cbSkip How many bytes to skip initially.
[21321]2167 */
[64224]2168static size_t lsilogicR3CopyBufferFromGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, void *pvDst,
2169 size_t cbDst, size_t cbSkip)
[21321]2170{
[64224]2171 RTSGSEG Seg;
2172 RTSGBUF SgBuf;
2173 Seg.pvSeg = (void *)pvDst;
2174 Seg.cbSeg = cbDst;
2175 RTSgBufInit(&SgBuf, &Seg, 1);
2176 return lsilogicR3CopySgBufFromGuest(pThis, pReq, &SgBuf, cbSkip, cbDst);
[21321]2177}
[64224]2178#endif
[21321]2179
[44694]2180# ifdef LOG_ENABLED
2181static void lsilogicR3DumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest)
[21321]2182{
[44694]2183 if (LogIsEnabled())
2184 {
2185 Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID));
2186 Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus));
2187 Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset));
2188 Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function));
2189 Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength));
2190 Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength));
2191 Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags));
2192 Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext));
2193 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++)
2194 Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i]));
2195 Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control));
2196 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++)
2197 Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i]));
2198 Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength));
2199 Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
2200 }
[21321]2201}
[44694]2202# endif
[21321]2203
[64224]2204/**
2205 * Handles the completion of th given request.
2206 *
[81781]2207 * @param pDevIns The device instance.
2208 * @param pThis Pointer to the shared LsiLogic device state.
2209 * @param pReq The request to complete.
2210 * @param rcReq Status code of the request.
[64224]2211 */
[89193]2212static void lsilogicR3ReqComplete(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICREQ pReq, int rcReq)
[32983]2213{
[64224]2214 PLSILOGICDEVICE pTgtDev = pReq->pTargetDevice;
[89193]2215 RTGCPHYS GCPhysAddrSenseBuffer;
[32983]2216
[89193]2217 GCPhysAddrSenseBuffer = pReq->GuestRequest.SCSIIO.u32SenseBufferLowAddress;
2218 GCPhysAddrSenseBuffer |= ((uint64_t)pThis->u32SenseBufferHighAddr << 32);
[32983]2219
[89193]2220 /* Copy the sense buffer over. */
2221 if (pReq->GuestRequest.SCSIIO.u8SenseBufferLength > 0)
2222 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysAddrSenseBuffer, pReq->abSenseBuffer,
2223 RT_UNLIKELY( pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2224 < sizeof(pReq->abSenseBuffer))
2225 ? pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2226 : sizeof(pReq->abSenseBuffer));
[32983]2227
[89193]2228 if (RT_SUCCESS(rcReq) && RT_LIKELY(pReq->u8ScsiSts == SCSI_STATUS_OK))
2229 {
2230 uint32_t u32MsgCtx = pReq->GuestRequest.SCSIIO.u32MessageContext;
[32983]2231
[89193]2232 /* Free the request before posting completion. */
2233 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2234 lsilogicR3FinishContextReply(pDevIns, pThis, u32MsgCtx);
[32983]2235 }
[81781]2236 else
2237 {
[89193]2238 MptReplyUnion IOCReply;
2239 RT_ZERO(IOCReply);
2240
2241 /* The SCSI target encountered an error during processing post a reply. */
2242 IOCReply.SCSIIOError.u8TargetID = pReq->GuestRequest.SCSIIO.u8TargetID;
2243 IOCReply.SCSIIOError.u8Bus = pReq->GuestRequest.SCSIIO.u8Bus;
2244 IOCReply.SCSIIOError.u8MessageLength = 8;
2245 IOCReply.SCSIIOError.u8Function = pReq->GuestRequest.SCSIIO.u8Function;
2246 IOCReply.SCSIIOError.u8CDBLength = pReq->GuestRequest.SCSIIO.u8CDBLength;
2247 IOCReply.SCSIIOError.u8SenseBufferLength = pReq->GuestRequest.SCSIIO.u8SenseBufferLength;
2248 IOCReply.SCSIIOError.u8MessageFlags = pReq->GuestRequest.SCSIIO.u8MessageFlags;
2249 IOCReply.SCSIIOError.u32MessageContext = pReq->GuestRequest.SCSIIO.u32MessageContext;
2250 IOCReply.SCSIIOError.u8SCSIStatus = pReq->u8ScsiSts;
2251 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID;
2252 IOCReply.SCSIIOError.u16IOCStatus = 0;
2253 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2254 IOCReply.SCSIIOError.u32TransferCount = 0;
2255 IOCReply.SCSIIOError.u32SenseCount = sizeof(pReq->abSenseBuffer);
2256 IOCReply.SCSIIOError.u32ResponseInfo = 0;
2257
2258 /* Free the request before posting completion. */
[81781]2259 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
[89193]2260 lsilogicFinishAddressReply(pDevIns, pThis, &IOCReply, false);
[81781]2261 }
[64224]2262
2263 ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
2264
2265 if (pTgtDev->cOutstandingRequests == 0 && pThis->fSignalIdle)
[81781]2266 PDMDevHlpAsyncNotificationCompleted(pDevIns);
[32983]2267}
2268
[21321]2269/**
2270 * Processes a SCSI I/O request by setting up the request
2271 * and sending it to the underlying SCSI driver.
2272 * Steps needed to complete request are done in the
2273 * callback called by the driver below upon completion of
2274 * the request.
2275 *
2276 * @returns VBox status code.
[81781]2277 * @param pDevIns The device instance.
2278 * @param pThis Pointer to the shared LsiLogic device state.
2279 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
2280 * @param GCPhysMessageFrameAddr Guest physical address where the request is located.
2281 * @param pGuestReq The request read fro th guest memory.
[21321]2282 */
[81781]2283static int lsilogicR3ProcessSCSIIORequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
2284 RTGCPHYS GCPhysMessageFrameAddr, PMptRequestUnion pGuestReq)
[21321]2285{
[64224]2286 MptReplyUnion IOCReply;
[21321]2287 int rc = VINF_SUCCESS;
2288
[44694]2289# ifdef LOG_ENABLED
[64224]2290 lsilogicR3DumpSCSIIORequest(&pGuestReq->SCSIIO);
[44694]2291# endif
[21321]2292
[64224]2293 if (RT_LIKELY( (pGuestReq->SCSIIO.u8TargetID < pThis->cDeviceStates)
2294 && (pGuestReq->SCSIIO.u8Bus == 0)))
[21321]2295 {
[81781]2296 PLSILOGICDEVICE pTgtDev = &pThisCC->paDeviceStates[pGuestReq->SCSIIO.u8TargetID];
[21321]2297
[104170]2298 if ( pTgtDev->pDrvBase
2299 && pGuestReq->SCSIIO.u8CDBLength <= RT_ELEMENTS(pGuestReq->SCSIIO.au8CDB))
[21321]2300 {
[64224]2301 /* Allocate and prepare a new request. */
2302 PDMMEDIAEXIOREQ hIoReq;
2303 PLSILOGICREQ pLsiReq = NULL;
2304 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pLsiReq,
2305 pGuestReq->SCSIIO.u32MessageContext,
2306 PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
2307 if (RT_SUCCESS(rc))
[45789]2308 {
[64224]2309 pLsiReq->hIoReq = hIoReq;
2310 pLsiReq->pTargetDevice = pTgtDev;
2311 pLsiReq->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr;
2312 pLsiReq->GCPhysSgStart = GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest);
2313 pLsiReq->cChainOffset = pGuestReq->SCSIIO.u8ChainOffset;
2314 if (pLsiReq->cChainOffset)
2315 pLsiReq->cChainOffset = pLsiReq->cChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest);
2316 memcpy(&pLsiReq->GuestRequest, pGuestReq, sizeof(MptRequestUnion));
2317 RT_BZERO(&pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer));
[30947]2318
[64224]2319 PDMMEDIAEXIOREQSCSITXDIR enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN;
2320 uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control);
[45789]2321
[67890]2322 /*
2323 * Keep the direction to unknown if there is a mismatch between the data length
2324 * and the transfer direction bit.
2325 * The Solaris 9 driver is buggy and sets it to none for INQUIRY requests.
2326 */
2327 if ( uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE
2328 && pLsiReq->GuestRequest.SCSIIO.u32DataLength == 0)
[64224]2329 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_NONE;
2330 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
2331 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE;
2332 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ)
2333 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
[21321]2334
[64224]2335 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2336 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pLsiReq->hIoReq, pLsiReq->GuestRequest.SCSIIO.au8LUN[1],
2337 &pLsiReq->GuestRequest.SCSIIO.au8CDB[0], pLsiReq->GuestRequest.SCSIIO.u8CDBLength,
[80589]2338 enmXferDir, NULL, pLsiReq->GuestRequest.SCSIIO.u32DataLength,
2339 &pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer), NULL,
2340 &pLsiReq->u8ScsiSts, 30 * RT_MS_1SEC);
[64224]2341 if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
[89193]2342 lsilogicR3ReqComplete(pDevIns, pThis, pLsiReq, rc);
[21321]2343
[64224]2344 return VINF_SUCCESS;
[45959]2345 }
2346 else
[64224]2347 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
[21321]2348 }
2349 else
2350 {
2351 /* Device is not present report SCSI selection timeout. */
[64224]2352 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
[21321]2353 }
2354 }
2355 else
2356 {
2357 /* Report out of bounds target ID or bus. */
[64224]2358 if (pGuestReq->SCSIIO.u8Bus != 0)
2359 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS;
[21321]2360 else
[64224]2361 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID;
[21321]2362 }
2363
[30947]2364 static int g_cLogged = 0;
2365
2366 if (g_cLogged++ < MAX_REL_LOG_ERRORS)
2367 {
[104170]2368 LogRel(("LsiLogic#%d: %d/%d/%d (Bus/Target/CDBLength) doesn't exist\n", pDevIns->iInstance,
2369 pGuestReq->SCSIIO.u8TargetID, pGuestReq->SCSIIO.u8Bus, pGuestReq->SCSIIO.u8CDBLength));
[30947]2370 /* Log the CDB too */
2371 LogRel(("LsiLogic#%d: Guest issued CDB {%#x",
[81781]2372 pDevIns->iInstance, pGuestReq->SCSIIO.au8CDB[0]));
[104170]2373 for (unsigned i = 1; i < RT_MIN(pGuestReq->SCSIIO.u8CDBLength, RT_ELEMENTS(pGuestReq->SCSIIO.au8CDB)); i++)
[64224]2374 LogRel((", %#x", pGuestReq->SCSIIO.au8CDB[i]));
[30947]2375 LogRel(("}\n"));
2376 }
2377
[21321]2378 /* The rest is equal to both errors. */
[64224]2379 IOCReply.SCSIIOError.u8TargetID = pGuestReq->SCSIIO.u8TargetID;
2380 IOCReply.SCSIIOError.u8Bus = pGuestReq->SCSIIO.u8Bus;
2381 IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4;
2382 IOCReply.SCSIIOError.u8Function = pGuestReq->SCSIIO.u8Function;
2383 IOCReply.SCSIIOError.u8CDBLength = pGuestReq->SCSIIO.u8CDBLength;
2384 IOCReply.SCSIIOError.u8SenseBufferLength = pGuestReq->SCSIIO.u8SenseBufferLength;
[87112]2385 IOCReply.SCSIIOError.u8Reserved = 0;
2386 IOCReply.SCSIIOError.u8MessageFlags = 0;
[64224]2387 IOCReply.SCSIIOError.u32MessageContext = pGuestReq->SCSIIO.u32MessageContext;
2388 IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK;
2389 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED;
2390 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2391 IOCReply.SCSIIOError.u32TransferCount = 0;
2392 IOCReply.SCSIIOError.u32SenseCount = 0;
2393 IOCReply.SCSIIOError.u32ResponseInfo = 0;
[21321]2394
[81781]2395 lsilogicFinishAddressReply(pDevIns, pThis, &IOCReply, false);
[21321]2396
2397 return rc;
2398}
2399
[32983]2400
[44694]2401/**
[64274]2402 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
[44694]2403 */
[64224]2404static DECLCALLBACK(int) lsilogicR3QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2405 uint32_t *piInstance, uint32_t *piLUN)
[21321]2406{
[64224]2407 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaPort);
[81781]2408 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
[21321]2409
[64224]2410 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2411 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2412 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
[21321]2413
[64224]2414 *ppcszController = pDevIns->pReg->szName;
2415 *piInstance = pDevIns->iInstance;
2416 *piLUN = pTgtDev->iLUN;
[32983]2417
[64224]2418 return VINF_SUCCESS;
2419}
[21321]2420
2421
[64224]2422/**
2423 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
2424 */
2425static DECLCALLBACK(int) lsilogicR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2426 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
2427 size_t cbCopy)
2428{
2429 RT_NOREF1(hIoReq);
2430 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
[81781]2431 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2432 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
[21321]2433
[89193]2434 size_t cbCopied = lsilogicR3CopySgBufToGuest(pDevIns, pReq, pSgBuf, offDst, cbCopy);
[64224]2435 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
2436}
[21321]2437
[64224]2438/**
2439 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
2440 */
2441static DECLCALLBACK(int) lsilogicR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2442 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
2443 size_t cbCopy)
2444{
2445 RT_NOREF1(hIoReq);
2446 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
[81781]2447 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2448 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
[45959]2449
[89193]2450 size_t cbCopied = lsilogicR3CopySgBufFromGuest(pDevIns, pReq, pSgBuf, offSrc, cbCopy);
[64224]2451 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
2452}
[21321]2453
[64224]2454/**
2455 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
2456 */
2457static DECLCALLBACK(int) lsilogicR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2458 void *pvIoReqAlloc, int rcReq)
2459{
2460 RT_NOREF(hIoReq);
2461 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
[81781]2462 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2463 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[89193]2464 lsilogicR3ReqComplete(pDevIns, pThis, (PLSILOGICREQ)pvIoReqAlloc, rcReq);
[21321]2465 return VINF_SUCCESS;
2466}
2467
[44694]2468/**
[64224]2469 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
[44694]2470 */
[64224]2471static DECLCALLBACK(void) lsilogicR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2472 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
[34433]2473{
[64224]2474 RT_NOREF3(hIoReq, pvIoReqAlloc, enmState);
2475 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
[34433]2476
[64224]2477 switch (enmState)
2478 {
2479 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
2480 {
2481 /* Make sure the request is not accounted for so the VM can suspend successfully. */
[81781]2482 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2483 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[64224]2484 uint32_t cTasksActive = ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
[81781]2485 if (!cTasksActive && pThis->fSignalIdle)
2486 PDMDevHlpAsyncNotificationCompleted(pDevIns);
[64224]2487 break;
2488 }
2489 case PDMMEDIAEXIOREQSTATE_ACTIVE:
2490 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
2491 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2492 break;
2493 default:
2494 AssertMsgFailed(("Invalid request state given %u\n", enmState));
2495 }
2496}
[34433]2497
[64224]2498/**
2499 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
2500 */
2501static DECLCALLBACK(void) lsilogicR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
2502{
2503 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
[81781]2504 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2505 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[34433]2506
[81781]2507 if (pThisCC->pMediaNotify)
[64409]2508 {
[91920]2509 int rc = PDMDevHlpVMReqCallNoWait(pDevIns, VMCPUID_ANY,
2510 (PFNRT)pThisCC->pMediaNotify->pfnEjected, 2,
2511 pThisCC->pMediaNotify, pTgtDev->iLUN);
[64409]2512 AssertRC(rc);
2513 }
[34433]2514}
2515
[64224]2516
[21321]2517/**
2518 * Return the configuration page header and data
2519 * which matches the given page type and number.
2520 *
2521 * @returns VINF_SUCCESS if successful
2522 * VERR_NOT_FOUND if the requested page could be found.
[81781]2523 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2524 * @param pPages The pages supported by the controller.
[21321]2525 * @param u8PageNumber Number of the page to get.
2526 * @param ppPageHeader Where to store the pointer to the page header.
2527 * @param ppbPageData Where to store the pointer to the page data.
[64274]2528 * @param pcbPage Where to store the size of the page data in bytes on success.
[21321]2529 */
[44694]2530static int lsilogicR3ConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pThis,
2531 PMptConfigurationPagesSupported pPages,
2532 uint8_t u8PageNumber,
2533 PMptConfigurationPageHeader *ppPageHeader,
2534 uint8_t **ppbPageData, size_t *pcbPage)
[21321]2535{
[62964]2536 RT_NOREF(pThis);
[21321]2537 int rc = VINF_SUCCESS;
2538
[44694]2539 AssertPtr(ppPageHeader); Assert(ppbPageData);
[21321]2540
[44694]2541 switch (u8PageNumber)
[21321]2542 {
2543 case 0:
[25587]2544 *ppPageHeader = &pPages->IOUnitPage0.u.fields.Header;
2545 *ppbPageData = pPages->IOUnitPage0.u.abPageData;
2546 *pcbPage = sizeof(pPages->IOUnitPage0);
[21321]2547 break;
2548 case 1:
[25587]2549 *ppPageHeader = &pPages->IOUnitPage1.u.fields.Header;
2550 *ppbPageData = pPages->IOUnitPage1.u.abPageData;
2551 *pcbPage = sizeof(pPages->IOUnitPage1);
[21321]2552 break;
2553 case 2:
[25587]2554 *ppPageHeader = &pPages->IOUnitPage2.u.fields.Header;
2555 *ppbPageData = pPages->IOUnitPage2.u.abPageData;
2556 *pcbPage = sizeof(pPages->IOUnitPage2);
[21321]2557 break;
2558 case 3:
[25587]2559 *ppPageHeader = &pPages->IOUnitPage3.u.fields.Header;
2560 *ppbPageData = pPages->IOUnitPage3.u.abPageData;
2561 *pcbPage = sizeof(pPages->IOUnitPage3);
[21321]2562 break;
[25587]2563 case 4:
2564 *ppPageHeader = &pPages->IOUnitPage4.u.fields.Header;
2565 *ppbPageData = pPages->IOUnitPage4.u.abPageData;
2566 *pcbPage = sizeof(pPages->IOUnitPage4);
2567 break;
[21321]2568 default:
2569 rc = VERR_NOT_FOUND;
2570 }
2571
2572 return rc;
2573}
2574
2575/**
2576 * Return the configuration page header and data
2577 * which matches the given page type and number.
2578 *
2579 * @returns VINF_SUCCESS if successful
2580 * VERR_NOT_FOUND if the requested page could be found.
[81781]2581 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2582 * @param pPages The pages supported by the controller.
[21321]2583 * @param u8PageNumber Number of the page to get.
2584 * @param ppPageHeader Where to store the pointer to the page header.
2585 * @param ppbPageData Where to store the pointer to the page data.
[64274]2586 * @param pcbPage Where to store the size of the page data in bytes on success.
[21321]2587 */
[44694]2588static int lsilogicR3ConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pThis,
2589 PMptConfigurationPagesSupported pPages,
2590 uint8_t u8PageNumber,
2591 PMptConfigurationPageHeader *ppPageHeader,
2592 uint8_t **ppbPageData, size_t *pcbPage)
[21321]2593{
[62964]2594 RT_NOREF(pThis);
[21321]2595 int rc = VINF_SUCCESS;
2596
[44694]2597 AssertPtr(ppPageHeader); Assert(ppbPageData);
[21321]2598
[44694]2599 switch (u8PageNumber)
[21321]2600 {
2601 case 0:
[25587]2602 *ppPageHeader = &pPages->IOCPage0.u.fields.Header;
2603 *ppbPageData = pPages->IOCPage0.u.abPageData;
2604 *pcbPage = sizeof(pPages->IOCPage0);
[21321]2605 break;
2606 case 1:
[25587]2607 *ppPageHeader = &pPages->IOCPage1.u.fields.Header;
2608 *ppbPageData = pPages->IOCPage1.u.abPageData;
2609 *pcbPage = sizeof(pPages->IOCPage1);
[21321]2610 break;
2611 case 2:
[25587]2612 *ppPageHeader = &pPages->IOCPage2.u.fields.Header;
2613 *ppbPageData = pPages->IOCPage2.u.abPageData;
2614 *pcbPage = sizeof(pPages->IOCPage2);
[21321]2615 break;
2616 case 3:
[25587]2617 *ppPageHeader = &pPages->IOCPage3.u.fields.Header;
2618 *ppbPageData = pPages->IOCPage3.u.abPageData;
2619 *pcbPage = sizeof(pPages->IOCPage3);
[21321]2620 break;
2621 case 4:
[25587]2622 *ppPageHeader = &pPages->IOCPage4.u.fields.Header;
2623 *ppbPageData = pPages->IOCPage4.u.abPageData;
2624 *pcbPage = sizeof(pPages->IOCPage4);
[21321]2625 break;
2626 case 6:
[25587]2627 *ppPageHeader = &pPages->IOCPage6.u.fields.Header;
2628 *ppbPageData = pPages->IOCPage6.u.abPageData;
2629 *pcbPage = sizeof(pPages->IOCPage6);
[21321]2630 break;
2631 default:
2632 rc = VERR_NOT_FOUND;
2633 }
2634
2635 return rc;
2636}
2637
2638/**
2639 * Return the configuration page header and data
2640 * which matches the given page type and number.
2641 *
2642 * @returns VINF_SUCCESS if successful
2643 * VERR_NOT_FOUND if the requested page could be found.
[81781]2644 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2645 * @param pPages The pages supported by the controller.
[21321]2646 * @param u8PageNumber Number of the page to get.
2647 * @param ppPageHeader Where to store the pointer to the page header.
2648 * @param ppbPageData Where to store the pointer to the page data.
[64274]2649 * @param pcbPage Where to store the size of the page data in bytes on success.
[21321]2650 */
[44694]2651static int lsilogicR3ConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pThis,
2652 PMptConfigurationPagesSupported pPages,
2653 uint8_t u8PageNumber,
2654 PMptConfigurationPageHeader *ppPageHeader,
2655 uint8_t **ppbPageData, size_t *pcbPage)
[21321]2656{
2657 int rc = VINF_SUCCESS;
2658
[44694]2659 AssertPtr(ppPageHeader); Assert(ppbPageData);
[21321]2660
[44694]2661 switch (u8PageNumber)
[21321]2662 {
2663 case 0:
[25587]2664 *ppPageHeader = &pPages->ManufacturingPage0.u.fields.Header;
2665 *ppbPageData = pPages->ManufacturingPage0.u.abPageData;
2666 *pcbPage = sizeof(pPages->ManufacturingPage0);
[21321]2667 break;
2668 case 1:
[25675]2669 *ppPageHeader = &pPages->ManufacturingPage1.u.fields.Header;
2670 *ppbPageData = pPages->ManufacturingPage1.u.abPageData;
[25587]2671 *pcbPage = sizeof(pPages->ManufacturingPage1);
[21321]2672 break;
2673 case 2:
[25587]2674 *ppPageHeader = &pPages->ManufacturingPage2.u.fields.Header;
2675 *ppbPageData = pPages->ManufacturingPage2.u.abPageData;
2676 *pcbPage = sizeof(pPages->ManufacturingPage2);
[21321]2677 break;
2678 case 3:
[25587]2679 *ppPageHeader = &pPages->ManufacturingPage3.u.fields.Header;
2680 *ppbPageData = pPages->ManufacturingPage3.u.abPageData;
2681 *pcbPage = sizeof(pPages->ManufacturingPage3);
[21321]2682 break;
2683 case 4:
[25587]2684 *ppPageHeader = &pPages->ManufacturingPage4.u.fields.Header;
2685 *ppbPageData = pPages->ManufacturingPage4.u.abPageData;
2686 *pcbPage = sizeof(pPages->ManufacturingPage4);
[21321]2687 break;
[25587]2688 case 5:
2689 *ppPageHeader = &pPages->ManufacturingPage5.u.fields.Header;
2690 *ppbPageData = pPages->ManufacturingPage5.u.abPageData;
2691 *pcbPage = sizeof(pPages->ManufacturingPage5);
2692 break;
2693 case 6:
2694 *ppPageHeader = &pPages->ManufacturingPage6.u.fields.Header;
2695 *ppbPageData = pPages->ManufacturingPage6.u.abPageData;
2696 *pcbPage = sizeof(pPages->ManufacturingPage6);
2697 break;
2698 case 7:
[44694]2699 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25697]2700 {
2701 *ppPageHeader = &pPages->u.SasPages.pManufacturingPage7->u.fields.Header;
2702 *ppbPageData = pPages->u.SasPages.pManufacturingPage7->u.abPageData;
2703 *pcbPage = pPages->u.SasPages.cbManufacturingPage7;
2704 }
2705 else
2706 rc = VERR_NOT_FOUND;
[25587]2707 break;
2708 case 8:
2709 *ppPageHeader = &pPages->ManufacturingPage8.u.fields.Header;
2710 *ppbPageData = pPages->ManufacturingPage8.u.abPageData;
2711 *pcbPage = sizeof(pPages->ManufacturingPage8);
2712 break;
2713 case 9:
2714 *ppPageHeader = &pPages->ManufacturingPage9.u.fields.Header;
2715 *ppbPageData = pPages->ManufacturingPage9.u.abPageData;
2716 *pcbPage = sizeof(pPages->ManufacturingPage9);
2717 break;
2718 case 10:
2719 *ppPageHeader = &pPages->ManufacturingPage10.u.fields.Header;
2720 *ppbPageData = pPages->ManufacturingPage10.u.abPageData;
2721 *pcbPage = sizeof(pPages->ManufacturingPage10);
2722 break;
[21321]2723 default:
2724 rc = VERR_NOT_FOUND;
2725 }
2726
2727 return rc;
2728}
2729
2730/**
2731 * Return the configuration page header and data
2732 * which matches the given page type and number.
2733 *
2734 * @returns VINF_SUCCESS if successful
2735 * VERR_NOT_FOUND if the requested page could be found.
[81781]2736 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2737 * @param pPages The pages supported by the controller.
[21321]2738 * @param u8PageNumber Number of the page to get.
2739 * @param ppPageHeader Where to store the pointer to the page header.
2740 * @param ppbPageData Where to store the pointer to the page data.
[64274]2741 * @param pcbPage Where to store the size of the page data in bytes on success.
[21321]2742 */
[44694]2743static int lsilogicR3ConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pThis,
2744 PMptConfigurationPagesSupported pPages,
2745 uint8_t u8PageNumber,
2746 PMptConfigurationPageHeader *ppPageHeader,
2747 uint8_t **ppbPageData, size_t *pcbPage)
[25587]2748{
[62964]2749 RT_NOREF(pThis);
[25587]2750 int rc = VINF_SUCCESS;
2751
[44694]2752 AssertPtr(ppPageHeader); Assert(ppbPageData);
[25587]2753
[44694]2754 switch (u8PageNumber)
[25587]2755 {
2756 case 1:
2757 *ppPageHeader = &pPages->BIOSPage1.u.fields.Header;
2758 *ppbPageData = pPages->BIOSPage1.u.abPageData;
2759 *pcbPage = sizeof(pPages->BIOSPage1);
2760 break;
2761 case 2:
2762 *ppPageHeader = &pPages->BIOSPage2.u.fields.Header;
2763 *ppbPageData = pPages->BIOSPage2.u.abPageData;
2764 *pcbPage = sizeof(pPages->BIOSPage2);
2765 break;
2766 case 4:
2767 *ppPageHeader = &pPages->BIOSPage4.u.fields.Header;
2768 *ppbPageData = pPages->BIOSPage4.u.abPageData;
2769 *pcbPage = sizeof(pPages->BIOSPage4);
2770 break;
2771 default:
2772 rc = VERR_NOT_FOUND;
2773 }
2774
2775 return rc;
2776}
2777
2778/**
2779 * Return the configuration page header and data
2780 * which matches the given page type and number.
2781 *
2782 * @returns VINF_SUCCESS if successful
2783 * VERR_NOT_FOUND if the requested page could be found.
[81781]2784 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2785 * @param pPages The pages supported by the controller.
2786 * @param u8Port The port to retrieve the page for.
[25587]2787 * @param u8PageNumber Number of the page to get.
2788 * @param ppPageHeader Where to store the pointer to the page header.
2789 * @param ppbPageData Where to store the pointer to the page data.
[64274]2790 * @param pcbPage Where to store the size of the page data in bytes on success.
[25587]2791 */
[44694]2792static int lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pThis,
2793 PMptConfigurationPagesSupported pPages,
2794 uint8_t u8Port,
2795 uint8_t u8PageNumber,
2796 PMptConfigurationPageHeader *ppPageHeader,
2797 uint8_t **ppbPageData, size_t *pcbPage)
[21321]2798{
[62964]2799 RT_NOREF(pThis);
[21321]2800 int rc = VINF_SUCCESS;
[44694]2801 AssertPtr(ppPageHeader); Assert(ppbPageData);
[21321]2802
2803
[25587]2804 if (u8Port >= RT_ELEMENTS(pPages->u.SpiPages.aPortPages))
[21321]2805 return VERR_NOT_FOUND;
2806
[44694]2807 switch (u8PageNumber)
[21321]2808 {
2809 case 0:
[25587]2810 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.fields.Header;
2811 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.abPageData;
2812 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0);
[21321]2813 break;
2814 case 1:
[25587]2815 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.fields.Header;
2816 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.abPageData;
2817 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1);
[21321]2818 break;
2819 case 2:
[25587]2820 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.fields.Header;
2821 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.abPageData;
2822 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2);
[21321]2823 break;
2824 default:
2825 rc = VERR_NOT_FOUND;
2826 }
2827
2828 return rc;
2829}
2830
2831/**
2832 * Return the configuration page header and data
2833 * which matches the given page type and number.
2834 *
2835 * @returns VINF_SUCCESS if successful
2836 * VERR_NOT_FOUND if the requested page could be found.
[81781]2837 * @param pThis Pointer to the shared LsiLogic device state. data.
[64274]2838 * @param pPages The pages supported by the controller.
2839 * @param u8Bus The bus the device is on the page should be returned.
2840 * @param u8TargetID The target ID of the device to return the page for.
[21321]2841 * @param u8PageNumber Number of the page to get.
2842 * @param ppPageHeader Where to store the pointer to the page header.
2843 * @param ppbPageData Where to store the pointer to the page data.
[64274]2844 * @param pcbPage Where to store the size of the page data in bytes on success.
[21321]2845 */
[44694]2846static int lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pThis,
2847 PMptConfigurationPagesSupported pPages,
2848 uint8_t u8Bus,
2849 uint8_t u8TargetID, uint8_t u8PageNumber,
2850 PMptConfigurationPageHeader *ppPageHeader,
2851 uint8_t **ppbPageData, size_t *pcbPage)
[21321]2852{
[62964]2853 RT_NOREF(pThis);
[21321]2854 int rc = VINF_SUCCESS;
[44694]2855 AssertPtr(ppPageHeader); Assert(ppbPageData);
[21321]2856
[25587]2857 if (u8Bus >= RT_ELEMENTS(pPages->u.SpiPages.aBuses))
[21321]2858 return VERR_NOT_FOUND;
2859
[25587]2860 if (u8TargetID >= RT_ELEMENTS(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages))
[21321]2861 return VERR_NOT_FOUND;
2862
[44694]2863 switch (u8PageNumber)
[21321]2864 {
2865 case 0:
[25587]2866 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
2867 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
2868 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0);
[21321]2869 break;
2870 case 1:
[25587]2871 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
2872 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
2873 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1);
[21321]2874 break;
2875 case 2:
[25587]2876 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
2877 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
2878 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2);
[21321]2879 break;
2880 case 3:
[25587]2881 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
2882 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
2883 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3);
[21321]2884 break;
2885 default:
2886 rc = VERR_NOT_FOUND;
2887 }
2888
2889 return rc;
2890}
2891
[81781]2892static int lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(PMptConfigurationPagesSupported pPages,
[44694]2893 uint8_t u8PageNumber,
2894 PMptExtendedConfigurationPageHeader *ppPageHeader,
2895 uint8_t **ppbPageData, size_t *pcbPage)
[25587]2896{
2897 int rc = VINF_SUCCESS;
2898
[44694]2899 switch (u8PageNumber)
[25587]2900 {
2901 case 0:
[25675]2902 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage0->u.fields.ExtHeader;
2903 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage0->u.abPageData;
2904 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage0;
[25587]2905 break;
2906 case 1:
[25675]2907 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage1->u.fields.ExtHeader;
2908 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage1->u.abPageData;
2909 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage1;
[25587]2910 break;
2911 case 2:
2912 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage2.u.fields.ExtHeader;
2913 *ppbPageData = pPages->u.SasPages.SASIOUnitPage2.u.abPageData;
2914 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage2);
2915 break;
2916 case 3:
2917 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage3.u.fields.ExtHeader;
2918 *ppbPageData = pPages->u.SasPages.SASIOUnitPage3.u.abPageData;
2919 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage3);
2920 break;
2921 default:
2922 rc = VERR_NOT_FOUND;
2923 }
2924
2925 return rc;
2926}
2927
[81781]2928static int lsilogicR3ConfigurationSASPHYPageGetFromNumber(PMptConfigurationPagesSupported pPages,
[44694]2929 uint8_t u8PageNumber,
2930 MptConfigurationPageAddress PageAddress,
2931 PMptExtendedConfigurationPageHeader *ppPageHeader,
2932 uint8_t **ppbPageData, size_t *pcbPage)
[25587]2933{
2934 int rc = VINF_SUCCESS;
2935 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2936 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
[25675]2937 PMptPHY pPHYPages = NULL;
[25587]2938
2939 Log(("Address form %d\n", uAddressForm));
2940
2941 if (uAddressForm == 0) /* PHY number */
2942 {
2943 uint8_t u8PhyNumber = PageAddress.SASPHY.Form0.u8PhyNumber;
2944
2945 Log(("PHY number %d\n", u8PhyNumber));
2946
[25675]2947 if (u8PhyNumber >= pPagesSas->cPHYs)
[25587]2948 return VERR_NOT_FOUND;
2949
[25675]2950 pPHYPages = &pPagesSas->paPHYs[u8PhyNumber];
[25587]2951 }
2952 else if (uAddressForm == 1) /* Index form */
2953 {
2954 uint16_t u16Index = PageAddress.SASPHY.Form1.u16Index;
2955
2956 Log(("PHY index %d\n", u16Index));
2957
[25675]2958 if (u16Index >= pPagesSas->cPHYs)
[25587]2959 return VERR_NOT_FOUND;
2960
[25675]2961 pPHYPages = &pPagesSas->paPHYs[u16Index];
2962 }
2963 else
2964 rc = VERR_NOT_FOUND; /* Correct? */
2965
2966 if (pPHYPages)
2967 {
[44694]2968 switch (u8PageNumber)
[25587]2969 {
2970 case 0:
[25675]2971 *ppPageHeader = &pPHYPages->SASPHYPage0.u.fields.ExtHeader;
2972 *ppbPageData = pPHYPages->SASPHYPage0.u.abPageData;
2973 *pcbPage = sizeof(pPHYPages->SASPHYPage0);
[25587]2974 break;
2975 case 1:
[25675]2976 *ppPageHeader = &pPHYPages->SASPHYPage1.u.fields.ExtHeader;
2977 *ppbPageData = pPHYPages->SASPHYPage1.u.abPageData;
2978 *pcbPage = sizeof(pPHYPages->SASPHYPage1);
[25587]2979 break;
2980 default:
2981 rc = VERR_NOT_FOUND;
2982 }
2983 }
2984 else
[25675]2985 rc = VERR_NOT_FOUND;
[25587]2986
2987 return rc;
2988}
2989
[81781]2990static int lsilogicR3ConfigurationSASDevicePageGetFromNumber(PMptConfigurationPagesSupported pPages,
[44694]2991 uint8_t u8PageNumber,
2992 MptConfigurationPageAddress PageAddress,
2993 PMptExtendedConfigurationPageHeader *ppPageHeader,
2994 uint8_t **ppbPageData, size_t *pcbPage)
[25587]2995{
2996 int rc = VINF_SUCCESS;
2997 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2998 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
2999 PMptSASDevice pSASDevice = NULL;
3000
3001 Log(("Address form %d\n", uAddressForm));
3002
3003 if (uAddressForm == 0)
3004 {
3005 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
3006
3007 Log(("Get next handle %#x\n", u16Handle));
3008
[25675]3009 pSASDevice = pPagesSas->pSASDeviceHead;
3010
[25587]3011 /* Get the first device? */
[25675]3012 if (u16Handle != 0xffff)
[25587]3013 {
[25675]3014 /* No, search for the right one. */
3015
[25587]3016 while ( pSASDevice
3017 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
3018 pSASDevice = pSASDevice->pNext;
3019
3020 if (pSASDevice)
3021 pSASDevice = pSASDevice->pNext;
3022 }
3023 }
3024 else if (uAddressForm == 1)
3025 {
3026 uint8_t u8TargetID = PageAddress.SASDevice.Form1.u8TargetID;
3027 uint8_t u8Bus = PageAddress.SASDevice.Form1.u8Bus;
3028
3029 Log(("u8TargetID=%d u8Bus=%d\n", u8TargetID, u8Bus));
3030
3031 pSASDevice = pPagesSas->pSASDeviceHead;
3032
3033 while ( pSASDevice
3034 && ( pSASDevice->SASDevicePage0.u.fields.u8TargetID != u8TargetID
3035 || pSASDevice->SASDevicePage0.u.fields.u8Bus != u8Bus))
3036 pSASDevice = pSASDevice->pNext;
3037 }
3038 else if (uAddressForm == 2)
3039 {
3040 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
3041
3042 Log(("Handle %#x\n", u16Handle));
3043
3044 pSASDevice = pPagesSas->pSASDeviceHead;
3045
3046 while ( pSASDevice
3047 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
3048 pSASDevice = pSASDevice->pNext;
3049 }
3050
3051 if (pSASDevice)
3052 {
[44694]3053 switch (u8PageNumber)
[25587]3054 {
3055 case 0:
3056 *ppPageHeader = &pSASDevice->SASDevicePage0.u.fields.ExtHeader;
3057 *ppbPageData = pSASDevice->SASDevicePage0.u.abPageData;
3058 *pcbPage = sizeof(pSASDevice->SASDevicePage0);
3059 break;
3060 case 1:
3061 *ppPageHeader = &pSASDevice->SASDevicePage1.u.fields.ExtHeader;
3062 *ppbPageData = pSASDevice->SASDevicePage1.u.abPageData;
3063 *pcbPage = sizeof(pSASDevice->SASDevicePage1);
3064 break;
3065 case 2:
3066 *ppPageHeader = &pSASDevice->SASDevicePage2.u.fields.ExtHeader;
3067 *ppbPageData = pSASDevice->SASDevicePage2.u.abPageData;
3068 *pcbPage = sizeof(pSASDevice->SASDevicePage2);
3069 break;
3070 default:
3071 rc = VERR_NOT_FOUND;
3072 }
3073 }
3074 else
3075 rc = VERR_NOT_FOUND;
3076
3077 return rc;
3078}
3079
[21321]3080/**
[25587]3081 * Returns the extended configuration page header and data.
3082 * @returns VINF_SUCCESS if successful
3083 * VERR_NOT_FOUND if the requested page could be found.
[81781]3084 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[25587]3085 * @param pConfigurationReq The configuration request.
[64274]3086 * @param ppPageHeader Where to return the pointer to the page header on success.
[25587]3087 * @param ppbPageData Where to store the pointer to the page data.
[64274]3088 * @param pcbPage Where to store the size of the page in bytes.
[25587]3089 */
[81781]3090static int lsilogicR3ConfigurationPageGetExtended(PLSILOGICSCSICC pThisCC, PMptConfigurationRequest pConfigurationReq,
[44694]3091 PMptExtendedConfigurationPageHeader *ppPageHeader,
3092 uint8_t **ppbPageData, size_t *pcbPage)
[25587]3093{
3094 int rc = VINF_SUCCESS;
3095
3096 Log(("Extended page requested:\n"));
3097 Log(("u8ExtPageType=%#x\n", pConfigurationReq->u8ExtPageType));
3098 Log(("u8ExtPageLength=%d\n", pConfigurationReq->u16ExtPageLength));
3099
3100 switch (pConfigurationReq->u8ExtPageType)
3101 {
3102 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT:
3103 {
[81781]3104 rc = lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(pThisCC->pConfigurationPages,
3105 pConfigurationReq->u8PageNumber,
3106 ppPageHeader, ppbPageData, pcbPage);
[25587]3107 break;
3108 }
3109 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS:
3110 {
[81781]3111 rc = lsilogicR3ConfigurationSASPHYPageGetFromNumber(pThisCC->pConfigurationPages,
3112 pConfigurationReq->u8PageNumber,
3113 pConfigurationReq->PageAddress,
3114 ppPageHeader, ppbPageData, pcbPage);
[25587]3115 break;
3116 }
3117 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE:
3118 {
[81781]3119 rc = lsilogicR3ConfigurationSASDevicePageGetFromNumber(pThisCC->pConfigurationPages,
3120 pConfigurationReq->u8PageNumber,
3121 pConfigurationReq->PageAddress,
3122 ppPageHeader, ppbPageData, pcbPage);
[25587]3123 break;
3124 }
3125 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASEXPANDER: /* No expanders supported */
3126 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_ENCLOSURE: /* No enclosures supported */
3127 default:
3128 rc = VERR_NOT_FOUND;
3129 }
3130
3131 return rc;
3132}
3133
3134/**
[21321]3135 * Processes a Configuration request.
3136 *
3137 * @returns VBox status code.
[81781]3138 * @param pDevIns The device instance.
3139 * @param pThis Pointer to the shared LsiLogic device state.
3140 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[44694]3141 * @param pConfigurationReq Pointer to the request structure.
3142 * @param pReply Pointer to the reply message frame
[21321]3143 */
[81781]3144static int lsilogicR3ProcessConfigurationRequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
3145 PMptConfigurationRequest pConfigurationReq, PMptConfigurationReply pReply)
[21321]3146{
[25675]3147 int rc = VINF_SUCCESS;
3148 uint8_t *pbPageData = NULL;
3149 PMptConfigurationPageHeader pPageHeader = NULL;
3150 PMptExtendedConfigurationPageHeader pExtPageHeader = NULL;
3151 uint8_t u8PageType;
3152 uint8_t u8PageAttribute;
3153 size_t cbPage = 0;
[21321]3154
[44694]3155 LogFlowFunc(("pThis=%#p\n", pThis));
[21321]3156
3157 u8PageType = MPT_CONFIGURATION_PAGE_TYPE_GET(pConfigurationReq->u8PageType);
3158 u8PageAttribute = MPT_CONFIGURATION_PAGE_ATTRIBUTE_GET(pConfigurationReq->u8PageType);
3159
[25587]3160 Log(("GuestRequest:\n"));
3161 Log(("u8Action=%#x\n", pConfigurationReq->u8Action));
3162 Log(("u8PageType=%#x\n", u8PageType));
3163 Log(("u8PageNumber=%d\n", pConfigurationReq->u8PageNumber));
3164 Log(("u8PageLength=%d\n", pConfigurationReq->u8PageLength));
3165 Log(("u8PageVersion=%d\n", pConfigurationReq->u8PageVersion));
3166
[21321]3167 /* Copy common bits from the request into the reply. */
3168 pReply->u8MessageLength = 6; /* 6 32bit D-Words. */
3169 pReply->u8Action = pConfigurationReq->u8Action;
3170 pReply->u8Function = pConfigurationReq->u8Function;
3171 pReply->u32MessageContext = pConfigurationReq->u32MessageContext;
3172
3173 switch (u8PageType)
3174 {
3175 case MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT:
3176 {
3177 /* Get the page data. */
[44694]3178 rc = lsilogicR3ConfigurationIOUnitPageGetFromNumber(pThis,
[81781]3179 pThisCC->pConfigurationPages,
3180 pConfigurationReq->u8PageNumber,
3181 &pPageHeader, &pbPageData, &cbPage);
[21321]3182 break;
3183 }
3184 case MPT_CONFIGURATION_PAGE_TYPE_IOC:
3185 {
3186 /* Get the page data. */
[44694]3187 rc = lsilogicR3ConfigurationIOCPageGetFromNumber(pThis,
[81781]3188 pThisCC->pConfigurationPages,
3189 pConfigurationReq->u8PageNumber,
3190 &pPageHeader, &pbPageData, &cbPage);
[21321]3191 break;
3192 }
3193 case MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING:
3194 {
3195 /* Get the page data. */
[44694]3196 rc = lsilogicR3ConfigurationManufacturingPageGetFromNumber(pThis,
[81781]3197 pThisCC->pConfigurationPages,
3198 pConfigurationReq->u8PageNumber,
3199 &pPageHeader, &pbPageData, &cbPage);
[21321]3200 break;
3201 }
3202 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT:
3203 {
3204 /* Get the page data. */
[44694]3205 rc = lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(pThis,
[81781]3206 pThisCC->pConfigurationPages,
3207 pConfigurationReq->PageAddress.MPIPortNumber.u8PortNumber,
3208 pConfigurationReq->u8PageNumber,
3209 &pPageHeader, &pbPageData, &cbPage);
[21321]3210 break;
3211 }
3212 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE:
3213 {
3214 /* Get the page data. */
[44694]3215 rc = lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(pThis,
[81781]3216 pThisCC->pConfigurationPages,
3217 pConfigurationReq->PageAddress.BusAndTargetId.u8Bus,
3218 pConfigurationReq->PageAddress.BusAndTargetId.u8TargetID,
3219 pConfigurationReq->u8PageNumber,
3220 &pPageHeader, &pbPageData, &cbPage);
[21321]3221 break;
3222 }
[25587]3223 case MPT_CONFIGURATION_PAGE_TYPE_BIOS:
3224 {
[44694]3225 rc = lsilogicR3ConfigurationBiosPageGetFromNumber(pThis,
[81781]3226 pThisCC->pConfigurationPages,
3227 pConfigurationReq->u8PageNumber,
3228 &pPageHeader, &pbPageData, &cbPage);
[25587]3229 break;
3230 }
3231 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED:
3232 {
[97029]3233 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3234 {
3235 rc = lsilogicR3ConfigurationPageGetExtended(pThisCC,
3236 pConfigurationReq,
3237 &pExtPageHeader, &pbPageData, &cbPage);
3238 }
3239 else
3240 rc = VERR_NOT_FOUND;
[25587]3241 break;
3242 }
[21321]3243 default:
3244 rc = VERR_NOT_FOUND;
3245 }
3246
3247 if (rc == VERR_NOT_FOUND)
3248 {
[25587]3249 Log(("Page not found\n"));
[21321]3250 pReply->u8PageType = pConfigurationReq->u8PageType;
3251 pReply->u8PageNumber = pConfigurationReq->u8PageNumber;
3252 pReply->u8PageLength = pConfigurationReq->u8PageLength;
3253 pReply->u8PageVersion = pConfigurationReq->u8PageVersion;
[25587]3254 pReply->u16IOCStatus = MPT_IOCSTATUS_CONFIG_INVALID_PAGE;
[21321]3255 return VINF_SUCCESS;
3256 }
3257
[25587]3258 if (u8PageType == MPT_CONFIGURATION_PAGE_TYPE_EXTENDED)
3259 {
3260 pReply->u8PageType = pExtPageHeader->u8PageType;
3261 pReply->u8PageNumber = pExtPageHeader->u8PageNumber;
3262 pReply->u8PageVersion = pExtPageHeader->u8PageVersion;
3263 pReply->u8ExtPageType = pExtPageHeader->u8ExtPageType;
3264 pReply->u16ExtPageLength = pExtPageHeader->u16ExtPageLength;
[21321]3265
[25587]3266 for (int i = 0; i < pExtPageHeader->u16ExtPageLength; i++)
3267 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3268 }
3269 else
3270 {
3271 pReply->u8PageType = pPageHeader->u8PageType;
3272 pReply->u8PageNumber = pPageHeader->u8PageNumber;
3273 pReply->u8PageLength = pPageHeader->u8PageLength;
3274 pReply->u8PageVersion = pPageHeader->u8PageVersion;
[21321]3275
[25587]3276 for (int i = 0; i < pReply->u8PageLength; i++)
3277 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3278 }
[21321]3279
3280 /*
3281 * Don't use the scatter gather handling code as the configuration request always have only one
3282 * simple element.
3283 */
3284 switch (pConfigurationReq->u8Action)
3285 {
3286 case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT: /* Nothing to do. We are always using the defaults. */
3287 case MPT_CONFIGURATION_REQUEST_ACTION_HEADER:
3288 {
3289 /* Already copied above nothing to do. */
3290 break;
3291 }
3292 case MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM:
3293 case MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT:
3294 case MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT:
3295 {
3296 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3297 if (cbBuffer != 0)
3298 {
3299 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3300 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3301 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3302
[84504]3303 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage));
[21321]3304 }
3305 break;
3306 }
3307 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT:
3308 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM:
3309 {
3310 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3311 if (cbBuffer != 0)
3312 {
3313 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3314 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3315 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3316
[30947]3317 LogFlow(("cbBuffer=%u cbPage=%u\n", cbBuffer, cbPage));
3318
[86483]3319 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage));
[21321]3320 }
3321 break;
3322 }
3323 default:
3324 AssertMsgFailed(("todo\n"));
3325 }
3326
3327 return VINF_SUCCESS;
3328}
3329
3330/**
[25587]3331 * Initializes the configuration pages for the SPI SCSI controller.
3332 *
[81781]3333 * @param pThis Pointer to the shared LsiLogic device state.
3334 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[25587]3335 */
[81781]3336static void lsilogicR3InitializeConfigurationPagesSpi(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
[25587]3337{
[81781]3338 PMptConfigurationPagesSpi pPages = &pThisCC->pConfigurationPages->u.SpiPages;
[25587]3339
[44694]3340 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n"));
3341 LogFlowFunc(("pThis=%#p\n", pThis));
[81783]3342 RT_NOREF(pThis);
[25587]3343
3344 /* Clear everything first. */
[44779]3345 memset(pPages, 0, sizeof(MptConfigurationPagesSpi));
[25587]3346
3347 for (unsigned i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++)
3348 {
3349 /* SCSI-SPI port page 0. */
3350 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3351 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3352 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageNumber = 0;
3353 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
3354 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fInformationUnitTransfersCapable = true;
3355 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fDTCapable = true;
3356 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fQASCapable = true;
3357 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MinimumSynchronousTransferPeriod = 0;
3358 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MaximumSynchronousOffset = 0xff;
3359 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fWide = true;
3360 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fAIPCapable = true;
3361 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u2SignalingType = 0x3; /* Single Ended. */
3362
3363 /* SCSI-SPI port page 1. */
3364 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3365 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3366 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageNumber = 1;
3367 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
3368 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u8SCSIID = 7;
3369 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u16PortResponseIDsBitmask = (1 << 7);
3370 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u32OnBusTimerValue = 0;
3371
3372 /* SCSI-SPI port page 2. */
3373 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3374 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3375 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageNumber = 2;
3376 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
3377 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u4HostSCSIID = 7;
3378 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u2InitializeHBA = 0x3;
3379 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.fTerminationDisabled = true;
3380 for (unsigned iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++)
3381 {
3382 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings[iDevice].fBootChoice = true;
3383 }
3384 /* Everything else 0 for now. */
3385 }
3386
3387 for (unsigned uBusCurr = 0; uBusCurr < RT_ELEMENTS(pPages->aBuses); uBusCurr++)
3388 {
3389 for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
3390 {
3391 /* SCSI-SPI device page 0. */
3392 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3393 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3394 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
3395 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
3396 /* Everything else 0 for now. */
3397
3398 /* SCSI-SPI device page 1. */
3399 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3400 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3401 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
3402 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
3403 /* Everything else 0 for now. */
3404
3405 /* SCSI-SPI device page 2. */
3406 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3407 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3408 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
3409 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
3410 /* Everything else 0 for now. */
3411
3412 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3413 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3414 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
3415 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
3416 /* Everything else 0 for now. */
3417 }
3418 }
3419}
3420
3421/**
3422 * Generates a handle.
3423 *
3424 * @returns the handle.
[81781]3425 * @param pThis Pointer to the shared LsiLogic device state.
[25587]3426 */
3427DECLINLINE(uint16_t) lsilogicGetHandle(PLSILOGICSCSI pThis)
3428{
3429 uint16_t u16Handle = pThis->u16NextHandle++;
3430 return u16Handle;
3431}
3432
3433/**
3434 * Generates a SAS address (WWID)
3435 *
3436 * @param pSASAddress Pointer to an unitialised SAS address.
3437 * @param iId iId which will go into the address.
3438 *
3439 * @todo Generate better SAS addresses. (Request a block from SUN probably)
3440 */
[99775]3441DECLINLINE(void) lsilogicSASAddressGenerate(PSASADDRESS pSASAddress, unsigned iId)
[25587]3442{
3443 pSASAddress->u8Address[0] = (0x5 << 5);
3444 pSASAddress->u8Address[1] = 0x01;
3445 pSASAddress->u8Address[2] = 0x02;
3446 pSASAddress->u8Address[3] = 0x03;
3447 pSASAddress->u8Address[4] = 0x04;
3448 pSASAddress->u8Address[5] = 0x05;
3449 pSASAddress->u8Address[6] = 0x06;
3450 pSASAddress->u8Address[7] = iId;
3451}
3452
3453/**
3454 * Initializes the configuration pages for the SAS SCSI controller.
3455 *
[81781]3456 * @param pThis Pointer to the shared LsiLogic device state.
3457 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[25587]3458 */
[81781]3459static void lsilogicR3InitializeConfigurationPagesSas(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
[25587]3460{
[81781]3461 PMptConfigurationPagesSas pPages = &pThisCC->pConfigurationPages->u.SasPages;
[25587]3462
3463 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS, ("Controller is not the SAS SCSI one\n"));
3464
3465 LogFlowFunc(("pThis=%#p\n", pThis));
3466
[25697]3467 /* Manufacturing Page 7 - Connector settings. */
[88530]3468 PMptConfigurationPageManufacturing7 pManufacturingPage7 = pPages->pManufacturingPage7;
[25697]3469 AssertPtr(pManufacturingPage7);
[88530]3470
[25697]3471 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pManufacturingPage7,
3472 0, 7,
3473 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3474 /* Set size manually. */
3475 if (pPages->cbManufacturingPage7 / 4 > 255)
3476 pManufacturingPage7->u.fields.Header.u8PageLength = 255;
3477 else
3478 pManufacturingPage7->u.fields.Header.u8PageLength = pPages->cbManufacturingPage7 / 4;
3479 pManufacturingPage7->u.fields.u8NumPhys = pThis->cPorts;
3480
[33540]3481 /* SAS I/O unit page 0 - Port specific information. */
[88530]3482 PMptConfigurationPageSASIOUnit0 pSASPage0 = pPages->pSASIOUnitPage0;
[25675]3483 AssertPtr(pSASPage0);
[25587]3484
[25675]3485 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage0, pPages->cbSASIOUnitPage0,
3486 0, MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY,
3487 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3488 pSASPage0->u.fields.u8NumPhys = pThis->cPorts;
3489 pPages->pSASIOUnitPage0 = pSASPage0;
3490
[25587]3491 /* SAS I/O unit page 1 - Port specific settings. */
[88530]3492 PMptConfigurationPageSASIOUnit1 pSASPage1 = pPages->pSASIOUnitPage1;
[25675]3493 AssertPtr(pSASPage1);
[25587]3494
[25675]3495 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage1, pPages->cbSASIOUnitPage1,
3496 1, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE,
3497 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3498 pSASPage1->u.fields.u8NumPhys = pSASPage0->u.fields.u8NumPhys;
3499 pSASPage1->u.fields.u16ControlFlags = 0;
3500 pSASPage1->u.fields.u16AdditionalControlFlags = 0;
3501
[33540]3502 /* SAS I/O unit page 2 - Port specific information. */
[25587]3503 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3504 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3505 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageNumber = 2;
3506 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3507 pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit2) / 4;
3508
[33540]3509 /* SAS I/O unit page 3 - Port specific information. */
[25587]3510 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3511 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3512 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageNumber = 3;
3513 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3514 pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit3) / 4;
3515
[88530]3516 Assert(pPages->cPHYs == pThis->cPorts);
[25675]3517 AssertPtr(pPages->paPHYs);
3518
[25587]3519 /* Initialize the PHY configuration */
[88530]3520 PMptSASDevice pSASDevice = pPages->pSASDeviceHead;
[25675]3521 for (unsigned i = 0; i < pThis->cPorts; i++)
[25587]3522 {
[25675]3523 PMptPHY pPHYPages = &pPages->paPHYs[i];
[25587]3524 uint16_t u16ControllerHandle = lsilogicGetHandle(pThis);
3525
[25697]3526 pManufacturingPage7->u.fields.aPHY[i].u8Location = LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO;
3527
[25675]3528 pSASPage0->u.fields.aPHY[i].u8Port = i;
3529 pSASPage0->u.fields.aPHY[i].u8PortFlags = 0;
3530 pSASPage0->u.fields.aPHY[i].u8PhyFlags = 0;
3531 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED;
3532 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3533 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16ControllerHandle;
3534 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = 0; /* No device attached. */
3535 pSASPage0->u.fields.aPHY[i].u32DiscoveryStatus = 0; /* No errors */
[25587]3536
[25675]3537 pSASPage1->u.fields.aPHY[i].u8Port = i;
3538 pSASPage1->u.fields.aPHY[i].u8PortFlags = 0;
3539 pSASPage1->u.fields.aPHY[i].u8PhyFlags = 0;
3540 pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3541 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3542 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
[25587]3543
3544 /* SAS PHY page 0. */
[25675]3545 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
[25587]3546 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
[25675]3547 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageNumber = 0;
3548 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3549 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY0) / 4;
3550 pPHYPages->SASPHYPage0.u.fields.u8AttachedPhyIdentifier = i;
3551 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
3552 pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3553 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3554 pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3555 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
[25587]3556
3557 /* SAS PHY page 1. */
[25675]3558 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3559 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3560 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageNumber = 1;
3561 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3562 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY1) / 4;
[25587]3563
3564 /* Settings for present devices. */
[81781]3565 if (pThisCC->paDeviceStates[i].pDrvBase)
[25587]3566 {
3567 uint16_t u16DeviceHandle = lsilogicGetHandle(pThis);
3568 SASADDRESS SASAddress;
3569 AssertPtr(pSASDevice);
3570
3571 memset(&SASAddress, 0, sizeof(SASADDRESS));
3572 lsilogicSASAddressGenerate(&SASAddress, i);
3573
[25675]3574 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
3575 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3576 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3577 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = u16DeviceHandle;
3578 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3579 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3580 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16DeviceHandle;
[25587]3581
[25675]3582 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
3583 pPHYPages->SASPHYPage0.u.fields.SASAddress = SASAddress;
3584 pPHYPages->SASPHYPage0.u.fields.u16OwnerDevHandle = u16DeviceHandle;
3585 pPHYPages->SASPHYPage0.u.fields.u16AttachedDevHandle = u16DeviceHandle;
[25587]3586
3587 /* SAS device page 0. */
3588 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3589 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3590 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageNumber = 0;
3591 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3592 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice0) / 4;
3593 pSASDevice->SASDevicePage0.u.fields.SASAddress = SASAddress;
3594 pSASDevice->SASDevicePage0.u.fields.u16ParentDevHandle = u16ControllerHandle;
3595 pSASDevice->SASDevicePage0.u.fields.u8PhyNum = i;
3596 pSASDevice->SASDevicePage0.u.fields.u8AccessStatus = LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS;
3597 pSASDevice->SASDevicePage0.u.fields.u16DevHandle = u16DeviceHandle;
3598 pSASDevice->SASDevicePage0.u.fields.u8TargetID = i;
3599 pSASDevice->SASDevicePage0.u.fields.u8Bus = 0;
3600 pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
3601 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3602 pSASDevice->SASDevicePage0.u.fields.u16Flags = LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT
3603 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID
3604 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT;
3605 pSASDevice->SASDevicePage0.u.fields.u8PhysicalPort = i;
3606
3607 /* SAS device page 1. */
3608 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3609 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3610 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageNumber = 1;
3611 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3612 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice1) / 4;
3613 pSASDevice->SASDevicePage1.u.fields.SASAddress = SASAddress;
3614 pSASDevice->SASDevicePage1.u.fields.u16DevHandle = u16DeviceHandle;
3615 pSASDevice->SASDevicePage1.u.fields.u8TargetID = i;
3616 pSASDevice->SASDevicePage1.u.fields.u8Bus = 0;
3617
3618 /* SAS device page 2. */
3619 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3620 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3621 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageNumber = 2;
3622 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3623 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice2) / 4;
3624 pSASDevice->SASDevicePage2.u.fields.SASAddress = SASAddress;
3625
[88530]3626 pSASDevice = pSASDevice->pNext;
[25587]3627 }
3628 }
3629}
3630
3631/**
[21321]3632 * Initializes the configuration pages.
3633 *
[81781]3634 * @param pDevIns The device instance.
3635 * @param pThis Pointer to the shared LsiLogic device state.
3636 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
[21321]3637 */
[81781]3638static void lsilogicR3InitializeConfigurationPages(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
[21321]3639{
[25587]3640 /* Initialize the common pages. */
[21321]3641
[44694]3642 LogFlowFunc(("pThis=%#p\n", pThis));
[21321]3643
[88530]3644 AssertPtrReturnVoid(pThisCC->pConfigurationPages);
3645 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
[21321]3646
3647 /* Manufacturing Page 0. */
[25675]3648 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage0,
3649 MptConfigurationPageManufacturing0, 0,
3650 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3651 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipName, "VBox MPT Fusion", 16);
3652 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipRevision, "1.0", 8);
3653 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardName, "VBox MPT Fusion", 16);
3654 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardAssembly, "SUN", 8);
[73502]3655 memcpy(pPages->ManufacturingPage0.u.fields.abBoardTracerNumber, "CAFECAFECAFECAFE", 16);
[21321]3656
3657 /* Manufacturing Page 1 - I don't know what this contains so we leave it 0 for now. */
[25675]3658 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage1,
3659 MptConfigurationPageManufacturing1, 1,
3660 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3661
3662 /* Manufacturing Page 2. */
[25675]3663 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage2,
3664 MptConfigurationPageManufacturing2, 2,
3665 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3666
[44694]3667 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]3668 {
3669 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3670 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3671 }
[44694]3672 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]3673 {
3674 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3675 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3676 }
3677
[21321]3678 /* Manufacturing Page 3. */
[25675]3679 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage3,
3680 MptConfigurationPageManufacturing3, 3,
3681 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3682
[44694]3683 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]3684 {
3685 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3686 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3687 }
[44694]3688 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]3689 {
3690 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3691 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3692 }
3693
[21321]3694 /* Manufacturing Page 4 - I don't know what this contains so we leave it 0 for now. */
[25675]3695 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage4,
3696 MptConfigurationPageManufacturing4, 4,
3697 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3698
[25587]3699 /* Manufacturing Page 5 - WWID settings. */
[25675]3700 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage5,
3701 MptConfigurationPageManufacturing5, 5,
3702 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
[21321]3703
[33540]3704 /* Manufacturing Page 6 - Product specific settings. */
[25675]3705 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage6,
3706 MptConfigurationPageManufacturing6, 6,
3707 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[25587]3708
[33540]3709 /* Manufacturing Page 8 - Product specific settings. */
[25675]3710 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage8,
3711 MptConfigurationPageManufacturing8, 8,
3712 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[25587]3713
[33540]3714 /* Manufacturing Page 9 - Product specific settings. */
[25675]3715 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage9,
3716 MptConfigurationPageManufacturing9, 9,
3717 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[25587]3718
[33540]3719 /* Manufacturing Page 10 - Product specific settings. */
[25675]3720 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage10,
3721 MptConfigurationPageManufacturing10, 10,
3722 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[25587]3723
[21321]3724 /* I/O Unit page 0. */
[25675]3725 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage0,
3726 MptConfigurationPageIOUnit0, 0,
3727 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3728 pPages->IOUnitPage0.u.fields.u64UniqueIdentifier = 0xcafe;
3729
3730 /* I/O Unit page 1. */
[25675]3731 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage1,
3732 MptConfigurationPageIOUnit1, 1,
3733 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3734 pPages->IOUnitPage1.u.fields.fSingleFunction = true;
3735 pPages->IOUnitPage1.u.fields.fAllPathsMapped = false;
3736 pPages->IOUnitPage1.u.fields.fIntegratedRAIDDisabled = true;
3737 pPages->IOUnitPage1.u.fields.f32BitAccessForced = false;
3738
3739 /* I/O Unit page 2. */
[25675]3740 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage2,
3741 MptConfigurationPageIOUnit2, 2,
3742 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT);
[21321]3743 pPages->IOUnitPage2.u.fields.fPauseOnError = false;
3744 pPages->IOUnitPage2.u.fields.fVerboseModeEnabled = false;
3745 pPages->IOUnitPage2.u.fields.fDisableColorVideo = false;
3746 pPages->IOUnitPage2.u.fields.fNotHookInt40h = false;
3747 pPages->IOUnitPage2.u.fields.u32BIOSVersion = 0xcafecafe;
3748 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true;
3749 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true;
3750 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0;
[81781]3751 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pDevIns->apPciDevs[0]->uDevFn;
[21321]3752
3753 /* I/O Unit page 3. */
[25675]3754 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
3755 MptConfigurationPageIOUnit3, 3,
3756 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[21321]3757 pPages->IOUnitPage3.u.fields.u8GPIOCount = 0;
3758
[25587]3759 /* I/O Unit page 4. */
[25675]3760 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage4,
3761 MptConfigurationPageIOUnit4, 4,
3762 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[25587]3763
[21321]3764 /* IOC page 0. */
[25675]3765 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage0,
3766 MptConfigurationPageIOC0, 0,
3767 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3768 pPages->IOCPage0.u.fields.u32TotalNVStore = 0;
3769 pPages->IOCPage0.u.fields.u32FreeNVStore = 0;
3770
[44694]3771 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]3772 {
3773 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3774 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3775 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3776 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SPI_CLASS_CODE;
3777 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID;
3778 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID;
3779 }
[44694]3780 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]3781 {
3782 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3783 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3784 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3785 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SAS_CLASS_CODE;
3786 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID;
3787 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID;
3788 }
3789
[21321]3790 /* IOC page 1. */
[25675]3791 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage1,
3792 MptConfigurationPageIOC1, 1,
3793 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[21321]3794 pPages->IOCPage1.u.fields.fReplyCoalescingEnabled = false;
3795 pPages->IOCPage1.u.fields.u32CoalescingTimeout = 0;
3796 pPages->IOCPage1.u.fields.u8CoalescingDepth = 0;
3797
3798 /* IOC page 2. */
[25675]3799 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage2,
3800 MptConfigurationPageIOC2, 2,
3801 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3802 /* Everything else here is 0. */
3803
3804 /* IOC page 3. */
[25675]3805 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage3,
3806 MptConfigurationPageIOC3, 3,
3807 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3808 /* Everything else here is 0. */
3809
3810 /* IOC page 4. */
[25675]3811 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage4,
3812 MptConfigurationPageIOC4, 4,
3813 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3814 /* Everything else here is 0. */
3815
3816 /* IOC page 6. */
[25675]3817 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage6,
3818 MptConfigurationPageIOC6, 6,
3819 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
[21321]3820 /* Everything else here is 0. */
3821
[25587]3822 /* BIOS page 1. */
[25675]3823 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage1,
3824 MptConfigurationPageBIOS1, 1,
3825 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[21321]3826
[25587]3827 /* BIOS page 2. */
[25675]3828 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage2,
3829 MptConfigurationPageBIOS2, 2,
3830 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[21321]3831
[25587]3832 /* BIOS page 4. */
[25675]3833 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage4,
3834 MptConfigurationPageBIOS4, 4,
3835 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
[21321]3836
[44694]3837 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[81781]3838 lsilogicR3InitializeConfigurationPagesSpi(pThis, pThisCC);
[44694]3839 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[81781]3840 lsilogicR3InitializeConfigurationPagesSas(pThis, pThisCC);
[25587]3841 else
[44694]3842 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
[21321]3843}
3844
3845/**
[25509]3846 * Sets the emulated controller type from a given string.
3847 *
3848 * @returns VBox status code.
3849 *
[81781]3850 * @param pThis Pointer to the shared LsiLogic device state.
[44694]3851 * @param pcszCtrlType The string to use.
[25509]3852 */
[44694]3853static int lsilogicR3GetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType)
[25509]3854{
3855 int rc = VERR_INVALID_PARAMETER;
3856
3857 if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME))
3858 {
3859 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SPI;
3860 rc = VINF_SUCCESS;
3861 }
3862 else if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SAS_CTRLNAME))
3863 {
3864 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SAS;
3865 rc = VINF_SUCCESS;
3866 }
3867
3868 return rc;
3869}
3870
3871/**
[44694]3872 * @callback_method_impl{PFNDBGFHANDLERDEV}
[29706]3873 */
[44694]3874static DECLCALLBACK(void) lsilogicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
[29706]3875{
[81781]3876 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3877 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[29706]3878
3879 /*
3880 * Parse args.
3881 */
[81781]3882 bool const fVerbose = pszArgs && strstr(pszArgs, "verbose") != NULL;
[29706]3883
3884 /*
3885 * Show info.
3886 */
3887 pHlp->pfnPrintf(pHlp,
[81773]3888 "%s#%d: port=%04x mmio=%RGp max-devices=%u GC=%RTbool R0=%RTbool\n",
[81781]3889 pDevIns->pReg->szName, pDevIns->iInstance,
[81773]3890 PDMDevHlpIoPortGetMappingAddress(pDevIns, pThis->hIoPortsReg),
3891 PDMDevHlpMmioGetMappingAddress(pDevIns, pThis->hMmioReg),
[81781]3892 pThis->cDeviceStates, pDevIns->fRCEnabled, pDevIns->fR0Enabled);
[29706]3893
3894 /*
3895 * Show general state.
3896 */
3897 pHlp->pfnPrintf(pHlp, "enmState=%u\n", pThis->enmState);
3898 pHlp->pfnPrintf(pHlp, "enmWhoInit=%u\n", pThis->enmWhoInit);
[45789]3899 pHlp->pfnPrintf(pHlp, "enmDoorbellState=%d\n", pThis->enmDoorbellState);
[29706]3900 pHlp->pfnPrintf(pHlp, "fDiagnosticEnabled=%RTbool\n", pThis->fDiagnosticEnabled);
[53341]3901 pHlp->pfnPrintf(pHlp, "fNotificationSent=%RTbool\n", pThis->fNotificationSent);
[29706]3902 pHlp->pfnPrintf(pHlp, "fEventNotificationEnabled=%RTbool\n", pThis->fEventNotificationEnabled);
3903 pHlp->pfnPrintf(pHlp, "uInterruptMask=%#x\n", pThis->uInterruptMask);
3904 pHlp->pfnPrintf(pHlp, "uInterruptStatus=%#x\n", pThis->uInterruptStatus);
3905 pHlp->pfnPrintf(pHlp, "u16IOCFaultCode=%#06x\n", pThis->u16IOCFaultCode);
3906 pHlp->pfnPrintf(pHlp, "u32HostMFAHighAddr=%#x\n", pThis->u32HostMFAHighAddr);
3907 pHlp->pfnPrintf(pHlp, "u32SenseBufferHighAddr=%#x\n", pThis->u32SenseBufferHighAddr);
3908 pHlp->pfnPrintf(pHlp, "cMaxDevices=%u\n", pThis->cMaxDevices);
3909 pHlp->pfnPrintf(pHlp, "cMaxBuses=%u\n", pThis->cMaxBuses);
3910 pHlp->pfnPrintf(pHlp, "cbReplyFrame=%u\n", pThis->cbReplyFrame);
3911 pHlp->pfnPrintf(pHlp, "cReplyQueueEntries=%u\n", pThis->cReplyQueueEntries);
3912 pHlp->pfnPrintf(pHlp, "cRequestQueueEntries=%u\n", pThis->cRequestQueueEntries);
3913 pHlp->pfnPrintf(pHlp, "cPorts=%u\n", pThis->cPorts);
3914
3915 /*
3916 * Show queue status.
3917 */
3918 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextEntryFreeWrite=%u\n", pThis->uReplyFreeQueueNextEntryFreeWrite);
3919 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextAddressRead=%u\n", pThis->uReplyFreeQueueNextAddressRead);
3920 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextEntryFreeWrite=%u\n", pThis->uReplyPostQueueNextEntryFreeWrite);
3921 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextAddressRead=%u\n", pThis->uReplyPostQueueNextAddressRead);
3922 pHlp->pfnPrintf(pHlp, "uRequestQueueNextEntryFreeWrite=%u\n", pThis->uRequestQueueNextEntryFreeWrite);
3923 pHlp->pfnPrintf(pHlp, "uRequestQueueNextAddressRead=%u\n", pThis->uRequestQueueNextAddressRead);
3924
3925 /*
3926 * Show queue content if verbose
3927 */
3928 if (fVerbose)
3929 {
3930 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81751]3931 pHlp->pfnPrintf(pHlp, "RFQ[%u]=%#x\n", i, pThis->aReplyFreeQueue[i]);
[29706]3932
3933 pHlp->pfnPrintf(pHlp, "\n");
3934
3935 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81751]3936 pHlp->pfnPrintf(pHlp, "RPQ[%u]=%#x\n", i, pThis->aReplyPostQueue[i]);
[29706]3937
3938 pHlp->pfnPrintf(pHlp, "\n");
3939
3940 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
[81751]3941 pHlp->pfnPrintf(pHlp, "ReqQ[%u]=%#x\n", i, pThis->aRequestQueue[i]);
[29706]3942 }
[29744]3943
3944 /*
3945 * Print the device status.
3946 */
3947 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
3948 {
[81781]3949 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
[29744]3950
3951 pHlp->pfnPrintf(pHlp, "\n");
3952
3953 pHlp->pfnPrintf(pHlp, "Device[%u]: device-attached=%RTbool cOutstandingRequests=%u\n",
3954 i, pDevice->pDrvBase != NULL, pDevice->cOutstandingRequests);
3955 }
[29706]3956}
3957
[29588]3958
[81781]3959/**
3960 * @callback_method_impl{FNPDMTHREADDEV}
3961 */
[46265]3962static DECLCALLBACK(int) lsilogicR3Worker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
3963{
[81781]3964 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3965 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3966 int rc = VINF_SUCCESS;
[46265]3967
3968 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
3969 return VINF_SUCCESS;
3970
3971 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
3972 {
3973 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true);
[53341]3974 bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false);
3975 if (!fNotificationSent)
[46265]3976 {
3977 Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping));
[81781]3978 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtProcess, RT_INDEFINITE_WAIT);
[46265]3979 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
3980 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
3981 break;
3982 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
[53341]3983 ASMAtomicWriteBool(&pThis->fNotificationSent, false);
[46265]3984 }
3985
3986 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false);
3987
3988 /* Only process request which arrived before we received the notification. */
3989 uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite);
3990
3991 /* Go through the messages now and process them. */
3992 while ( RT_LIKELY(pThis->enmState == LSILOGICSTATE_OPERATIONAL)
3993 && (pThis->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite))
3994 {
[64224]3995 MptRequestUnion GuestRequest;
[81751]3996 uint32_t u32RequestMessageFrameDesc = pThis->aRequestQueue[pThis->uRequestQueueNextAddressRead];
[46265]3997 RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr,
3998 (u32RequestMessageFrameDesc & ~0x07));
3999
4000 /* Read the message header from the guest first. */
[86483]4001 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, sizeof(MptMessageHdr));
[46265]4002
4003 /* Determine the size of the request. */
4004 uint32_t cbRequest = 0;
[64224]4005 switch (GuestRequest.Header.u8Function)
[46265]4006 {
4007 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
4008 cbRequest = sizeof(MptSCSIIORequest);
4009 break;
4010 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
4011 cbRequest = sizeof(MptSCSITaskManagementRequest);
4012 break;
4013 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
4014 cbRequest = sizeof(MptIOCInitRequest);
4015 break;
4016 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
4017 cbRequest = sizeof(MptIOCFactsRequest);
4018 break;
4019 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
4020 cbRequest = sizeof(MptConfigurationRequest);
4021 break;
4022 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
4023 cbRequest = sizeof(MptPortFactsRequest);
4024 break;
4025 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
4026 cbRequest = sizeof(MptPortEnableRequest);
4027 break;
4028 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
4029 cbRequest = sizeof(MptEventNotificationRequest);
4030 break;
4031 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
4032 AssertMsgFailed(("todo\n"));
4033 //cbRequest = sizeof(MptEventAckRequest);
4034 break;
4035 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
4036 cbRequest = sizeof(MptFWDownloadRequest);
4037 break;
4038 case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
4039 cbRequest = sizeof(MptFWUploadRequest);
4040 break;
4041 default:
[64224]4042 AssertMsgFailed(("Unknown function issued %u\n", GuestRequest.Header.u8Function));
[46265]4043 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INVALID_FUNCTION);
4044 }
4045
4046 if (cbRequest != 0)
4047 {
4048 /* Read the complete message frame from guest memory now. */
[86483]4049 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, cbRequest);
[46265]4050
4051 /* Handle SCSI I/O requests now. */
[64224]4052 if (GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST)
[46265]4053 {
[81781]4054 rc = lsilogicR3ProcessSCSIIORequest(pDevIns, pThis, pThisCC, GCPhysMessageFrameAddr, &GuestRequest);
[46265]4055 AssertRC(rc);
4056 }
4057 else
4058 {
4059 MptReplyUnion Reply;
[81781]4060 rc = lsilogicR3ProcessMessageRequest(pDevIns, pThis, pThisCC, &GuestRequest.Header, &Reply);
[46265]4061 AssertRC(rc);
4062 }
4063
4064 pThis->uRequestQueueNextAddressRead++;
4065 pThis->uRequestQueueNextAddressRead %= pThis->cRequestQueueEntries;
4066 }
4067 } /* While request frames available. */
4068 } /* While running */
4069
4070 return VINF_SUCCESS;
4071}
4072
4073
[32983]4074/**
[81781]4075 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
[46265]4076 */
4077static DECLCALLBACK(int) lsilogicR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4078{
[62964]4079 RT_NOREF(pThread);
[81591]4080 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[81781]4081 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
[46265]4082}
4083
4084
4085/**
[32983]4086 * Kicks the controller to process pending tasks after the VM was resumed
4087 * or loaded from a saved state.
4088 *
[81781]4089 * @param pDevIns The device instance.
4090 * @param pThis Pointer to the shared LsiLogic device state.
[32983]4091 */
[81781]4092static void lsilogicR3Kick(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis)
[32983]4093{
[53341]4094 if (pThis->fNotificationSent)
[32983]4095 {
[81745]4096 /* Notify the worker thread that there are pending requests. */
4097 LogFlowFunc(("Signal event semaphore\n"));
[81781]4098 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
[81745]4099 AssertRC(rc);
[32983]4100 }
4101}
4102
[44694]4103
4104/*
4105 * Saved state.
4106 */
4107
4108/**
4109 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4110 */
4111static DECLCALLBACK(int) lsilogicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
[24071]4112{
[62964]4113 RT_NOREF(uPass);
[81781]4114 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4115 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4116 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[24071]4117
[81745]4118 pHlp->pfnSSMPutU32(pSSM, pThis->enmCtrlType);
4119 pHlp->pfnSSMPutU32(pSSM, pThis->cDeviceStates);
4120 pHlp->pfnSSMPutU32(pSSM, pThis->cPorts);
[25587]4121
[24071]4122 /* Save the device config. */
[25675]4123 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
[81781]4124 pHlp->pfnSSMPutBool(pSSM, pThisCC->paDeviceStates[i].pDrvBase != NULL);
[24071]4125
4126 return VINF_SSM_DONT_CALL_AGAIN;
4127}
4128
[44694]4129/**
4130 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4131 */
4132static DECLCALLBACK(int) lsilogicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
[21321]4133{
[81781]4134 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4135 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4136 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[21321]4137
4138 /* Every device first. */
[44694]4139 lsilogicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4140 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
[21321]4141 {
[81781]4142 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
[21321]4143
4144 AssertMsg(!pDevice->cOutstandingRequests,
4145 ("There are still outstanding requests on this device\n"));
[81745]4146 pHlp->pfnSSMPutU32(pSSM, pDevice->cOutstandingRequests);
[64224]4147
4148 /* Query all suspended requests and store them in the request queue. */
4149 if (pDevice->pDrvMediaEx)
4150 {
4151 uint32_t cReqsRedo = pDevice->pDrvMediaEx->pfnIoReqGetSuspendedCount(pDevice->pDrvMediaEx);
4152 if (cReqsRedo)
4153 {
4154 PDMMEDIAEXIOREQ hIoReq;
4155 PLSILOGICREQ pReq;
4156 int rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pDevice->pDrvMediaEx, &hIoReq,
4157 (void **)&pReq);
4158 AssertRCBreak(rc);
4159
4160 for (;;)
4161 {
[89193]4162 /* Write only the lower 32bit part of the address. */
4163 ASMAtomicWriteU32(&pThis->aRequestQueue[pThis->uRequestQueueNextEntryFreeWrite],
4164 pReq->GCPhysMessageFrameAddr & UINT32_C(0xffffffff));
[64224]4165
[89193]4166 pThis->uRequestQueueNextEntryFreeWrite++;
4167 pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries;
[64224]4168
4169 cReqsRedo--;
4170 if (!cReqsRedo)
4171 break;
4172
4173 rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pDevice->pDrvMediaEx, hIoReq,
4174 &hIoReq, (void **)&pReq);
4175 AssertRCBreak(rc);
4176 }
4177 }
4178 }
[21321]4179 }
[64224]4180
[21321]4181 /* Now the main device state. */
[81745]4182 pHlp->pfnSSMPutU32(pSSM, pThis->enmState);
4183 pHlp->pfnSSMPutU32(pSSM, pThis->enmWhoInit);
4184 pHlp->pfnSSMPutU32(pSSM, pThis->enmDoorbellState);
4185 pHlp->pfnSSMPutBool(pSSM, pThis->fDiagnosticEnabled);
4186 pHlp->pfnSSMPutBool(pSSM, pThis->fNotificationSent);
4187 pHlp->pfnSSMPutBool(pSSM, pThis->fEventNotificationEnabled);
4188 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptMask);
4189 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptStatus);
[44694]4190 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
[81745]4191 pHlp->pfnSSMPutU32(pSSM, pThis->aMessage[i]);
4192 pHlp->pfnSSMPutU32(pSSM, pThis->iMessage);
4193 pHlp->pfnSSMPutU32(pSSM, pThis->cMessage);
4194 pHlp->pfnSSMPutMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4195 pHlp->pfnSSMPutU32(pSSM, pThis->uNextReplyEntryRead);
4196 pHlp->pfnSSMPutU32(pSSM, pThis->cReplySize);
4197 pHlp->pfnSSMPutU16(pSSM, pThis->u16IOCFaultCode);
4198 pHlp->pfnSSMPutU32(pSSM, pThis->u32HostMFAHighAddr);
4199 pHlp->pfnSSMPutU32(pSSM, pThis->u32SenseBufferHighAddr);
4200 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxDevices);
4201 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxBuses);
4202 pHlp->pfnSSMPutU16(pSSM, pThis->cbReplyFrame);
4203 pHlp->pfnSSMPutU32(pSSM, pThis->iDiagnosticAccess);
4204 pHlp->pfnSSMPutU32(pSSM, pThis->cReplyQueueEntries);
4205 pHlp->pfnSSMPutU32(pSSM, pThis->cRequestQueueEntries);
4206 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextEntryFreeWrite);
4207 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextAddressRead);
4208 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextEntryFreeWrite);
4209 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextAddressRead);
4210 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextEntryFreeWrite);
4211 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextAddressRead);
[25587]4212
[44694]4213 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81751]4214 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyFreeQueue[i]);
[44694]4215 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81751]4216 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyPostQueue[i]);
[44694]4217 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
[81751]4218 pHlp->pfnSSMPutU32(pSSM, pThis->aRequestQueue[i]);
[25587]4219
[81745]4220 pHlp->pfnSSMPutU16(pSSM, pThis->u16NextHandle);
[25587]4221
[45970]4222 /* Save diagnostic memory register and data regions. */
[81745]4223 pHlp->pfnSSMPutU32(pSSM, pThis->u32DiagMemAddr);
[81781]4224 pHlp->pfnSSMPutU32(pSSM, lsilogicR3MemRegionsCount(pThisCC));
[45970]4225
[64766]4226 PLSILOGICMEMREGN pIt;
[81781]4227 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
[45970]4228 {
[81745]4229 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrStart);
4230 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrEnd);
4231 pHlp->pfnSSMPutMem(pSSM, &pIt->au32Data[0], (pIt->u32AddrEnd - pIt->u32AddrStart + 1) * sizeof(uint32_t));
[45970]4232 }
4233
[81781]4234 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
[25587]4235
[81745]4236 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4237 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4238 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4239 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4240 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4241 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4242 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4243 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4244 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4245 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4246 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4247 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4248 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4249 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4250 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4251 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4252 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4253 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4254 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4255 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4256 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4257 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4258 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4259 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
[25587]4260
4261 /* Device dependent pages */
[44694]4262 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]4263 {
4264 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4265
[81745]4266 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4267 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4268 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
[25587]4269
4270 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4271 {
[81745]4272 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4273 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4274 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4275 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
[25587]4276 }
4277 }
[44694]4278 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]4279 {
4280 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4281
[81745]4282 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbManufacturingPage7);
4283 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage0);
4284 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage1);
[25675]4285
[81745]4286 pHlp->pfnSSMPutMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4287 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4288 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
[25675]4289
[81745]4290 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4291 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
[25587]4292
[81745]4293 pHlp->pfnSSMPutU32(pSSM, pSasPages->cPHYs);
[25675]4294 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
[25587]4295 {
[81745]4296 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4297 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
[25587]4298 }
4299
4300 /* The number of devices first. */
[81745]4301 pHlp->pfnSSMPutU32(pSSM, pSasPages->cDevices);
[25587]4302
[81745]4303 for (PMptSASDevice pCurr = pSasPages->pSASDeviceHead; pCurr; pCurr = pCurr->pNext)
[25587]4304 {
[81745]4305 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4306 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4307 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
[25587]4308 }
4309 }
4310 else
[44694]4311 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
[25587]4312
[81745]4313 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
[21321]4314}
4315
[44694]4316/**
4317 * @callback_method_impl{FNSSMDEVLOADDONE}
4318 */
4319static DECLCALLBACK(int) lsilogicR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
[32983]4320{
[62964]4321 RT_NOREF(pSSM);
[81591]4322 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[32983]4323
[81781]4324 lsilogicR3Kick(pDevIns, pThis);
[32983]4325 return VINF_SUCCESS;
4326}
4327
[44694]4328/**
4329 * @callback_method_impl{FNSSMDEVLOADEXEC}
4330 */
4331static DECLCALLBACK(int) lsilogicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
[21321]4332{
[81781]4333 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4334 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4335 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[24071]4336 int rc;
[21321]4337
[89193]4338 if ( uVersion > LSILOGIC_SAVED_STATE_VERSION
4339 || uVersion < LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
[21321]4340 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4341
[24071]4342 /* device config */
[25587]4343 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4344 {
4345 LSILOGICCTRLTYPE enmCtrlType;
[25675]4346 uint32_t cDeviceStates, cPorts;
[25587]4347
[81765]4348 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, enmCtrlType, LSILOGICCTRLTYPE);
[81745]4349 pHlp->pfnSSMGetU32(pSSM, &cDeviceStates);
4350 rc = pHlp->pfnSSMGetU32(pSSM, &cPorts);
[25587]4351 AssertRCReturn(rc, rc);
4352
[44694]4353 if (enmCtrlType != pThis->enmCtrlType)
[81745]4354 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
4355 pThis->enmCtrlType, enmCtrlType);
[44694]4356 if (cDeviceStates != pThis->cDeviceStates)
[81745]4357 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
4358 pThis->cDeviceStates, cDeviceStates);
[44694]4359 if (cPorts != pThis->cPorts)
[81745]4360 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"),
4361 pThis->cPorts, cPorts);
[25587]4362 }
[24071]4363 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4364 {
[44694]4365 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
[24071]4366 {
4367 bool fPresent;
[81745]4368 rc = pHlp->pfnSSMGetBool(pSSM, &fPresent);
[24071]4369 AssertRCReturn(rc, rc);
[81781]4370 if (fPresent != (pThisCC->paDeviceStates[i].pDrvBase != NULL))
[81745]4371 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
[81781]4372 i, pThisCC->paDeviceStates[i].pDrvBase != NULL, fPresent);
[24071]4373 }
4374 }
4375 if (uPass != SSM_PASS_FINAL)
4376 return VINF_SUCCESS;
4377
[21321]4378 /* Every device first. */
[44694]4379 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
[21321]4380 {
[81781]4381 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
[21321]4382
4383 AssertMsg(!pDevice->cOutstandingRequests,
4384 ("There are still outstanding requests on this device\n"));
[81765]4385 pHlp->pfnSSMGetU32V(pSSM, &pDevice->cOutstandingRequests);
[21321]4386 }
4387 /* Now the main device state. */
[81765]4388 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmState, LSILOGICSTATE);
4389 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmWhoInit, LSILOGICWHOINIT);
[45789]4390 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL)
4391 {
4392 /*
4393 * The doorbell status flag distinguishes only between
4394 * doorbell not in use or a Function handshake is currently in progress.
4395 */
[81765]4396 bool fDoorbellInProgress = false;
4397 rc = pHlp->pfnSSMGetBool(pSSM, &fDoorbellInProgress);
4398 AssertRCReturn(rc, rc);
[45789]4399 if (fDoorbellInProgress)
4400 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE;
4401 else
4402 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
4403 }
4404 else
[81765]4405 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmDoorbellState, LSILOGICDOORBELLSTATE);
[81745]4406 pHlp->pfnSSMGetBool(pSSM, &pThis->fDiagnosticEnabled);
4407 pHlp->pfnSSMGetBool(pSSM, &pThis->fNotificationSent);
4408 pHlp->pfnSSMGetBool(pSSM, &pThis->fEventNotificationEnabled);
[81765]4409 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptMask);
4410 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptStatus);
[44694]4411 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
[81765]4412 pHlp->pfnSSMGetU32(pSSM, &pThis->aMessage[i]);
[81745]4413 pHlp->pfnSSMGetU32(pSSM, &pThis->iMessage);
4414 pHlp->pfnSSMGetU32(pSSM, &pThis->cMessage);
4415 pHlp->pfnSSMGetMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4416 pHlp->pfnSSMGetU32(pSSM, &pThis->uNextReplyEntryRead);
4417 pHlp->pfnSSMGetU32(pSSM, &pThis->cReplySize);
4418 pHlp->pfnSSMGetU16(pSSM, &pThis->u16IOCFaultCode);
4419 pHlp->pfnSSMGetU32(pSSM, &pThis->u32HostMFAHighAddr);
4420 pHlp->pfnSSMGetU32(pSSM, &pThis->u32SenseBufferHighAddr);
4421 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxDevices);
4422 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxBuses);
4423 pHlp->pfnSSMGetU16(pSSM, &pThis->cbReplyFrame);
4424 pHlp->pfnSSMGetU32(pSSM, &pThis->iDiagnosticAccess);
[29588]4425
4426 uint32_t cReplyQueueEntries, cRequestQueueEntries;
[81745]4427 pHlp->pfnSSMGetU32(pSSM, &cReplyQueueEntries);
4428 rc = pHlp->pfnSSMGetU32(pSSM, &cRequestQueueEntries);
4429 AssertRCReturn(rc, rc);
[29588]4430
[44694]4431 if ( cReplyQueueEntries != pThis->cReplyQueueEntries
4432 || cRequestQueueEntries != pThis->cRequestQueueEntries)
[29588]4433 {
[81751]4434 LogRel(("Changing queue sizes: cReplyQueueEntries=%u cRequestQueuEntries=%u\n", cReplyQueueEntries, cRequestQueueEntries));
4435 if ( cReplyQueueEntries > RT_ELEMENTS(pThis->aReplyFreeQueue)
4436 || cReplyQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
4437 || cRequestQueueEntries > RT_ELEMENTS(pThis->aRequestQueue)
4438 || cRequestQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN)
4439 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Out of bounds: cReplyQueueEntries=%u cRequestQueueEntries=%u"),
4440 cReplyQueueEntries, cRequestQueueEntries);
[44694]4441 pThis->cReplyQueueEntries = cReplyQueueEntries;
4442 pThis->cRequestQueueEntries = cRequestQueueEntries;
[29588]4443 }
4444
[81765]4445 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextEntryFreeWrite);
4446 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextAddressRead);
4447 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextEntryFreeWrite);
4448 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextAddressRead);
4449 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextEntryFreeWrite);
4450 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextAddressRead);
[25587]4451
[81781]4452 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
[25587]4453
4454 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4455 {
4456 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4457 MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2;
4458
[44694]4459 if (pThis->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI)
[81745]4460 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller"));
[25587]4461
[81751]4462 pHlp->pfnSSMGetMem(pSSM, &ConfigPagesV2, sizeof(MptConfigurationPagesSupported_SSM_V2));
[25587]4463
4464 pPages->ManufacturingPage0 = ConfigPagesV2.ManufacturingPage0;
4465 pPages->ManufacturingPage1 = ConfigPagesV2.ManufacturingPage1;
4466 pPages->ManufacturingPage2 = ConfigPagesV2.ManufacturingPage2;
4467 pPages->ManufacturingPage3 = ConfigPagesV2.ManufacturingPage3;
4468 pPages->ManufacturingPage4 = ConfigPagesV2.ManufacturingPage4;
4469 pPages->IOUnitPage0 = ConfigPagesV2.IOUnitPage0;
4470 pPages->IOUnitPage1 = ConfigPagesV2.IOUnitPage1;
4471 pPages->IOUnitPage2 = ConfigPagesV2.IOUnitPage2;
4472 pPages->IOUnitPage3 = ConfigPagesV2.IOUnitPage3;
4473 pPages->IOCPage0 = ConfigPagesV2.IOCPage0;
4474 pPages->IOCPage1 = ConfigPagesV2.IOCPage1;
4475 pPages->IOCPage2 = ConfigPagesV2.IOCPage2;
4476 pPages->IOCPage3 = ConfigPagesV2.IOCPage3;
4477 pPages->IOCPage4 = ConfigPagesV2.IOCPage4;
4478 pPages->IOCPage6 = ConfigPagesV2.IOCPage6;
4479
4480 pSpiPages->aPortPages[0].SCSISPIPortPage0 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage0;
4481 pSpiPages->aPortPages[0].SCSISPIPortPage1 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage1;
4482 pSpiPages->aPortPages[0].SCSISPIPortPage2 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage2;
4483
4484 for (unsigned i = 0; i < RT_ELEMENTS(pPages->u.SpiPages.aBuses[0].aDevicePages); i++)
4485 {
4486 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
4487 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
4488 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
4489 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
4490 }
4491 }
4492 else
4493 {
4494 /* Queue content */
[44694]4495 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81765]4496 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyFreeQueue[i]);
[44694]4497 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
[81765]4498 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyPostQueue[i]);
[44694]4499 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
[81765]4500 pHlp->pfnSSMGetU32V(pSSM, &pThis->aRequestQueue[i]);
[25587]4501
[81745]4502 pHlp->pfnSSMGetU16(pSSM, &pThis->u16NextHandle);
[25587]4503
[45970]4504 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM)
4505 {
4506
4507 /* Save diagnostic memory register and data regions. */
[81745]4508 pHlp->pfnSSMGetU32(pSSM, &pThis->u32DiagMemAddr);
[73091]4509 uint32_t cMemRegions = 0;
[81745]4510 rc = pHlp->pfnSSMGetU32(pSSM, &cMemRegions);
[77296]4511 AssertLogRelRCReturn(rc, rc);
[45970]4512
4513 while (cMemRegions)
4514 {
4515 uint32_t u32AddrStart = 0;
[81745]4516 pHlp->pfnSSMGetU32(pSSM, &u32AddrStart);
[45970]4517 uint32_t u32AddrEnd = 0;
[81745]4518 rc = pHlp->pfnSSMGetU32(pSSM, &u32AddrEnd);
[77296]4519 AssertLogRelRCReturn(rc, rc);
[45970]4520
[73091]4521 uint32_t cRegion = u32AddrEnd - u32AddrStart + 1;
[73097]4522 PLSILOGICMEMREGN pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_UOFFSETOF_DYN(LSILOGICMEMREGN, au32Data[cRegion]));
[45970]4523 if (pRegion)
4524 {
4525 pRegion->u32AddrStart = u32AddrStart;
4526 pRegion->u32AddrEnd = u32AddrEnd;
[81745]4527 pHlp->pfnSSMGetMem(pSSM, &pRegion->au32Data[0], cRegion * sizeof(uint32_t));
[81781]4528 lsilogicR3MemRegionInsert(pThisCC, pRegion);
4529 pThisCC->cbMemRegns += cRegion * sizeof(uint32_t);
[45970]4530 }
4531 else
4532 {
4533 /* Leave a log message but continue. */
4534 LogRel(("LsiLogic: Out of memory while restoring the state, might not work as expected\n"));
[81745]4535 pHlp->pfnSSMSkip(pSSM, cRegion * sizeof(uint32_t));
[45970]4536 }
4537 cMemRegions--;
4538 }
4539 }
4540
[25587]4541 /* Configuration pages */
[81745]4542 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4543 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4544 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4545 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4546 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4547 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4548 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4549 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4550 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4551 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4552 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4553 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4554 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4555 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4556 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4557 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4558 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4559 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4560 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4561 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4562 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4563 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4564 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4565 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
[25587]4566
4567 /* Device dependent pages */
[44694]4568 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25587]4569 {
4570 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4571
[81745]4572 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4573 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4574 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
[25587]4575
4576 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4577 {
[81745]4578 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4579 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4580 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4581 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
[25587]4582 }
4583 }
[44694]4584 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25587]4585 {
[25697]4586 uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7;
[25587]4587 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4588
[81745]4589 pHlp->pfnSSMGetU32(pSSM, &cbManufacturingPage7);
4590 pHlp->pfnSSMGetU32(pSSM, &cbPage0);
4591 rc = pHlp->pfnSSMGetU32(pSSM, &cbPage1);
4592 AssertRCReturn(rc, rc);
[25675]4593
4594 if ( (cbPage0 != pSasPages->cbSASIOUnitPage0)
[25697]4595 || (cbPage1 != pSasPages->cbSASIOUnitPage1)
4596 || (cbManufacturingPage7 != pSasPages->cbManufacturingPage7))
[25675]4597 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4598
[25697]4599 AssertPtr(pSasPages->pManufacturingPage7);
[25675]4600 AssertPtr(pSasPages->pSASIOUnitPage0);
4601 AssertPtr(pSasPages->pSASIOUnitPage1);
4602
[81745]4603 pHlp->pfnSSMGetMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4604 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4605 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
[25675]4606
[81745]4607 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4608 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
[25587]4609
[81745]4610 rc = pHlp->pfnSSMGetU32(pSSM, &cPHYs);
4611 AssertRCReturn(rc, rc);
[25675]4612 if (cPHYs != pSasPages->cPHYs)
4613 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4614
4615 AssertPtr(pSasPages->paPHYs);
4616 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
[25587]4617 {
[81745]4618 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4619 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
[25587]4620 }
4621
4622 /* The number of devices first. */
[81745]4623 rc = pHlp->pfnSSMGetU32(pSSM, &pSasPages->cDevices);
4624 AssertRCReturn(rc, rc);
[25587]4625
4626 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4627
4628 for (unsigned i = 0; i < pSasPages->cDevices; i++)
4629 {
[81745]4630 AssertReturn(pCurr, VERR_SSM_LOAD_CONFIG_MISMATCH);
[25587]4631
[81745]4632 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4633 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4634 rc = pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4635 AssertRCReturn(rc, rc);
4636
[25587]4637 pCurr = pCurr->pNext;
4638 }
4639
4640 Assert(!pCurr);
4641 }
4642 else
[44694]4643 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
[25587]4644 }
4645
[89193]4646 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_VBOXSCSI_REMOVAL)
4647 vboxscsiR3LoadExecLegacy(pHlp, pSSM);
[21321]4648
4649 uint32_t u32;
[81745]4650 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
[21321]4651 if (RT_FAILURE(rc))
4652 return rc;
[62964]4653 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
[21321]4654
4655 return VINF_SUCCESS;
4656}
4657
[44694]4658
4659/*
4660 * The device level IBASE and LED interfaces.
4661 */
4662
[21321]4663/**
[64274]4664 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed, For a SCSI device.}
[21321]4665 *
[44694]4666 * @remarks Called by the scsi driver, proxying the main calls.
[21321]4667 */
[44694]4668static DECLCALLBACK(int) lsilogicR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
[21321]4669{
[44694]4670 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ILed);
[21321]4671 if (iLUN == 0)
4672 {
4673 *ppLed = &pDevice->Led;
4674 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4675 return VINF_SUCCESS;
4676 }
4677 return VERR_PDM_LUN_NOT_FOUND;
4678}
4679
[25966]4680
[21321]4681/**
[25966]4682 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
[21321]4683 */
[44694]4684static DECLCALLBACK(void *) lsilogicR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
[21321]4685{
[44694]4686 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IBase);
[21321]4687
[25985]4688 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
[64224]4689 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pDevice->IMediaPort);
4690 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pDevice->IMediaExPort);
[25984]4691 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
[25966]4692 return NULL;
[21321]4693}
4694
[44694]4695
4696/*
4697 * The controller level IBASE and LED interfaces.
4698 */
4699
[21321]4700/**
4701 * Gets the pointer to the status LED of a unit.
4702 *
4703 * @returns VBox status code.
4704 * @param pInterface Pointer to the interface structure containing the called function pointer.
4705 * @param iLUN The unit which status LED we desire.
4706 * @param ppLed Where to store the LED pointer.
4707 */
[44694]4708static DECLCALLBACK(int) lsilogicR3StatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
[21321]4709{
[81781]4710 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, ILeds);
4711 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PLSILOGICSCSI);
[44694]4712 if (iLUN < pThis->cDeviceStates)
[21321]4713 {
[81781]4714 *ppLed = &pThisCC->paDeviceStates[iLUN].Led;
[21321]4715 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4716 return VINF_SUCCESS;
4717 }
4718 return VERR_PDM_LUN_NOT_FOUND;
4719}
4720
4721/**
[25966]4722 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
[21321]4723 */
[44694]4724static DECLCALLBACK(void *) lsilogicR3StatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
[21321]4725{
[81781]4726 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, IBase);
4727 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4728 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds);
[25966]4729 return NULL;
[21321]4730}
4731
[29609]4732
[44694]4733/*
4734 * The PDM device interface and some helpers.
4735 */
4736
[21321]4737/**
[29609]4738 * Checks if all asynchronous I/O is finished.
4739 *
[44694]4740 * Used by lsilogicR3Reset, lsilogicR3Suspend and lsilogicR3PowerOff.
[29609]4741 *
4742 * @returns true if quiesced, false if busy.
4743 * @param pDevIns The device instance.
4744 */
4745static bool lsilogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
4746{
[81781]4747 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4748 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[29609]4749
4750 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4751 {
[81781]4752 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
[29609]4753 if (pThisDevice->pDrvBase)
4754 {
4755 if (pThisDevice->cOutstandingRequests != 0)
4756 return false;
4757 }
4758 }
4759
4760 return true;
4761}
4762
4763/**
[44694]4764 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
4765 * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.}
[29609]4766 */
4767static DECLCALLBACK(bool) lsilogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
4768{
4769 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4770 return false;
4771
[81591]4772 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[29609]4773 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4774 return true;
4775}
4776
4777/**
4778 * Common worker for ahciR3Suspend and ahciR3PowerOff.
4779 */
4780static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
4781{
[81781]4782 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4783 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[29609]4784
4785 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
4786 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4787 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncSuspendOrPowerOffDone);
4788 else
[32983]4789 {
[29609]4790 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
[32983]4791
[53341]4792 AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
[32983]4793 }
[71775]4794
4795 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4796 {
[81781]4797 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
[71775]4798 if (pThisDevice->pDrvMediaEx)
4799 pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
4800 }
[29609]4801}
4802
4803/**
[44694]4804 * @interface_method_impl{PDMDEVREG,pfnSuspend}
[29609]4805 */
[44694]4806static DECLCALLBACK(void) lsilogicR3Suspend(PPDMDEVINS pDevIns)
[29609]4807{
[44694]4808 Log(("lsilogicR3Suspend\n"));
[29609]4809 lsilogicR3SuspendOrPowerOff(pDevIns);
4810}
4811
4812/**
[44694]4813 * @interface_method_impl{PDMDEVREG,pfnResume}
[32983]4814 */
[44694]4815static DECLCALLBACK(void) lsilogicR3Resume(PPDMDEVINS pDevIns)
[32983]4816{
[81591]4817 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[32983]4818
[44694]4819 Log(("lsilogicR3Resume\n"));
[32983]4820
[81781]4821 lsilogicR3Kick(pDevIns, pThis);
[32983]4822}
4823
4824/**
[44694]4825 * @interface_method_impl{PDMDEVREG,pfnDetach}
[21321]4826 *
4827 * One harddisk at one port has been unplugged.
4828 * The VM is suspended at this point.
4829 */
[44694]4830static DECLCALLBACK(void) lsilogicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
[21321]4831{
[81781]4832 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4833 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4834 Log(("%s: iLUN=%#x\n", __FUNCTION__, iLUN));
[62964]4835 RT_NOREF(fFlags);
[21321]4836
[81781]4837 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG, ("LsiLogic: Device does not support hotplugging\n"));
4838
[25675]4839 if (iLUN >= pThis->cDeviceStates)
4840 return;
4841
[21321]4842 /*
4843 * Zero some important members.
4844 */
[81781]4845 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
[21321]4846 pDevice->pDrvBase = NULL;
[64224]4847 pDevice->pDrvMedia = NULL;
4848 pDevice->pDrvMediaEx = NULL;
[21321]4849}
4850
4851/**
[44694]4852 * @interface_method_impl{PDMDEVREG,pfnAttach}
[21321]4853 */
[44694]4854static DECLCALLBACK(int) lsilogicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
[21321]4855{
[81781]4856 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4857 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4858 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
[21321]4859 int rc;
4860
[25675]4861 if (iLUN >= pThis->cDeviceStates)
4862 return VERR_PDM_LUN_NOT_FOUND;
4863
[22277]4864 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
[21321]4865 ("LsiLogic: Device does not support hotplugging\n"),
4866 VERR_INVALID_PARAMETER);
4867
4868 /* the usual paranoia */
4869 AssertRelease(!pDevice->pDrvBase);
[64224]4870 AssertRelease(!pDevice->pDrvMedia);
4871 AssertRelease(!pDevice->pDrvMediaEx);
[21321]4872 Assert(pDevice->iLUN == iLUN);
4873
4874 /*
4875 * Try attach the block device and get the interfaces,
4876 * required as well as optional.
4877 */
4878 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
4879 if (RT_SUCCESS(rc))
4880 {
[64224]4881 /* Query the media interface. */
4882 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
[90791]4883 AssertMsgReturn(RT_VALID_PTR(pDevice->pDrvMedia),
[64224]4884 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
4885 VERR_PDM_MISSING_INTERFACE);
4886
4887 /* Get the extended media interface. */
4888 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
[90791]4889 AssertMsgReturn(RT_VALID_PTR(pDevice->pDrvMediaEx),
[64224]4890 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
4891 VERR_PDM_MISSING_INTERFACE);
4892
4893 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
[64225]4894 AssertMsgRCReturn(rc, ("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!", pDevice->iLUN),
4895 rc);
[21321]4896 }
4897 else
4898 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
4899
4900 if (RT_FAILURE(rc))
4901 {
4902 pDevice->pDrvBase = NULL;
[64224]4903 pDevice->pDrvMedia = NULL;
4904 pDevice->pDrvMediaEx = NULL;
[21321]4905 }
4906 return rc;
4907}
4908
4909/**
[29609]4910 * Common reset worker.
4911 *
4912 * @param pDevIns The device instance data.
[21321]4913 */
[29609]4914static void lsilogicR3ResetCommon(PPDMDEVINS pDevIns)
[21321]4915{
[81781]4916 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4917 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[21321]4918 int rc;
4919
[81781]4920 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
[21321]4921 AssertRC(rc);
4922}
4923
4924/**
[44694]4925 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
4926 * Callback employed by lsilogicR3Reset.}
[29609]4927 */
4928static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns)
4929{
[81591]4930 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[29609]4931
4932 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4933 return false;
4934 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4935
4936 lsilogicR3ResetCommon(pDevIns);
4937 return true;
4938}
4939
4940/**
[44694]4941 * @interface_method_impl{PDMDEVREG,pfnReset}
[29609]4942 */
[44694]4943static DECLCALLBACK(void) lsilogicR3Reset(PPDMDEVINS pDevIns)
[29609]4944{
[81591]4945 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
[29609]4946
4947 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
4948 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4949 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncResetDone);
4950 else
4951 {
4952 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4953 lsilogicR3ResetCommon(pDevIns);
4954 }
4955}
4956
4957/**
[44694]4958 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
[21321]4959 */
[44694]4960static DECLCALLBACK(void) lsilogicR3PowerOff(PPDMDEVINS pDevIns)
[21321]4961{
[44694]4962 Log(("lsilogicR3PowerOff\n"));
4963 lsilogicR3SuspendOrPowerOff(pDevIns);
4964}
4965
4966/**
4967 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4968 */
4969static DECLCALLBACK(int) lsilogicR3Destruct(PPDMDEVINS pDevIns)
4970{
[81752]4971 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
[81781]4972 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4973 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
[21321]4974
[81752]4975 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueCritSect);
4976 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyPostQueueCritSect);
4977 PDMDevHlpCritSectDelete(pDevIns, &pThis->RequestQueueCritSect);
4978 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueWriteCritSect);
[21321]4979
[88530]4980 if (RTCritSectIsInitialized(&pThisCC->CritSectMemRegns))
4981 RTCritSectDelete(&pThisCC->CritSectMemRegns);
4982
[81781]4983 RTMemFree(pThisCC->paDeviceStates);
4984 pThisCC->paDeviceStates = NULL;
[25675]4985
[46265]4986 if (pThis->hEvtProcess != NIL_SUPSEMEVENT)
4987 {
[81781]4988 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtProcess);
[46265]4989 pThis->hEvtProcess = NIL_SUPSEMEVENT;
4990 }
4991
[81781]4992 lsilogicR3ConfigurationPagesFree(pThis, pThisCC);
4993 lsilogicR3MemRegionsFree(pThisCC);
[44694]4994 return VINF_SUCCESS;
[21321]4995}
4996
4997/**
[44694]4998 * @interface_method_impl{PDMDEVREG,pfnConstruct}
[29609]4999 */
[44694]5000static DECLCALLBACK(int) lsilogicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
[29609]5001{
[81752]5002 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
[81781]5003 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5004 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5005 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5006 int rc = VINF_SUCCESS;
[21321]5007
5008 /*
[44694]5009 * Initialize enought of the state to make the destructure not trip up.
5010 */
[46265]5011 pThis->hEvtProcess = NIL_SUPSEMEVENT;
[81781]5012 RTListInit(&pThisCC->ListMemRegns);
[81773]5013 pThis->hMmioReg = NIL_IOMMMIOHANDLE;
5014 pThis->hMmioDiag = NIL_IOMMMIOHANDLE;
5015 pThis->hIoPortsReg = NIL_IOMIOPORTHANDLE;
5016 pThis->hIoPortsBios = NIL_IOMIOPORTHANDLE;
[81781]5017 pThisCC->pDevIns = pDevIns;
5018 pThisCC->IBase.pfnQueryInterface = lsilogicR3StatusQueryInterface;
5019 pThisCC->ILeds.pfnQueryStatusLed = lsilogicR3StatusQueryStatusLed;
[44694]5020
[81781]5021
[44694]5022 /*
[21321]5023 * Validate and read configuration.
5024 */
[81745]5025 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
5026 "ReplyQueueDepth|"
5027 "RequestQueueDepth|"
5028 "ControllerType|"
5029 "NumPorts|"
[89193]5030 "Bootable", /* Keep it for legacy configs, even though it doesn't do anything anymore, see @bugref{4841}. */
[81745]5031 "");
[21321]5032
[81745]5033 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "ReplyQueueDepth",
5034 &pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT);
[21321]5035 if (RT_FAILURE(rc))
5036 return PDMDEV_SET_ERROR(pDevIns, rc,
5037 N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
[81751]5038 if ( pThis->cReplyQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN
5039 || pThis->cReplyQueueEntries > LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5040 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5041 N_("LsiLogic configuration error: 'ReplyQueueDepth' = %u is out of ranage (%u..%u)"),
5042 pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN,
5043 LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1);
[21321]5044 Log(("%s: ReplyQueueDepth=%u\n", __FUNCTION__, pThis->cReplyQueueEntries));
5045
[81745]5046 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "RequestQueueDepth",
5047 &pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT);
[21321]5048 if (RT_FAILURE(rc))
[81751]5049 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
5050 if ( pThis->cRequestQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
5051 || pThis->cRequestQueueEntries > LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5052 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5053 N_("LsiLogic configuration error: 'RequestQueue' = %u is out of ranage (%u..%u)"),
5054 pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN,
5055 LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN - 1);
[21321]5056 Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries));
5057
[81752]5058 char szCtrlType[64];
5059 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "ControllerType", szCtrlType, sizeof(szCtrlType), LSILOGICSCSI_PCI_SPI_CTRLNAME);
[25509]5060 if (RT_FAILURE(rc))
5061 return PDMDEV_SET_ERROR(pDevIns, rc,
5062 N_("LsiLogic configuration error: failed to read ControllerType as string"));
[81752]5063 Log(("%s: ControllerType=%s\n", __FUNCTION__, szCtrlType));
5064 rc = lsilogicR3GetCtrlTypeFromString(pThis, szCtrlType);
5065 if (RT_FAILURE(rc))
5066 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to determine controller type from string"));
[34009]5067
[44695]5068 char szDevTag[20];
[37466]5069 RTStrPrintf(szDevTag, sizeof(szDevTag), "LSILOGIC%s-%u",
[33919]5070 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "SPI" : "SAS",
5071 iInstance);
5072
[81745]5073 rc = pHlp->pfnCFGMQueryU8(pCfg, "NumPorts", &pThis->cPorts);
[25675]5074 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5075 {
5076 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5077 pThis->cPorts = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
5078 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5079 pThis->cPorts = LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT;
5080 else
5081 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5082 }
5083 else if (RT_FAILURE(rc))
5084 return PDMDEV_SET_ERROR(pDevIns, rc,
5085 N_("LsiLogic configuration error: failed to read NumPorts as integer"));
5086
[21321]5087 /* Init static parts. */
[81031]5088 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
5089 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
[21321]5090
[81031]5091 PDMPciDevSetVendorId(pPciDev, LSILOGICSCSI_PCI_VENDOR_ID); /* LsiLogic */
[25509]5092 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5093 {
[81031]5094 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SPI_DEVICE_ID); /* LSI53C1030 */
5095 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID);
5096 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID);
[25509]5097 }
5098 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5099 {
[81031]5100 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SAS_DEVICE_ID); /* SAS1068 */
5101 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID);
5102 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID);
[25509]5103 }
5104 else
5105 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5106
[81031]5107 PDMPciDevSetClassProg(pPciDev, 0x00); /* SCSI */
5108 PDMPciDevSetClassSub(pPciDev, 0x00); /* SCSI */
5109 PDMPciDevSetClassBase(pPciDev, 0x01); /* Mass storage */
5110 PDMPciDevSetInterruptPin(pPciDev, 0x01); /* Interrupt pin A */
[25509]5111
[44694]5112# ifdef VBOX_WITH_MSI_DEVICES
[81031]5113 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
5114 PDMPciDevSetCapabilityList(pPciDev, 0x80);
[44694]5115# endif
[32935]5116
[21321]5117 /*
[44695]5118 * Create critical sections protecting the reply post and free queues.
5119 */
5120 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag);
5121 if (RT_FAILURE(rc))
5122 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue"));
5123
5124 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag);
5125 if (RT_FAILURE(rc))
5126 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply post queue"));
5127
[64808]5128 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->RequestQueueCritSect, RT_SRC_POS, "%sRQ", szDevTag);
5129 if (RT_FAILURE(rc))
5130 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for request queue"));
5131
5132 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueWriteCritSect, RT_SRC_POS, "%sRFQW", szDevTag);
5133 if (RT_FAILURE(rc))
5134 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue write access"));
5135
[44695]5136 /*
[88530]5137 * Critical section protecting the memory regions.
5138 */
5139 rc = RTCritSectInit(&pThisCC->CritSectMemRegns);
5140 if (RT_FAILURE(rc))
5141 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: Failed to initialize critical section protecting the memory regions"));
5142
5143 /*
[21321]5144 * Register the PCI device, it's I/O regions.
5145 */
[81031]5146 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
[21321]5147 if (RT_FAILURE(rc))
5148 return rc;
5149
[44694]5150# ifdef VBOX_WITH_MSI_DEVICES
[44571]5151 PDMMSIREG MsiReg;
5152 RT_ZERO(MsiReg);
[33419]5153 /* use this code for MSI-X support */
[44694]5154# if 0
[44571]5155 MsiReg.cMsixVectors = 1;
5156 MsiReg.iMsixCapOffset = 0x80;
5157 MsiReg.iMsixNextOffset = 0x00;
5158 MsiReg.iMsixBar = 3;
[80704]5159 Assert(pDevIns->pReg->cMaxMsixVectors >= MsiReg.cMsixVectors); /* fix device registration when enabling this */
[44694]5160# else
[44571]5161 MsiReg.cMsiVectors = 1;
5162 MsiReg.iMsiCapOffset = 0x80;
5163 MsiReg.iMsiNextOffset = 0x00;
[44694]5164# endif
[44571]5165 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
[32935]5166 if (RT_FAILURE (rc))
[32938]5167 {
5168 /* That's OK, we can work without MSI */
[81031]5169 PDMPciDevSetCapabilityList(pPciDev, 0x0);
[32938]5170 }
[44694]5171# endif
[32935]5172
[81773]5173 /* Region #0: I/O ports. */
5174 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, LSILOGIC_PCI_SPACE_IO_SIZE,
5175 lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/,
5176 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5177 NULL /*paExtDesc*/, &pThis->hIoPortsReg);
5178 AssertRCReturn(rc, rc);
[21321]5179
[81773]5180 /* Region #1: MMIO.
5181 *
5182 * Non-4-byte read access to LSILOGIC_REG_REPLY_QUEUE may cause real strange behavior
5183 * because the data is part of a physical guest address. But some drivers use 1-byte
5184 * access to scan for SCSI controllers. So, we simplify our code by telling IOM to
5185 * read DWORDs.
5186 *
5187 * Regarding writes, we couldn't find anything specific in the specs about what should
5188 * happen. So far we've ignored unaligned writes and assumed the missing bytes of
5189 * byte and word access to be zero. We suspect that IOMMMIO_FLAGS_WRITE_ONLY_DWORD
5190 * or IOMMMIO_FLAGS_WRITE_DWORD_ZEROED would be the most appropriate here, but since we
5191 * don't have real hw to test one, the old behavior is kept exactly like it used to be.
5192 */
5193 /** @todo Check out unaligned writes and non-dword writes on real LsiLogic
5194 * hardware. */
5195 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 1 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5196 lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/,
5197 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5198 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5199 &pThis->hMmioReg);
5200 AssertRCReturn(rc, rc);
[21321]5201
[81773]5202 /* Region #2: MMIO - Diag. */
5203 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 2 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5204 lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/,
[104193]5205 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_DWORD_ZEROED,
[81773]5206 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogicDiag" : "LsiLogicSasDiag",
5207 &pThis->hMmioDiag);
5208 AssertRCReturn(rc, rc);
[21321]5209
5210 /*
5211 * We need one entry free in the queue.
5212 */
5213 pThis->cReplyQueueEntries++;
[81751]5214 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyFreeQueue), VERR_INTERNAL_ERROR_3);
5215 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyPostQueue), VERR_INTERNAL_ERROR_3);
5216
[21321]5217 pThis->cRequestQueueEntries++;
[81751]5218 AssertLogRelReturn(pThis->cRequestQueueEntries <= RT_ELEMENTS(pThis->aRequestQueue), VERR_INTERNAL_ERROR_3);
[21321]5219
5220 /*
[81751]5221 * Device states.
[21321]5222 */
[25587]5223 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
[25675]5224 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
[25587]5225 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
[25675]5226 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
[25587]5227 else
[81752]5228 AssertLogRelMsgFailedReturn(("Invalid controller type: %d\n", pThis->enmCtrlType), VERR_INTERNAL_ERROR_4);
[25587]5229
[25675]5230 /*
[46265]5231 * Create event semaphore and worker thread.
5232 */
[81781]5233 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pThreadWrk, pThis, lsilogicR3Worker,
[46265]5234 lsilogicR3WorkerWakeUp, 0, RTTHREADTYPE_IO, szDevTag);
5235 if (RT_FAILURE(rc))
5236 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5237 N_("LsiLogic: Failed to create worker thread %s"), szDevTag);
5238
[81781]5239 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtProcess);
[46265]5240 if (RT_FAILURE(rc))
5241 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5242 N_("LsiLogic: Failed to create SUP event semaphore"));
5243
5244 /*
[25675]5245 * Allocate device states.
5246 */
[81781]5247 pThisCC->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
5248 if (!pThisCC->paDeviceStates)
[44695]5249 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate memory for device states"));
[25675]5250
5251 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
[25587]5252 {
[81781]5253 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
[25587]5254
[25675]5255 /* Initialize static parts of the device. */
[64224]5256 pDevice->iLUN = i;
[81781]5257 pDevice->pDevIns = pDevIns;
[64224]5258 pDevice->Led.u32Magic = PDMLED_MAGIC;
5259 pDevice->IBase.pfnQueryInterface = lsilogicR3DeviceQueryInterface;
5260 pDevice->IMediaPort.pfnQueryDeviceLocation = lsilogicR3QueryDeviceLocation;
5261 pDevice->IMediaExPort.pfnIoReqCompleteNotify = lsilogicR3IoReqCompleteNotify;
5262 pDevice->IMediaExPort.pfnIoReqCopyFromBuf = lsilogicR3IoReqCopyFromBuf;
5263 pDevice->IMediaExPort.pfnIoReqCopyToBuf = lsilogicR3IoReqCopyToBuf;
[64660]5264 pDevice->IMediaExPort.pfnIoReqQueryBuf = NULL;
[64224]5265 pDevice->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
5266 pDevice->IMediaExPort.pfnIoReqStateChanged = lsilogicR3IoReqStateChanged;
5267 pDevice->IMediaExPort.pfnMediumEjected = lsilogicR3MediumEjected;
5268 pDevice->ILed.pfnQueryStatusLed = lsilogicR3DeviceQueryStatusLed;
[81781]5269 RTStrPrintf(pDevice->szName, sizeof(pDevice->szName), "Device%u", i);
[25675]5270
[21321]5271 /* Attach SCSI driver. */
[81781]5272 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, pDevice->szName);
[21321]5273 if (RT_SUCCESS(rc))
5274 {
[64224]5275 /* Query the media interface. */
5276 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
[90791]5277 AssertMsgReturn(RT_VALID_PTR(pDevice->pDrvMedia),
[64224]5278 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5279 VERR_PDM_MISSING_INTERFACE);
5280
5281 /* Get the extended media interface. */
5282 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
[90791]5283 AssertMsgReturn(RT_VALID_PTR(pDevice->pDrvMediaEx),
[64224]5284 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5285 VERR_PDM_MISSING_INTERFACE);
5286
5287 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5288 if (RT_FAILURE(rc))
5289 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5290 N_("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!"),
5291 pDevice->iLUN);
[21321]5292 }
5293 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5294 {
5295 pDevice->pDrvBase = NULL;
5296 rc = VINF_SUCCESS;
[81781]5297 Log(("LsiLogic: no driver attached to device %s\n", pDevice->szName));
[21321]5298 }
5299 else
5300 {
[81781]5301 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", pDevice->szName));
[21321]5302 return rc;
5303 }
5304 }
5305
5306 /*
5307 * Attach status driver (optional).
5308 */
5309 PPDMIBASE pBase;
[81781]5310 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
[21321]5311 if (RT_SUCCESS(rc))
[64409]5312 {
[81781]5313 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5314 pThisCC->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
[64409]5315 }
[81773]5316 else
5317 AssertMsgReturn(rc == VERR_PDM_NO_ATTACHED_DRIVER,
5318 ("Failed to attach to status driver. rc=%Rrc\n", rc),
5319 PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver")));
[21321]5320
5321 /* Register save state handlers. */
[32983]5322 rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
[44694]5323 NULL, lsilogicR3LiveExec, NULL,
5324 NULL, lsilogicR3SaveExec, NULL,
5325 NULL, lsilogicR3LoadExec, lsilogicR3LoadDone);
[21321]5326 if (RT_FAILURE(rc))
5327 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
5328
5329 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
5330
[29706]5331 /*
5332 * Register the info item.
5333 */
5334 char szTmp[128];
[44695]5335 RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
[29706]5336 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp,
5337 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
5338 ? "LsiLogic SPI info."
[44694]5339 : "LsiLogic SAS info.", lsilogicR3Info);
[29706]5340
[88530]5341 /* Allocate configuration pages. */
5342 rc = lsilogicR3ConfigurationPagesAlloc(pThis, pThisCC);
5343 if (RT_FAILURE(rc))
5344 PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: Failed to allocate memory for configuration pages"));
5345
[21321]5346 /* Perform hard reset. */
[81781]5347 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
[21321]5348 AssertRC(rc);
5349
5350 return rc;
5351}
5352
[81773]5353#else /* !IN_RING3 */
[80531]5354
[21321]5355/**
[81773]5356 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5357 */
5358static DECLCALLBACK(int) lsilogicRZConstruct(PPDMDEVINS pDevIns)
5359{
5360 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5361 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5362
[81774]5363 /* Setup callbacks for this context: */
[85101]5364 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsReg, lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/);
[81774]5365 AssertRCReturn(rc, rc);
5366
[81773]5367 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioReg, lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/);
5368 AssertRCReturn(rc, rc);
5369
5370 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioDiag, lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/);
5371 AssertRCReturn(rc, rc);
5372
5373 return VINF_SUCCESS;
5374}
5375
5376#endif /* !IN_RING3 */
5377
5378/**
[29326]5379 * The device registration structure - SPI SCSI controller.
[21321]5380 */
5381const PDMDEVREG g_DeviceLsiLogicSCSI =
5382{
[80531]5383 /* .u32Version = */ PDM_DEVREG_VERSION,
5384 /* .uReserved0 = */ 0,
5385 /* .szName = */ "lsilogicscsi",
[81781]5386 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5387 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
[80531]5388 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5389 /* .cMaxInstances = */ ~0U,
5390 /* .uSharedVersion = */ 42,
5391 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
[81781]5392 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5393 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
[80701]5394 /* .cMaxPciDevices = */ 1,
[80704]5395 /* .cMaxMsixVectors = */ 0,
[80531]5396 /* .pszDescription = */ "LSI Logic 53c1030 SCSI controller.\n",
5397#if defined(IN_RING3)
5398 /* .pszRCMod = */ "VBoxDDRC.rc",
5399 /* .pszR0Mod = */ "VBoxDDR0.r0",
5400 /* .pfnConstruct = */ lsilogicR3Construct,
5401 /* .pfnDestruct = */ lsilogicR3Destruct,
[81781]5402 /* .pfnRelocate = */ NULL,
[80531]5403 /* .pfnMemSetup = */ NULL,
5404 /* .pfnPowerOn = */ NULL,
5405 /* .pfnReset = */ lsilogicR3Reset,
5406 /* .pfnSuspend = */ lsilogicR3Suspend,
5407 /* .pfnResume = */ lsilogicR3Resume,
5408 /* .pfnAttach = */ lsilogicR3Attach,
5409 /* .pfnDetach = */ lsilogicR3Detach,
5410 /* .pfnQueryInterface = */ NULL,
5411 /* .pfnInitComplete = */ NULL,
5412 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5413 /* .pfnSoftReset = */ NULL,
5414 /* .pfnReserved0 = */ NULL,
5415 /* .pfnReserved1 = */ NULL,
5416 /* .pfnReserved2 = */ NULL,
5417 /* .pfnReserved3 = */ NULL,
5418 /* .pfnReserved4 = */ NULL,
5419 /* .pfnReserved5 = */ NULL,
5420 /* .pfnReserved6 = */ NULL,
5421 /* .pfnReserved7 = */ NULL,
5422#elif defined(IN_RING0)
5423 /* .pfnEarlyConstruct = */ NULL,
[81773]5424 /* .pfnConstruct = */ lsilogicRZConstruct,
[80531]5425 /* .pfnDestruct = */ NULL,
5426 /* .pfnFinalDestruct = */ NULL,
5427 /* .pfnRequest = */ NULL,
5428 /* .pfnReserved0 = */ NULL,
5429 /* .pfnReserved1 = */ NULL,
5430 /* .pfnReserved2 = */ NULL,
5431 /* .pfnReserved3 = */ NULL,
5432 /* .pfnReserved4 = */ NULL,
5433 /* .pfnReserved5 = */ NULL,
5434 /* .pfnReserved6 = */ NULL,
5435 /* .pfnReserved7 = */ NULL,
5436#elif defined(IN_RC)
[81773]5437 /* .pfnConstruct = */ lsilogicRZConstruct,
[80531]5438 /* .pfnReserved0 = */ NULL,
5439 /* .pfnReserved1 = */ NULL,
5440 /* .pfnReserved2 = */ NULL,
5441 /* .pfnReserved3 = */ NULL,
5442 /* .pfnReserved4 = */ NULL,
5443 /* .pfnReserved5 = */ NULL,
5444 /* .pfnReserved6 = */ NULL,
5445 /* .pfnReserved7 = */ NULL,
5446#else
5447# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5448#endif
5449 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
[21321]5450};
5451
[29326]5452/**
5453 * The device registration structure - SAS controller.
5454 */
5455const PDMDEVREG g_DeviceLsiLogicSAS =
5456{
[80531]5457 /* .u32Version = */ PDM_DEVREG_VERSION,
5458 /* .uReserved0 = */ 0,
5459 /* .szName = */ "lsilogicsas",
[82456]5460 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5461 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION
5462 | PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
[80531]5463 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5464 /* .cMaxInstances = */ ~0U,
5465 /* .uSharedVersion = */ 42,
5466 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
[81781]5467 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5468 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
[80702]5469 /* .cMaxPciDevices = */ 1,
[80704]5470 /* .cMaxMsixVectors = */ 0,
[80531]5471 /* .pszDescription = */ "LSI Logic SAS1068 controller.\n",
5472#if defined(IN_RING3)
5473 /* .pszRCMod = */ "VBoxDDRC.rc",
5474 /* .pszR0Mod = */ "VBoxDDR0.r0",
5475 /* .pfnConstruct = */ lsilogicR3Construct,
5476 /* .pfnDestruct = */ lsilogicR3Destruct,
[81781]5477 /* .pfnRelocate = */ NULL,
[80531]5478 /* .pfnMemSetup = */ NULL,
5479 /* .pfnPowerOn = */ NULL,
5480 /* .pfnReset = */ lsilogicR3Reset,
5481 /* .pfnSuspend = */ lsilogicR3Suspend,
5482 /* .pfnResume = */ lsilogicR3Resume,
5483 /* .pfnAttach = */ lsilogicR3Attach,
5484 /* .pfnDetach = */ lsilogicR3Detach,
5485 /* .pfnQueryInterface = */ NULL,
5486 /* .pfnInitComplete = */ NULL,
5487 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5488 /* .pfnSoftReset = */ NULL,
5489 /* .pfnReserved0 = */ NULL,
5490 /* .pfnReserved1 = */ NULL,
5491 /* .pfnReserved2 = */ NULL,
5492 /* .pfnReserved3 = */ NULL,
5493 /* .pfnReserved4 = */ NULL,
5494 /* .pfnReserved5 = */ NULL,
5495 /* .pfnReserved6 = */ NULL,
5496 /* .pfnReserved7 = */ NULL,
5497#elif defined(IN_RING0)
5498 /* .pfnEarlyConstruct = */ NULL,
[81773]5499 /* .pfnConstruct = */ lsilogicRZConstruct,
[80531]5500 /* .pfnDestruct = */ NULL,
5501 /* .pfnFinalDestruct = */ NULL,
5502 /* .pfnRequest = */ NULL,
5503 /* .pfnReserved0 = */ NULL,
5504 /* .pfnReserved1 = */ NULL,
5505 /* .pfnReserved2 = */ NULL,
5506 /* .pfnReserved3 = */ NULL,
5507 /* .pfnReserved4 = */ NULL,
5508 /* .pfnReserved5 = */ NULL,
5509 /* .pfnReserved6 = */ NULL,
5510 /* .pfnReserved7 = */ NULL,
5511#elif defined(IN_RC)
[81773]5512 /* .pfnConstruct = */ lsilogicRZConstruct,
[80531]5513 /* .pfnReserved0 = */ NULL,
5514 /* .pfnReserved1 = */ NULL,
5515 /* .pfnReserved2 = */ NULL,
5516 /* .pfnReserved3 = */ NULL,
5517 /* .pfnReserved4 = */ NULL,
5518 /* .pfnReserved5 = */ NULL,
5519 /* .pfnReserved6 = */ NULL,
5520 /* .pfnReserved7 = */ NULL,
5521#else
5522# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5523#endif
5524 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
[29326]5525};
5526
[21321]5527#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use