VirtualBox

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

Last change on this file since 103882 was 99775, checked in by vboxsync, 12 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use