VirtualBox

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

Last change on this file since 64808 was 64808, checked in by vboxsync, 8 years ago

LsiLogic: Protect the request queue and writes to the reply free queue against concurrent access from the guest when using multiple vCPUs, should fix task aborts observed with Linux kernels starting from at least 3.18 (maybe even earlier, last known godd kernel is 3.14)

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette