VirtualBox

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

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

gcc 7: Devices: fall thru

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 244.7 KB
Line 
1/* $Id: DevLsiLogicSCSI.cpp 65648 2017-02-07 11:43:22Z 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 if (pThis->uNextReplyEntryRead < pThis->cReplySize)
1608 u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++];
1609 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1610 break;
1611 case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW:
1612 {
1613 uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis);
1614
1615 u32 |= cReplyFrames & UINT32_C(0xffff);
1616 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH;
1617 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1618 break;
1619 }
1620 case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_HIGH:
1621 {
1622 uint32_t cReplyFrames = lsilogicReplyFreeQueueGetFrameCount(pThis);
1623
1624 u32 |= cReplyFrames >> 16;
1625 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW;
1626 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1627 break;
1628 }
1629 case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW:
1630 if (pThis->uReplyFreeQueueNextEntryFreeWrite != pThis->uReplyFreeQueueNextAddressRead)
1631 {
1632 u32 |= pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead] & UINT32_C(0xffff);
1633 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH;
1634 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1635 }
1636 break;
1637 case LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_HIGH:
1638 u32 |= pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextAddressRead] >> 16;
1639 pThis->uReplyFreeQueueNextAddressRead++;
1640 pThis->uReplyFreeQueueNextAddressRead %= pThis->cReplyQueueEntries;
1641 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_RFR_NEXT_FRAME_LOW;
1642 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1643 break;
1644 default:
1645 AssertMsgFailed(("Invalid doorbell state %d\n", pThis->enmDoorbellState));
1646 }
1647
1648 break;
1649 }
1650 case LSILOGIC_REG_HOST_INTR_STATUS:
1651 {
1652 u32 = ASMAtomicReadU32(&pThis->uInterruptStatus);
1653 break;
1654 }
1655 case LSILOGIC_REG_HOST_INTR_MASK:
1656 {
1657 u32 = ASMAtomicReadU32(&pThis->uInterruptMask);
1658 break;
1659 }
1660 case LSILOGIC_REG_HOST_DIAGNOSTIC:
1661 {
1662 if (pThis->fDiagnosticEnabled)
1663 u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
1664 if (pThis->fDiagRegsEnabled)
1665 u32 |= LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE;
1666 break;
1667 }
1668 case LSILOGIC_REG_DIAG_RW_DATA:
1669 {
1670 if (pThis->fDiagRegsEnabled)
1671 {
1672#ifndef IN_RING3
1673 return VINF_IOM_R3_MMIO_READ;
1674#else
1675 lsilogicR3DiagRegDataRead(pThis, &u32);
1676#endif
1677 }
1678 }
1679 /* fall thru */
1680 case LSILOGIC_REG_DIAG_RW_ADDRESS:
1681 {
1682 if (pThis->fDiagRegsEnabled)
1683 {
1684#ifndef IN_RING3
1685 return VINF_IOM_R3_MMIO_READ;
1686#else
1687 lsilogicR3DiagRegAddressRead(pThis, &u32);
1688#endif
1689 }
1690 }
1691 /* fall thru */
1692 case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */
1693 default: /* Ignore. */
1694 {
1695 /** @todo LSILOGIC_REG_DIAG_* should return all F's when accessed by MMIO. We
1696 * return 0. Likely to apply to undefined offsets as well. */
1697 break;
1698 }
1699 }
1700
1701 *pu32 = u32;
1702 LogFlowFunc(("pThis=%#p offReg=%#x u32=%#x\n", pThis, offReg, u32));
1703 return rc;
1704}
1705
1706/**
1707 * @callback_method_impl{FNIOMIOPORTOUT}
1708 */
1709PDMBOTHCBDECL(int) lsilogicIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)
1710{
1711 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1712 uint32_t offReg = uPort - pThis->IOPortBase;
1713 int rc;
1714 RT_NOREF2(pvUser, cb);
1715
1716 if (!(offReg & 3))
1717 {
1718 rc = lsilogicRegisterWrite(pThis, offReg, u32);
1719 if (rc == VINF_IOM_R3_MMIO_WRITE)
1720 rc = VINF_IOM_R3_IOPORT_WRITE;
1721 }
1722 else
1723 {
1724 Log(("lsilogicIOPortWrite: Ignoring misaligned write - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb));
1725 rc = VINF_SUCCESS;
1726 }
1727
1728 return rc;
1729}
1730
1731/**
1732 * @callback_method_impl{FNIOMIOPORTIN}
1733 */
1734PDMBOTHCBDECL(int) lsilogicIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)
1735{
1736 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1737 uint32_t offReg = uPort - pThis->IOPortBase;
1738 RT_NOREF_PV(pvUser);
1739 RT_NOREF_PV(cb);
1740
1741 int rc = lsilogicRegisterRead(pThis, offReg & ~(uint32_t)3, pu32);
1742 if (rc == VINF_IOM_R3_MMIO_READ)
1743 rc = VINF_IOM_R3_IOPORT_READ;
1744
1745 return rc;
1746}
1747
1748/**
1749 * @callback_method_impl{FNIOMMMIOWRITE}
1750 */
1751PDMBOTHCBDECL(int) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1752{
1753 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1754 uint32_t offReg = GCPhysAddr - pThis->GCPhysMMIOBase;
1755 uint32_t u32;
1756 int rc;
1757 RT_NOREF_PV(pvUser);
1758
1759 /* See comments in lsilogicR3Map regarding size and alignment. */
1760 if (cb == 4)
1761 u32 = *(uint32_t const *)pv;
1762 else
1763 {
1764 if (cb > 4)
1765 u32 = *(uint32_t const *)pv;
1766 else if (cb >= 2)
1767 u32 = *(uint16_t const *)pv;
1768 else
1769 u32 = *(uint8_t const *)pv;
1770 Log(("lsilogicMMIOWrite: Non-DWORD write access - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb));
1771 }
1772
1773 if (!(offReg & 3))
1774 rc = lsilogicRegisterWrite(pThis, offReg, u32);
1775 else
1776 {
1777 Log(("lsilogicIOPortWrite: Ignoring misaligned write - offReg=%#x u32=%#x cb=%#x\n", offReg, u32, cb));
1778 rc = VINF_SUCCESS;
1779 }
1780 return rc;
1781}
1782
1783/**
1784 * @callback_method_impl{FNIOMMMIOREAD}
1785 */
1786PDMBOTHCBDECL(int) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1787{
1788 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1789 uint32_t offReg = GCPhysAddr - pThis->GCPhysMMIOBase;
1790 Assert(!(offReg & 3)); Assert(cb == 4);
1791 RT_NOREF2(pvUser, cb);
1792
1793 return lsilogicRegisterRead(pThis, offReg, (uint32_t *)pv);
1794}
1795
1796PDMBOTHCBDECL(int) lsilogicDiagnosticWrite(PPDMDEVINS pDevIns, void *pvUser,
1797 RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
1798{
1799#ifdef LOG_ENABLED
1800 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1801 LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
1802#endif
1803
1804 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
1805 return VINF_SUCCESS;
1806}
1807
1808PDMBOTHCBDECL(int) lsilogicDiagnosticRead(PPDMDEVINS pDevIns, void *pvUser,
1809 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1810{
1811#ifdef LOG_ENABLED
1812 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1813 LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
1814#endif
1815
1816 RT_NOREF_PV(pDevIns); RT_NOREF_PV(pvUser); RT_NOREF_PV(GCPhysAddr); RT_NOREF_PV(pv); RT_NOREF_PV(cb);
1817 return VINF_SUCCESS;
1818}
1819
1820#ifdef IN_RING3
1821
1822# ifdef LOG_ENABLED
1823/**
1824 * Dump an SG entry.
1825 *
1826 * @returns nothing.
1827 * @param pSGEntry Pointer to the SG entry to dump
1828 */
1829static void lsilogicDumpSGEntry(PMptSGEntryUnion pSGEntry)
1830{
1831 if (LogIsEnabled())
1832 {
1833 switch (pSGEntry->Simple32.u2ElementType)
1834 {
1835 case MPTSGENTRYTYPE_SIMPLE:
1836 {
1837 Log(("%s: Dumping info for SIMPLE SG entry:\n", __FUNCTION__));
1838 Log(("%s: u24Length=%u\n", __FUNCTION__, pSGEntry->Simple32.u24Length));
1839 Log(("%s: fEndOfList=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfList));
1840 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.f64BitAddress));
1841 Log(("%s: fBufferContainsData=%d\n", __FUNCTION__, pSGEntry->Simple32.fBufferContainsData));
1842 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.fLocalAddress));
1843 Log(("%s: fEndOfBuffer=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfBuffer));
1844 Log(("%s: fLastElement=%d\n", __FUNCTION__, pSGEntry->Simple32.fLastElement));
1845 Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1846 if (pSGEntry->Simple32.f64BitAddress)
1847 {
1848 Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh));
1849 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__,
1850 ((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32)
1851 | pSGEntry->Simple64.u32DataBufferAddressLow));
1852 }
1853 else
1854 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1855
1856 break;
1857 }
1858 case MPTSGENTRYTYPE_CHAIN:
1859 {
1860 Log(("%s: Dumping info for CHAIN SG entry:\n", __FUNCTION__));
1861 Log(("%s: u16Length=%u\n", __FUNCTION__, pSGEntry->Chain.u16Length));
1862 Log(("%s: u8NExtChainOffset=%d\n", __FUNCTION__, pSGEntry->Chain.u8NextChainOffset));
1863 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Chain.f64BitAddress));
1864 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Chain.fLocalAddress));
1865 Log(("%s: u32SegmentAddressLow=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1866 Log(("%s: u32SegmentAddressHigh=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressHigh));
1867 if (pSGEntry->Chain.f64BitAddress)
1868 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__,
1869 ((uint64_t)pSGEntry->Chain.u32SegmentAddressHigh << 32) | pSGEntry->Chain.u32SegmentAddressLow));
1870 else
1871 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1872 break;
1873 }
1874 }
1875 }
1876}
1877# endif /* LOG_ENABLED */
1878
1879/**
1880 * Copy from guest to host memory worker.
1881 *
1882 * @copydoc LSILOGICR3MEMCOPYCALLBACK
1883 */
1884static DECLCALLBACK(void) lsilogicR3CopyBufferFromGuestWorker(PLSILOGICSCSI pThis, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
1885 size_t cbCopy, size_t *pcbSkip)
1886{
1887 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
1888 cbCopy -= cbSkipped;
1889 GCPhys += cbSkipped;
1890 *pcbSkip -= cbSkipped;
1891
1892 while (cbCopy)
1893 {
1894 size_t cbSeg = cbCopy;
1895 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
1896
1897 AssertPtr(pvSeg);
1898 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhys, pvSeg, cbSeg);
1899 GCPhys += cbSeg;
1900 cbCopy -= cbSeg;
1901 }
1902}
1903
1904/**
1905 * Copy from host to guest memory worker.
1906 *
1907 * @copydoc LSILOGICR3MEMCOPYCALLBACK
1908 */
1909static DECLCALLBACK(void) lsilogicR3CopyBufferToGuestWorker(PLSILOGICSCSI pThis, RTGCPHYS GCPhys, PRTSGBUF pSgBuf,
1910 size_t cbCopy, size_t *pcbSkip)
1911{
1912 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
1913 cbCopy -= cbSkipped;
1914 GCPhys += cbSkipped;
1915 *pcbSkip -= cbSkipped;
1916
1917 while (cbCopy)
1918 {
1919 size_t cbSeg = cbCopy;
1920 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
1921
1922 AssertPtr(pvSeg);
1923 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhys, pvSeg, cbSeg);
1924 GCPhys += cbSeg;
1925 cbCopy -= cbSeg;
1926 }
1927}
1928
1929/**
1930 * Walks the guest S/G buffer calling the given copy worker for every buffer.
1931 *
1932 * @returns The amout of bytes actually copied.
1933 * @param pThis Pointer to the LsiLogic device state.
1934 * @param pLsiReq LSI request state.
1935 * @param pfnCopyWorker The copy method to apply for each guest buffer.
1936 * @param pSgBuf The host S/G buffer.
1937 * @param cbSkip How many bytes to skip in advance before starting to copy.
1938 * @param cbCopy How many bytes to copy.
1939 */
1940static size_t lsilogicSgBufWalker(PLSILOGICSCSI pThis, PLSILOGICREQ pLsiReq,
1941 PLSILOGICR3MEMCOPYCALLBACK pfnCopyWorker,
1942 PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
1943{
1944 bool fEndOfList = false;
1945 RTGCPHYS GCPhysSgEntryNext = pLsiReq->GCPhysSgStart;
1946 RTGCPHYS GCPhysSegmentStart = pLsiReq->GCPhysSgStart;
1947 uint32_t cChainOffsetNext = pLsiReq->cChainOffset;
1948 PPDMDEVINS pDevIns = pThis->CTX_SUFF(pDevIns);
1949 size_t cbCopied = 0;
1950
1951 /*
1952 * Add the amount to skip to the host buffer size to avoid a
1953 * few conditionals later on.
1954 */
1955 cbCopy += cbSkip;
1956
1957 /* Go through the list until we reach the end. */
1958 while ( !fEndOfList
1959 && cbCopy)
1960 {
1961 bool fEndOfSegment = false;
1962
1963 while ( !fEndOfSegment
1964 && cbCopy)
1965 {
1966 MptSGEntryUnion SGEntry;
1967
1968 Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSgEntryNext));
1969
1970 /* Read the entry. */
1971 PDMDevHlpPhysRead(pDevIns, GCPhysSgEntryNext, &SGEntry, sizeof(MptSGEntryUnion));
1972
1973# ifdef LOG_ENABLED
1974 lsilogicDumpSGEntry(&SGEntry);
1975# endif
1976
1977 AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n"));
1978
1979 /* Check if this is a zero element and abort. */
1980 if ( !SGEntry.Simple32.u24Length
1981 && SGEntry.Simple32.fEndOfList
1982 && SGEntry.Simple32.fEndOfBuffer)
1983 return cbCopied - RT_MIN(cbSkip, cbCopied);
1984
1985 uint32_t cbCopyThis = SGEntry.Simple32.u24Length;
1986 RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow;
1987
1988 if (SGEntry.Simple32.f64BitAddress)
1989 {
1990 GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32;
1991 GCPhysSgEntryNext += sizeof(MptSGEntrySimple64);
1992 }
1993 else
1994 GCPhysSgEntryNext += sizeof(MptSGEntrySimple32);
1995
1996 pfnCopyWorker(pThis, GCPhysAddrDataBuffer, pSgBuf, cbCopyThis, &cbSkip);
1997 cbCopy -= cbCopyThis;
1998 cbCopied += cbCopyThis;
1999
2000 /* Check if we reached the end of the list. */
2001 if (SGEntry.Simple32.fEndOfList)
2002 {
2003 /* We finished. */
2004 fEndOfSegment = true;
2005 fEndOfList = true;
2006 }
2007 else if (SGEntry.Simple32.fLastElement)
2008 fEndOfSegment = true;
2009 } /* while (!fEndOfSegment) */
2010
2011 /* Get next chain element. */
2012 if (cChainOffsetNext)
2013 {
2014 MptSGEntryChain SGEntryChain;
2015
2016 PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + cChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
2017
2018 AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n"));
2019
2020 /* Set the next address now. */
2021 GCPhysSgEntryNext = SGEntryChain.u32SegmentAddressLow;
2022 if (SGEntryChain.f64BitAddress)
2023 GCPhysSgEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32;
2024
2025 GCPhysSegmentStart = GCPhysSgEntryNext;
2026 cChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t);
2027 }
2028 } /* while (!fEndOfList) */
2029
2030 return cbCopied - RT_MIN(cbSkip, cbCopied);
2031}
2032
2033/**
2034 * Copies a data buffer into the S/G buffer set up by the guest.
2035 *
2036 * @returns Amount of bytes copied to the guest.
2037 * @param pThis The LsiLogic controller device instance.
2038 * @param pReq Request structure.
2039 * @param pSgBuf The S/G buffer to copy from.
2040 * @param cbSkip How many bytes to skip in advance before starting to copy.
2041 * @param cbCopy How many bytes to copy.
2042 */
2043static size_t lsilogicR3CopySgBufToGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
2044 size_t cbSkip, size_t cbCopy)
2045{
2046 return lsilogicSgBufWalker(pThis, pReq, lsilogicR3CopyBufferToGuestWorker,
2047 pSgBuf, cbSkip, cbCopy);
2048}
2049
2050/**
2051 * Copies the guest S/G buffer into a host data buffer.
2052 *
2053 * @returns Amount of bytes copied from the guest.
2054 * @param pThis The LsiLogic controller device instance.
2055 * @param pReq Request structure.
2056 * @param pSgBuf The S/G buffer to copy into.
2057 * @param cbSkip How many bytes to skip in advance before starting to copy.
2058 * @param cbCopy How many bytes to copy.
2059 */
2060static size_t lsilogicR3CopySgBufFromGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
2061 size_t cbSkip, size_t cbCopy)
2062{
2063 return lsilogicSgBufWalker(pThis, pReq, lsilogicR3CopyBufferFromGuestWorker,
2064 pSgBuf, cbSkip, cbCopy);
2065}
2066
2067#if 0 /* unused */
2068/**
2069 * Copy a simple memory buffer to the guest memory buffer.
2070 *
2071 * @returns Amount of bytes copied to the guest.
2072 * @param pThis The LsiLogic controller device instance.
2073 * @param pReq Request structure.
2074 * @param pvSrc The buffer to copy from.
2075 * @param cbSrc How many bytes to copy.
2076 * @param cbSkip How many bytes to skip initially.
2077 */
2078static size_t lsilogicR3CopyBufferToGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, const void *pvSrc,
2079 size_t cbSrc, size_t cbSkip)
2080{
2081 RTSGSEG Seg;
2082 RTSGBUF SgBuf;
2083 Seg.pvSeg = (void *)pvSrc;
2084 Seg.cbSeg = cbSrc;
2085 RTSgBufInit(&SgBuf, &Seg, 1);
2086 return lsilogicR3CopySgBufToGuest(pThis, pReq, &SgBuf, cbSkip, cbSrc);
2087}
2088
2089/**
2090 * Copy a guest memry buffe into simple host memory buffer.
2091 *
2092 * @returns Amount of bytes copied to the guest.
2093 * @param pThis The LsiLogic controller device instance.
2094 * @param pReq Request structure.
2095 * @param pvSrc The buffer to copy from.
2096 * @param cbSrc How many bytes to copy.
2097 * @param cbSkip How many bytes to skip initially.
2098 */
2099static size_t lsilogicR3CopyBufferFromGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, void *pvDst,
2100 size_t cbDst, size_t cbSkip)
2101{
2102 RTSGSEG Seg;
2103 RTSGBUF SgBuf;
2104 Seg.pvSeg = (void *)pvDst;
2105 Seg.cbSeg = cbDst;
2106 RTSgBufInit(&SgBuf, &Seg, 1);
2107 return lsilogicR3CopySgBufFromGuest(pThis, pReq, &SgBuf, cbSkip, cbDst);
2108}
2109#endif
2110
2111# ifdef LOG_ENABLED
2112static void lsilogicR3DumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest)
2113{
2114 if (LogIsEnabled())
2115 {
2116 Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID));
2117 Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus));
2118 Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset));
2119 Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function));
2120 Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength));
2121 Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength));
2122 Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags));
2123 Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext));
2124 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++)
2125 Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i]));
2126 Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control));
2127 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++)
2128 Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i]));
2129 Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength));
2130 Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
2131 }
2132}
2133# endif
2134
2135/**
2136 * Handles the completion of th given request.
2137 *
2138 * @returns nothing.
2139 * @param pThis Pointer to the LsiLogic device state.
2140 * @param pReq The request to complete.
2141 * @param rcReq Status code of the request.
2142 */
2143static void lsilogicR3ReqComplete(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, int rcReq)
2144{
2145 PLSILOGICDEVICE pTgtDev = pReq->pTargetDevice;
2146
2147 if (RT_UNLIKELY(pReq->fBIOS))
2148 {
2149 uint8_t u8ScsiSts = pReq->u8ScsiSts;
2150 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2151 int rc = vboxscsiRequestFinished(&pThis->VBoxSCSI, u8ScsiSts);
2152 AssertMsgRC(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc));
2153 }
2154 else
2155 {
2156 RTGCPHYS GCPhysAddrSenseBuffer;
2157
2158 GCPhysAddrSenseBuffer = pReq->GuestRequest.SCSIIO.u32SenseBufferLowAddress;
2159 GCPhysAddrSenseBuffer |= ((uint64_t)pThis->u32SenseBufferHighAddr << 32);
2160
2161 /* Copy the sense buffer over. */
2162 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhysAddrSenseBuffer, pReq->abSenseBuffer,
2163 RT_UNLIKELY( pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2164 < sizeof(pReq->abSenseBuffer))
2165 ? pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2166 : sizeof(pReq->abSenseBuffer));
2167
2168 if (RT_SUCCESS(rcReq) && RT_LIKELY(pReq->u8ScsiSts == SCSI_STATUS_OK))
2169 {
2170 uint32_t u32MsgCtx = pReq->GuestRequest.SCSIIO.u32MessageContext;
2171
2172 /* Free the request before posting completion. */
2173 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2174 lsilogicR3FinishContextReply(pThis, u32MsgCtx);
2175 }
2176 else
2177 {
2178 MptReplyUnion IOCReply;
2179 RT_ZERO(IOCReply);
2180
2181 /* The SCSI target encountered an error during processing post a reply. */
2182 IOCReply.SCSIIOError.u8TargetID = pReq->GuestRequest.SCSIIO.u8TargetID;
2183 IOCReply.SCSIIOError.u8Bus = pReq->GuestRequest.SCSIIO.u8Bus;
2184 IOCReply.SCSIIOError.u8MessageLength = 8;
2185 IOCReply.SCSIIOError.u8Function = pReq->GuestRequest.SCSIIO.u8Function;
2186 IOCReply.SCSIIOError.u8CDBLength = pReq->GuestRequest.SCSIIO.u8CDBLength;
2187 IOCReply.SCSIIOError.u8SenseBufferLength = pReq->GuestRequest.SCSIIO.u8SenseBufferLength;
2188 IOCReply.SCSIIOError.u8MessageFlags = pReq->GuestRequest.SCSIIO.u8MessageFlags;
2189 IOCReply.SCSIIOError.u32MessageContext = pReq->GuestRequest.SCSIIO.u32MessageContext;
2190 IOCReply.SCSIIOError.u8SCSIStatus = pReq->u8ScsiSts;
2191 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID;
2192 IOCReply.SCSIIOError.u16IOCStatus = 0;
2193 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2194 IOCReply.SCSIIOError.u32TransferCount = 0;
2195 IOCReply.SCSIIOError.u32SenseCount = sizeof(pReq->abSenseBuffer);
2196 IOCReply.SCSIIOError.u32ResponseInfo = 0;
2197
2198 /* Free the request before posting completion. */
2199 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2200 lsilogicFinishAddressReply(pThis, &IOCReply, false);
2201 }
2202 }
2203
2204 ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
2205
2206 if (pTgtDev->cOutstandingRequests == 0 && pThis->fSignalIdle)
2207 PDMDevHlpAsyncNotificationCompleted(pThis->pDevInsR3);
2208}
2209
2210/**
2211 * Processes a SCSI I/O request by setting up the request
2212 * and sending it to the underlying SCSI driver.
2213 * Steps needed to complete request are done in the
2214 * callback called by the driver below upon completion of
2215 * the request.
2216 *
2217 * @returns VBox status code.
2218 * @param pThis Pointer to the LsiLogic device state.
2219 * @param GCPhysMessageFrameAddr Guest physical address where the request is located.
2220 * @param pGuestReq The request read fro th guest memory.
2221 */
2222static int lsilogicR3ProcessSCSIIORequest(PLSILOGICSCSI pThis, RTGCPHYS GCPhysMessageFrameAddr,
2223 PMptRequestUnion pGuestReq)
2224{
2225 MptReplyUnion IOCReply;
2226 int rc = VINF_SUCCESS;
2227
2228# ifdef LOG_ENABLED
2229 lsilogicR3DumpSCSIIORequest(&pGuestReq->SCSIIO);
2230# endif
2231
2232 if (RT_LIKELY( (pGuestReq->SCSIIO.u8TargetID < pThis->cDeviceStates)
2233 && (pGuestReq->SCSIIO.u8Bus == 0)))
2234 {
2235 PLSILOGICDEVICE pTgtDev = &pThis->paDeviceStates[pGuestReq->SCSIIO.u8TargetID];
2236
2237 if (pTgtDev->pDrvBase)
2238 {
2239 /* Allocate and prepare a new request. */
2240 PDMMEDIAEXIOREQ hIoReq;
2241 PLSILOGICREQ pLsiReq = NULL;
2242 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pLsiReq,
2243 pGuestReq->SCSIIO.u32MessageContext,
2244 PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
2245 if (RT_SUCCESS(rc))
2246 {
2247 pLsiReq->hIoReq = hIoReq;
2248 pLsiReq->pTargetDevice = pTgtDev;
2249 pLsiReq->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr;
2250 pLsiReq->fBIOS = false;
2251 pLsiReq->GCPhysSgStart = GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest);
2252 pLsiReq->cChainOffset = pGuestReq->SCSIIO.u8ChainOffset;
2253 if (pLsiReq->cChainOffset)
2254 pLsiReq->cChainOffset = pLsiReq->cChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest);
2255 memcpy(&pLsiReq->GuestRequest, pGuestReq, sizeof(MptRequestUnion));
2256 RT_BZERO(&pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer));
2257
2258 PDMMEDIAEXIOREQSCSITXDIR enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN;
2259 uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control);
2260
2261 if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE)
2262 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_NONE;
2263 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
2264 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE;
2265 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ)
2266 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
2267
2268 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2269 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pLsiReq->hIoReq, pLsiReq->GuestRequest.SCSIIO.au8LUN[1],
2270 &pLsiReq->GuestRequest.SCSIIO.au8CDB[0], pLsiReq->GuestRequest.SCSIIO.u8CDBLength,
2271 enmXferDir, pLsiReq->GuestRequest.SCSIIO.u32DataLength,
2272 &pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer), &pLsiReq->u8ScsiSts,
2273 30 * RT_MS_1SEC);
2274 if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
2275 lsilogicR3ReqComplete(pThis, pLsiReq, rc);
2276
2277 return VINF_SUCCESS;
2278 }
2279 else
2280 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
2281 }
2282 else
2283 {
2284 /* Device is not present report SCSI selection timeout. */
2285 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
2286 }
2287 }
2288 else
2289 {
2290 /* Report out of bounds target ID or bus. */
2291 if (pGuestReq->SCSIIO.u8Bus != 0)
2292 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS;
2293 else
2294 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID;
2295 }
2296
2297 static int g_cLogged = 0;
2298
2299 if (g_cLogged++ < MAX_REL_LOG_ERRORS)
2300 {
2301 LogRel(("LsiLogic#%d: %d/%d (Bus/Target) doesn't exist\n", pThis->CTX_SUFF(pDevIns)->iInstance,
2302 pGuestReq->SCSIIO.u8TargetID, pGuestReq->SCSIIO.u8Bus));
2303 /* Log the CDB too */
2304 LogRel(("LsiLogic#%d: Guest issued CDB {%#x",
2305 pThis->CTX_SUFF(pDevIns)->iInstance, pGuestReq->SCSIIO.au8CDB[0]));
2306 for (unsigned i = 1; i < pGuestReq->SCSIIO.u8CDBLength; i++)
2307 LogRel((", %#x", pGuestReq->SCSIIO.au8CDB[i]));
2308 LogRel(("}\n"));
2309 }
2310
2311 /* The rest is equal to both errors. */
2312 IOCReply.SCSIIOError.u8TargetID = pGuestReq->SCSIIO.u8TargetID;
2313 IOCReply.SCSIIOError.u8Bus = pGuestReq->SCSIIO.u8Bus;
2314 IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4;
2315 IOCReply.SCSIIOError.u8Function = pGuestReq->SCSIIO.u8Function;
2316 IOCReply.SCSIIOError.u8CDBLength = pGuestReq->SCSIIO.u8CDBLength;
2317 IOCReply.SCSIIOError.u8SenseBufferLength = pGuestReq->SCSIIO.u8SenseBufferLength;
2318 IOCReply.SCSIIOError.u32MessageContext = pGuestReq->SCSIIO.u32MessageContext;
2319 IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK;
2320 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED;
2321 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2322 IOCReply.SCSIIOError.u32TransferCount = 0;
2323 IOCReply.SCSIIOError.u32SenseCount = 0;
2324 IOCReply.SCSIIOError.u32ResponseInfo = 0;
2325
2326 lsilogicFinishAddressReply(pThis, &IOCReply, false);
2327
2328 return rc;
2329}
2330
2331
2332/**
2333 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2334 */
2335static DECLCALLBACK(int) lsilogicR3QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2336 uint32_t *piInstance, uint32_t *piLUN)
2337{
2338 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaPort);
2339 PPDMDEVINS pDevIns = pTgtDev->CTX_SUFF(pLsiLogic)->CTX_SUFF(pDevIns);
2340
2341 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2342 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2343 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2344
2345 *ppcszController = pDevIns->pReg->szName;
2346 *piInstance = pDevIns->iInstance;
2347 *piLUN = pTgtDev->iLUN;
2348
2349 return VINF_SUCCESS;
2350}
2351
2352
2353/**
2354 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
2355 */
2356static DECLCALLBACK(int) lsilogicR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2357 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
2358 size_t cbCopy)
2359{
2360 RT_NOREF1(hIoReq);
2361 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2362 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
2363
2364 size_t cbCopied = 0;
2365 if (RT_UNLIKELY(pReq->fBIOS))
2366 cbCopied = vboxscsiCopyToBuf(&pTgtDev->CTX_SUFF(pLsiLogic)->VBoxSCSI, pSgBuf, offDst, cbCopy);
2367 else
2368 cbCopied = lsilogicR3CopySgBufToGuest(pTgtDev->CTX_SUFF(pLsiLogic), pReq, pSgBuf, offDst, cbCopy);
2369 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
2370}
2371
2372/**
2373 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
2374 */
2375static DECLCALLBACK(int) lsilogicR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2376 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
2377 size_t cbCopy)
2378{
2379 RT_NOREF1(hIoReq);
2380 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2381 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
2382
2383 size_t cbCopied = 0;
2384 if (RT_UNLIKELY(pReq->fBIOS))
2385 cbCopied = vboxscsiCopyFromBuf(&pTgtDev->CTX_SUFF(pLsiLogic)->VBoxSCSI, pSgBuf, offSrc, cbCopy);
2386 else
2387 cbCopied = lsilogicR3CopySgBufFromGuest(pTgtDev->CTX_SUFF(pLsiLogic), pReq, pSgBuf, offSrc, cbCopy);
2388 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
2389}
2390
2391/**
2392 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
2393 */
2394static DECLCALLBACK(int) lsilogicR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2395 void *pvIoReqAlloc, int rcReq)
2396{
2397 RT_NOREF(hIoReq);
2398 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2399 lsilogicR3ReqComplete(pTgtDev->CTX_SUFF(pLsiLogic), (PLSILOGICREQ)pvIoReqAlloc, rcReq);
2400 return VINF_SUCCESS;
2401}
2402
2403/**
2404 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
2405 */
2406static DECLCALLBACK(void) lsilogicR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2407 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
2408{
2409 RT_NOREF3(hIoReq, pvIoReqAlloc, enmState);
2410 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2411
2412 switch (enmState)
2413 {
2414 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
2415 {
2416 /* Make sure the request is not accounted for so the VM can suspend successfully. */
2417 uint32_t cTasksActive = ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
2418 if (!cTasksActive && pTgtDev->CTX_SUFF(pLsiLogic)->fSignalIdle)
2419 PDMDevHlpAsyncNotificationCompleted(pTgtDev->CTX_SUFF(pLsiLogic)->pDevInsR3);
2420 break;
2421 }
2422 case PDMMEDIAEXIOREQSTATE_ACTIVE:
2423 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
2424 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2425 break;
2426 default:
2427 AssertMsgFailed(("Invalid request state given %u\n", enmState));
2428 }
2429}
2430
2431/**
2432 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
2433 */
2434static DECLCALLBACK(void) lsilogicR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
2435{
2436 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2437 PLSILOGICSCSI pThis = pTgtDev->CTX_SUFF(pLsiLogic);
2438
2439 if (pThis->pMediaNotify)
2440 {
2441 int rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pThis->CTX_SUFF(pDevIns)), VMCPUID_ANY,
2442 (PFNRT)pThis->pMediaNotify->pfnEjected, 2,
2443 pThis->pMediaNotify, pTgtDev->iLUN);
2444 AssertRC(rc);
2445 }
2446}
2447
2448
2449/**
2450 * Return the configuration page header and data
2451 * which matches the given page type and number.
2452 *
2453 * @returns VINF_SUCCESS if successful
2454 * VERR_NOT_FOUND if the requested page could be found.
2455 * @param pThis The LsiLogic controller instance data.
2456 * @param pPages The pages supported by the controller.
2457 * @param u8PageNumber Number of the page to get.
2458 * @param ppPageHeader Where to store the pointer to the page header.
2459 * @param ppbPageData Where to store the pointer to the page data.
2460 * @param pcbPage Where to store the size of the page data in bytes on success.
2461 */
2462static int lsilogicR3ConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pThis,
2463 PMptConfigurationPagesSupported pPages,
2464 uint8_t u8PageNumber,
2465 PMptConfigurationPageHeader *ppPageHeader,
2466 uint8_t **ppbPageData, size_t *pcbPage)
2467{
2468 RT_NOREF(pThis);
2469 int rc = VINF_SUCCESS;
2470
2471 AssertPtr(ppPageHeader); Assert(ppbPageData);
2472
2473 switch (u8PageNumber)
2474 {
2475 case 0:
2476 *ppPageHeader = &pPages->IOUnitPage0.u.fields.Header;
2477 *ppbPageData = pPages->IOUnitPage0.u.abPageData;
2478 *pcbPage = sizeof(pPages->IOUnitPage0);
2479 break;
2480 case 1:
2481 *ppPageHeader = &pPages->IOUnitPage1.u.fields.Header;
2482 *ppbPageData = pPages->IOUnitPage1.u.abPageData;
2483 *pcbPage = sizeof(pPages->IOUnitPage1);
2484 break;
2485 case 2:
2486 *ppPageHeader = &pPages->IOUnitPage2.u.fields.Header;
2487 *ppbPageData = pPages->IOUnitPage2.u.abPageData;
2488 *pcbPage = sizeof(pPages->IOUnitPage2);
2489 break;
2490 case 3:
2491 *ppPageHeader = &pPages->IOUnitPage3.u.fields.Header;
2492 *ppbPageData = pPages->IOUnitPage3.u.abPageData;
2493 *pcbPage = sizeof(pPages->IOUnitPage3);
2494 break;
2495 case 4:
2496 *ppPageHeader = &pPages->IOUnitPage4.u.fields.Header;
2497 *ppbPageData = pPages->IOUnitPage4.u.abPageData;
2498 *pcbPage = sizeof(pPages->IOUnitPage4);
2499 break;
2500 default:
2501 rc = VERR_NOT_FOUND;
2502 }
2503
2504 return rc;
2505}
2506
2507/**
2508 * Return the configuration page header and data
2509 * which matches the given page type and number.
2510 *
2511 * @returns VINF_SUCCESS if successful
2512 * VERR_NOT_FOUND if the requested page could be found.
2513 * @param pThis The LsiLogic controller instance data.
2514 * @param pPages The pages supported by the controller.
2515 * @param u8PageNumber Number of the page to get.
2516 * @param ppPageHeader Where to store the pointer to the page header.
2517 * @param ppbPageData Where to store the pointer to the page data.
2518 * @param pcbPage Where to store the size of the page data in bytes on success.
2519 */
2520static int lsilogicR3ConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pThis,
2521 PMptConfigurationPagesSupported pPages,
2522 uint8_t u8PageNumber,
2523 PMptConfigurationPageHeader *ppPageHeader,
2524 uint8_t **ppbPageData, size_t *pcbPage)
2525{
2526 RT_NOREF(pThis);
2527 int rc = VINF_SUCCESS;
2528
2529 AssertPtr(ppPageHeader); Assert(ppbPageData);
2530
2531 switch (u8PageNumber)
2532 {
2533 case 0:
2534 *ppPageHeader = &pPages->IOCPage0.u.fields.Header;
2535 *ppbPageData = pPages->IOCPage0.u.abPageData;
2536 *pcbPage = sizeof(pPages->IOCPage0);
2537 break;
2538 case 1:
2539 *ppPageHeader = &pPages->IOCPage1.u.fields.Header;
2540 *ppbPageData = pPages->IOCPage1.u.abPageData;
2541 *pcbPage = sizeof(pPages->IOCPage1);
2542 break;
2543 case 2:
2544 *ppPageHeader = &pPages->IOCPage2.u.fields.Header;
2545 *ppbPageData = pPages->IOCPage2.u.abPageData;
2546 *pcbPage = sizeof(pPages->IOCPage2);
2547 break;
2548 case 3:
2549 *ppPageHeader = &pPages->IOCPage3.u.fields.Header;
2550 *ppbPageData = pPages->IOCPage3.u.abPageData;
2551 *pcbPage = sizeof(pPages->IOCPage3);
2552 break;
2553 case 4:
2554 *ppPageHeader = &pPages->IOCPage4.u.fields.Header;
2555 *ppbPageData = pPages->IOCPage4.u.abPageData;
2556 *pcbPage = sizeof(pPages->IOCPage4);
2557 break;
2558 case 6:
2559 *ppPageHeader = &pPages->IOCPage6.u.fields.Header;
2560 *ppbPageData = pPages->IOCPage6.u.abPageData;
2561 *pcbPage = sizeof(pPages->IOCPage6);
2562 break;
2563 default:
2564 rc = VERR_NOT_FOUND;
2565 }
2566
2567 return rc;
2568}
2569
2570/**
2571 * Return the configuration page header and data
2572 * which matches the given page type and number.
2573 *
2574 * @returns VINF_SUCCESS if successful
2575 * VERR_NOT_FOUND if the requested page could be found.
2576 * @param pThis The LsiLogic controller instance data.
2577 * @param pPages The pages supported by the controller.
2578 * @param u8PageNumber Number of the page to get.
2579 * @param ppPageHeader Where to store the pointer to the page header.
2580 * @param ppbPageData Where to store the pointer to the page data.
2581 * @param pcbPage Where to store the size of the page data in bytes on success.
2582 */
2583static int lsilogicR3ConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pThis,
2584 PMptConfigurationPagesSupported pPages,
2585 uint8_t u8PageNumber,
2586 PMptConfigurationPageHeader *ppPageHeader,
2587 uint8_t **ppbPageData, size_t *pcbPage)
2588{
2589 int rc = VINF_SUCCESS;
2590
2591 AssertPtr(ppPageHeader); Assert(ppbPageData);
2592
2593 switch (u8PageNumber)
2594 {
2595 case 0:
2596 *ppPageHeader = &pPages->ManufacturingPage0.u.fields.Header;
2597 *ppbPageData = pPages->ManufacturingPage0.u.abPageData;
2598 *pcbPage = sizeof(pPages->ManufacturingPage0);
2599 break;
2600 case 1:
2601 *ppPageHeader = &pPages->ManufacturingPage1.u.fields.Header;
2602 *ppbPageData = pPages->ManufacturingPage1.u.abPageData;
2603 *pcbPage = sizeof(pPages->ManufacturingPage1);
2604 break;
2605 case 2:
2606 *ppPageHeader = &pPages->ManufacturingPage2.u.fields.Header;
2607 *ppbPageData = pPages->ManufacturingPage2.u.abPageData;
2608 *pcbPage = sizeof(pPages->ManufacturingPage2);
2609 break;
2610 case 3:
2611 *ppPageHeader = &pPages->ManufacturingPage3.u.fields.Header;
2612 *ppbPageData = pPages->ManufacturingPage3.u.abPageData;
2613 *pcbPage = sizeof(pPages->ManufacturingPage3);
2614 break;
2615 case 4:
2616 *ppPageHeader = &pPages->ManufacturingPage4.u.fields.Header;
2617 *ppbPageData = pPages->ManufacturingPage4.u.abPageData;
2618 *pcbPage = sizeof(pPages->ManufacturingPage4);
2619 break;
2620 case 5:
2621 *ppPageHeader = &pPages->ManufacturingPage5.u.fields.Header;
2622 *ppbPageData = pPages->ManufacturingPage5.u.abPageData;
2623 *pcbPage = sizeof(pPages->ManufacturingPage5);
2624 break;
2625 case 6:
2626 *ppPageHeader = &pPages->ManufacturingPage6.u.fields.Header;
2627 *ppbPageData = pPages->ManufacturingPage6.u.abPageData;
2628 *pcbPage = sizeof(pPages->ManufacturingPage6);
2629 break;
2630 case 7:
2631 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
2632 {
2633 *ppPageHeader = &pPages->u.SasPages.pManufacturingPage7->u.fields.Header;
2634 *ppbPageData = pPages->u.SasPages.pManufacturingPage7->u.abPageData;
2635 *pcbPage = pPages->u.SasPages.cbManufacturingPage7;
2636 }
2637 else
2638 rc = VERR_NOT_FOUND;
2639 break;
2640 case 8:
2641 *ppPageHeader = &pPages->ManufacturingPage8.u.fields.Header;
2642 *ppbPageData = pPages->ManufacturingPage8.u.abPageData;
2643 *pcbPage = sizeof(pPages->ManufacturingPage8);
2644 break;
2645 case 9:
2646 *ppPageHeader = &pPages->ManufacturingPage9.u.fields.Header;
2647 *ppbPageData = pPages->ManufacturingPage9.u.abPageData;
2648 *pcbPage = sizeof(pPages->ManufacturingPage9);
2649 break;
2650 case 10:
2651 *ppPageHeader = &pPages->ManufacturingPage10.u.fields.Header;
2652 *ppbPageData = pPages->ManufacturingPage10.u.abPageData;
2653 *pcbPage = sizeof(pPages->ManufacturingPage10);
2654 break;
2655 default:
2656 rc = VERR_NOT_FOUND;
2657 }
2658
2659 return rc;
2660}
2661
2662/**
2663 * Return the configuration page header and data
2664 * which matches the given page type and number.
2665 *
2666 * @returns VINF_SUCCESS if successful
2667 * VERR_NOT_FOUND if the requested page could be found.
2668 * @param pThis The LsiLogic controller instance data.
2669 * @param pPages The pages supported by the controller.
2670 * @param u8PageNumber Number of the page to get.
2671 * @param ppPageHeader Where to store the pointer to the page header.
2672 * @param ppbPageData Where to store the pointer to the page data.
2673 * @param pcbPage Where to store the size of the page data in bytes on success.
2674 */
2675static int lsilogicR3ConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pThis,
2676 PMptConfigurationPagesSupported pPages,
2677 uint8_t u8PageNumber,
2678 PMptConfigurationPageHeader *ppPageHeader,
2679 uint8_t **ppbPageData, size_t *pcbPage)
2680{
2681 RT_NOREF(pThis);
2682 int rc = VINF_SUCCESS;
2683
2684 AssertPtr(ppPageHeader); Assert(ppbPageData);
2685
2686 switch (u8PageNumber)
2687 {
2688 case 1:
2689 *ppPageHeader = &pPages->BIOSPage1.u.fields.Header;
2690 *ppbPageData = pPages->BIOSPage1.u.abPageData;
2691 *pcbPage = sizeof(pPages->BIOSPage1);
2692 break;
2693 case 2:
2694 *ppPageHeader = &pPages->BIOSPage2.u.fields.Header;
2695 *ppbPageData = pPages->BIOSPage2.u.abPageData;
2696 *pcbPage = sizeof(pPages->BIOSPage2);
2697 break;
2698 case 4:
2699 *ppPageHeader = &pPages->BIOSPage4.u.fields.Header;
2700 *ppbPageData = pPages->BIOSPage4.u.abPageData;
2701 *pcbPage = sizeof(pPages->BIOSPage4);
2702 break;
2703 default:
2704 rc = VERR_NOT_FOUND;
2705 }
2706
2707 return rc;
2708}
2709
2710/**
2711 * Return the configuration page header and data
2712 * which matches the given page type and number.
2713 *
2714 * @returns VINF_SUCCESS if successful
2715 * VERR_NOT_FOUND if the requested page could be found.
2716 * @param pThis The LsiLogic controller instance data.
2717 * @param pPages The pages supported by the controller.
2718 * @param u8Port The port to retrieve the page for.
2719 * @param u8PageNumber Number of the page to get.
2720 * @param ppPageHeader Where to store the pointer to the page header.
2721 * @param ppbPageData Where to store the pointer to the page data.
2722 * @param pcbPage Where to store the size of the page data in bytes on success.
2723 */
2724static int lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pThis,
2725 PMptConfigurationPagesSupported pPages,
2726 uint8_t u8Port,
2727 uint8_t u8PageNumber,
2728 PMptConfigurationPageHeader *ppPageHeader,
2729 uint8_t **ppbPageData, size_t *pcbPage)
2730{
2731 RT_NOREF(pThis);
2732 int rc = VINF_SUCCESS;
2733 AssertPtr(ppPageHeader); Assert(ppbPageData);
2734
2735
2736 if (u8Port >= RT_ELEMENTS(pPages->u.SpiPages.aPortPages))
2737 return VERR_NOT_FOUND;
2738
2739 switch (u8PageNumber)
2740 {
2741 case 0:
2742 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.fields.Header;
2743 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.abPageData;
2744 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0);
2745 break;
2746 case 1:
2747 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.fields.Header;
2748 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.abPageData;
2749 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1);
2750 break;
2751 case 2:
2752 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.fields.Header;
2753 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.abPageData;
2754 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2);
2755 break;
2756 default:
2757 rc = VERR_NOT_FOUND;
2758 }
2759
2760 return rc;
2761}
2762
2763/**
2764 * Return the configuration page header and data
2765 * which matches the given page type and number.
2766 *
2767 * @returns VINF_SUCCESS if successful
2768 * VERR_NOT_FOUND if the requested page could be found.
2769 * @param pThis The LsiLogic controller instance data.
2770 * @param pPages The pages supported by the controller.
2771 * @param u8Bus The bus the device is on the page should be returned.
2772 * @param u8TargetID The target ID of the device to return the page for.
2773 * @param u8PageNumber Number of the page to get.
2774 * @param ppPageHeader Where to store the pointer to the page header.
2775 * @param ppbPageData Where to store the pointer to the page data.
2776 * @param pcbPage Where to store the size of the page data in bytes on success.
2777 */
2778static int lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pThis,
2779 PMptConfigurationPagesSupported pPages,
2780 uint8_t u8Bus,
2781 uint8_t u8TargetID, uint8_t u8PageNumber,
2782 PMptConfigurationPageHeader *ppPageHeader,
2783 uint8_t **ppbPageData, size_t *pcbPage)
2784{
2785 RT_NOREF(pThis);
2786 int rc = VINF_SUCCESS;
2787 AssertPtr(ppPageHeader); Assert(ppbPageData);
2788
2789 if (u8Bus >= RT_ELEMENTS(pPages->u.SpiPages.aBuses))
2790 return VERR_NOT_FOUND;
2791
2792 if (u8TargetID >= RT_ELEMENTS(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages))
2793 return VERR_NOT_FOUND;
2794
2795 switch (u8PageNumber)
2796 {
2797 case 0:
2798 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
2799 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
2800 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0);
2801 break;
2802 case 1:
2803 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
2804 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
2805 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1);
2806 break;
2807 case 2:
2808 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
2809 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
2810 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2);
2811 break;
2812 case 3:
2813 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
2814 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
2815 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3);
2816 break;
2817 default:
2818 rc = VERR_NOT_FOUND;
2819 }
2820
2821 return rc;
2822}
2823
2824static int lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(PLSILOGICSCSI pThis,
2825 PMptConfigurationPagesSupported pPages,
2826 uint8_t u8PageNumber,
2827 PMptExtendedConfigurationPageHeader *ppPageHeader,
2828 uint8_t **ppbPageData, size_t *pcbPage)
2829{
2830 RT_NOREF(pThis);
2831 int rc = VINF_SUCCESS;
2832
2833 switch (u8PageNumber)
2834 {
2835 case 0:
2836 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage0->u.fields.ExtHeader;
2837 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage0->u.abPageData;
2838 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage0;
2839 break;
2840 case 1:
2841 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage1->u.fields.ExtHeader;
2842 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage1->u.abPageData;
2843 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage1;
2844 break;
2845 case 2:
2846 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage2.u.fields.ExtHeader;
2847 *ppbPageData = pPages->u.SasPages.SASIOUnitPage2.u.abPageData;
2848 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage2);
2849 break;
2850 case 3:
2851 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage3.u.fields.ExtHeader;
2852 *ppbPageData = pPages->u.SasPages.SASIOUnitPage3.u.abPageData;
2853 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage3);
2854 break;
2855 default:
2856 rc = VERR_NOT_FOUND;
2857 }
2858
2859 return rc;
2860}
2861
2862static int lsilogicR3ConfigurationSASPHYPageGetFromNumber(PLSILOGICSCSI pThis,
2863 PMptConfigurationPagesSupported pPages,
2864 uint8_t u8PageNumber,
2865 MptConfigurationPageAddress PageAddress,
2866 PMptExtendedConfigurationPageHeader *ppPageHeader,
2867 uint8_t **ppbPageData, size_t *pcbPage)
2868{
2869 RT_NOREF(pThis);
2870 int rc = VINF_SUCCESS;
2871 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2872 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
2873 PMptPHY pPHYPages = NULL;
2874
2875 Log(("Address form %d\n", uAddressForm));
2876
2877 if (uAddressForm == 0) /* PHY number */
2878 {
2879 uint8_t u8PhyNumber = PageAddress.SASPHY.Form0.u8PhyNumber;
2880
2881 Log(("PHY number %d\n", u8PhyNumber));
2882
2883 if (u8PhyNumber >= pPagesSas->cPHYs)
2884 return VERR_NOT_FOUND;
2885
2886 pPHYPages = &pPagesSas->paPHYs[u8PhyNumber];
2887 }
2888 else if (uAddressForm == 1) /* Index form */
2889 {
2890 uint16_t u16Index = PageAddress.SASPHY.Form1.u16Index;
2891
2892 Log(("PHY index %d\n", u16Index));
2893
2894 if (u16Index >= pPagesSas->cPHYs)
2895 return VERR_NOT_FOUND;
2896
2897 pPHYPages = &pPagesSas->paPHYs[u16Index];
2898 }
2899 else
2900 rc = VERR_NOT_FOUND; /* Correct? */
2901
2902 if (pPHYPages)
2903 {
2904 switch (u8PageNumber)
2905 {
2906 case 0:
2907 *ppPageHeader = &pPHYPages->SASPHYPage0.u.fields.ExtHeader;
2908 *ppbPageData = pPHYPages->SASPHYPage0.u.abPageData;
2909 *pcbPage = sizeof(pPHYPages->SASPHYPage0);
2910 break;
2911 case 1:
2912 *ppPageHeader = &pPHYPages->SASPHYPage1.u.fields.ExtHeader;
2913 *ppbPageData = pPHYPages->SASPHYPage1.u.abPageData;
2914 *pcbPage = sizeof(pPHYPages->SASPHYPage1);
2915 break;
2916 default:
2917 rc = VERR_NOT_FOUND;
2918 }
2919 }
2920 else
2921 rc = VERR_NOT_FOUND;
2922
2923 return rc;
2924}
2925
2926static int lsilogicR3ConfigurationSASDevicePageGetFromNumber(PLSILOGICSCSI pThis,
2927 PMptConfigurationPagesSupported pPages,
2928 uint8_t u8PageNumber,
2929 MptConfigurationPageAddress PageAddress,
2930 PMptExtendedConfigurationPageHeader *ppPageHeader,
2931 uint8_t **ppbPageData, size_t *pcbPage)
2932{
2933 RT_NOREF(pThis);
2934 int rc = VINF_SUCCESS;
2935 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2936 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
2937 PMptSASDevice pSASDevice = NULL;
2938
2939 Log(("Address form %d\n", uAddressForm));
2940
2941 if (uAddressForm == 0)
2942 {
2943 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
2944
2945 Log(("Get next handle %#x\n", u16Handle));
2946
2947 pSASDevice = pPagesSas->pSASDeviceHead;
2948
2949 /* Get the first device? */
2950 if (u16Handle != 0xffff)
2951 {
2952 /* No, search for the right one. */
2953
2954 while ( pSASDevice
2955 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
2956 pSASDevice = pSASDevice->pNext;
2957
2958 if (pSASDevice)
2959 pSASDevice = pSASDevice->pNext;
2960 }
2961 }
2962 else if (uAddressForm == 1)
2963 {
2964 uint8_t u8TargetID = PageAddress.SASDevice.Form1.u8TargetID;
2965 uint8_t u8Bus = PageAddress.SASDevice.Form1.u8Bus;
2966
2967 Log(("u8TargetID=%d u8Bus=%d\n", u8TargetID, u8Bus));
2968
2969 pSASDevice = pPagesSas->pSASDeviceHead;
2970
2971 while ( pSASDevice
2972 && ( pSASDevice->SASDevicePage0.u.fields.u8TargetID != u8TargetID
2973 || pSASDevice->SASDevicePage0.u.fields.u8Bus != u8Bus))
2974 pSASDevice = pSASDevice->pNext;
2975 }
2976 else if (uAddressForm == 2)
2977 {
2978 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
2979
2980 Log(("Handle %#x\n", u16Handle));
2981
2982 pSASDevice = pPagesSas->pSASDeviceHead;
2983
2984 while ( pSASDevice
2985 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
2986 pSASDevice = pSASDevice->pNext;
2987 }
2988
2989 if (pSASDevice)
2990 {
2991 switch (u8PageNumber)
2992 {
2993 case 0:
2994 *ppPageHeader = &pSASDevice->SASDevicePage0.u.fields.ExtHeader;
2995 *ppbPageData = pSASDevice->SASDevicePage0.u.abPageData;
2996 *pcbPage = sizeof(pSASDevice->SASDevicePage0);
2997 break;
2998 case 1:
2999 *ppPageHeader = &pSASDevice->SASDevicePage1.u.fields.ExtHeader;
3000 *ppbPageData = pSASDevice->SASDevicePage1.u.abPageData;
3001 *pcbPage = sizeof(pSASDevice->SASDevicePage1);
3002 break;
3003 case 2:
3004 *ppPageHeader = &pSASDevice->SASDevicePage2.u.fields.ExtHeader;
3005 *ppbPageData = pSASDevice->SASDevicePage2.u.abPageData;
3006 *pcbPage = sizeof(pSASDevice->SASDevicePage2);
3007 break;
3008 default:
3009 rc = VERR_NOT_FOUND;
3010 }
3011 }
3012 else
3013 rc = VERR_NOT_FOUND;
3014
3015 return rc;
3016}
3017
3018/**
3019 * Returns the extended configuration page header and data.
3020 * @returns VINF_SUCCESS if successful
3021 * VERR_NOT_FOUND if the requested page could be found.
3022 * @param pThis Pointer to the LsiLogic device state.
3023 * @param pConfigurationReq The configuration request.
3024 * @param ppPageHeader Where to return the pointer to the page header on success.
3025 * @param ppbPageData Where to store the pointer to the page data.
3026 * @param pcbPage Where to store the size of the page in bytes.
3027 */
3028static int lsilogicR3ConfigurationPageGetExtended(PLSILOGICSCSI pThis, PMptConfigurationRequest pConfigurationReq,
3029 PMptExtendedConfigurationPageHeader *ppPageHeader,
3030 uint8_t **ppbPageData, size_t *pcbPage)
3031{
3032 int rc = VINF_SUCCESS;
3033
3034 Log(("Extended page requested:\n"));
3035 Log(("u8ExtPageType=%#x\n", pConfigurationReq->u8ExtPageType));
3036 Log(("u8ExtPageLength=%d\n", pConfigurationReq->u16ExtPageLength));
3037
3038 switch (pConfigurationReq->u8ExtPageType)
3039 {
3040 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT:
3041 {
3042 rc = lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(pThis,
3043 pThis->pConfigurationPages,
3044 pConfigurationReq->u8PageNumber,
3045 ppPageHeader, ppbPageData, pcbPage);
3046 break;
3047 }
3048 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS:
3049 {
3050 rc = lsilogicR3ConfigurationSASPHYPageGetFromNumber(pThis,
3051 pThis->pConfigurationPages,
3052 pConfigurationReq->u8PageNumber,
3053 pConfigurationReq->PageAddress,
3054 ppPageHeader, ppbPageData, pcbPage);
3055 break;
3056 }
3057 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE:
3058 {
3059 rc = lsilogicR3ConfigurationSASDevicePageGetFromNumber(pThis,
3060 pThis->pConfigurationPages,
3061 pConfigurationReq->u8PageNumber,
3062 pConfigurationReq->PageAddress,
3063 ppPageHeader, ppbPageData, pcbPage);
3064 break;
3065 }
3066 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASEXPANDER: /* No expanders supported */
3067 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_ENCLOSURE: /* No enclosures supported */
3068 default:
3069 rc = VERR_NOT_FOUND;
3070 }
3071
3072 return rc;
3073}
3074
3075/**
3076 * Processes a Configuration request.
3077 *
3078 * @returns VBox status code.
3079 * @param pThis Pointer to the LsiLogic device state.
3080 * @param pConfigurationReq Pointer to the request structure.
3081 * @param pReply Pointer to the reply message frame
3082 */
3083static int lsilogicR3ProcessConfigurationRequest(PLSILOGICSCSI pThis, PMptConfigurationRequest pConfigurationReq,
3084 PMptConfigurationReply pReply)
3085{
3086 int rc = VINF_SUCCESS;
3087 uint8_t *pbPageData = NULL;
3088 PMptConfigurationPageHeader pPageHeader = NULL;
3089 PMptExtendedConfigurationPageHeader pExtPageHeader = NULL;
3090 uint8_t u8PageType;
3091 uint8_t u8PageAttribute;
3092 size_t cbPage = 0;
3093
3094 LogFlowFunc(("pThis=%#p\n", pThis));
3095
3096 u8PageType = MPT_CONFIGURATION_PAGE_TYPE_GET(pConfigurationReq->u8PageType);
3097 u8PageAttribute = MPT_CONFIGURATION_PAGE_ATTRIBUTE_GET(pConfigurationReq->u8PageType);
3098
3099 Log(("GuestRequest:\n"));
3100 Log(("u8Action=%#x\n", pConfigurationReq->u8Action));
3101 Log(("u8PageType=%#x\n", u8PageType));
3102 Log(("u8PageNumber=%d\n", pConfigurationReq->u8PageNumber));
3103 Log(("u8PageLength=%d\n", pConfigurationReq->u8PageLength));
3104 Log(("u8PageVersion=%d\n", pConfigurationReq->u8PageVersion));
3105
3106 /* Copy common bits from the request into the reply. */
3107 pReply->u8MessageLength = 6; /* 6 32bit D-Words. */
3108 pReply->u8Action = pConfigurationReq->u8Action;
3109 pReply->u8Function = pConfigurationReq->u8Function;
3110 pReply->u32MessageContext = pConfigurationReq->u32MessageContext;
3111
3112 switch (u8PageType)
3113 {
3114 case MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT:
3115 {
3116 /* Get the page data. */
3117 rc = lsilogicR3ConfigurationIOUnitPageGetFromNumber(pThis,
3118 pThis->pConfigurationPages,
3119 pConfigurationReq->u8PageNumber,
3120 &pPageHeader, &pbPageData, &cbPage);
3121 break;
3122 }
3123 case MPT_CONFIGURATION_PAGE_TYPE_IOC:
3124 {
3125 /* Get the page data. */
3126 rc = lsilogicR3ConfigurationIOCPageGetFromNumber(pThis,
3127 pThis->pConfigurationPages,
3128 pConfigurationReq->u8PageNumber,
3129 &pPageHeader, &pbPageData, &cbPage);
3130 break;
3131 }
3132 case MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING:
3133 {
3134 /* Get the page data. */
3135 rc = lsilogicR3ConfigurationManufacturingPageGetFromNumber(pThis,
3136 pThis->pConfigurationPages,
3137 pConfigurationReq->u8PageNumber,
3138 &pPageHeader, &pbPageData, &cbPage);
3139 break;
3140 }
3141 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT:
3142 {
3143 /* Get the page data. */
3144 rc = lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(pThis,
3145 pThis->pConfigurationPages,
3146 pConfigurationReq->PageAddress.MPIPortNumber.u8PortNumber,
3147 pConfigurationReq->u8PageNumber,
3148 &pPageHeader, &pbPageData, &cbPage);
3149 break;
3150 }
3151 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE:
3152 {
3153 /* Get the page data. */
3154 rc = lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(pThis,
3155 pThis->pConfigurationPages,
3156 pConfigurationReq->PageAddress.BusAndTargetId.u8Bus,
3157 pConfigurationReq->PageAddress.BusAndTargetId.u8TargetID,
3158 pConfigurationReq->u8PageNumber,
3159 &pPageHeader, &pbPageData, &cbPage);
3160 break;
3161 }
3162 case MPT_CONFIGURATION_PAGE_TYPE_BIOS:
3163 {
3164 rc = lsilogicR3ConfigurationBiosPageGetFromNumber(pThis,
3165 pThis->pConfigurationPages,
3166 pConfigurationReq->u8PageNumber,
3167 &pPageHeader, &pbPageData, &cbPage);
3168 break;
3169 }
3170 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED:
3171 {
3172 rc = lsilogicR3ConfigurationPageGetExtended(pThis,
3173 pConfigurationReq,
3174 &pExtPageHeader, &pbPageData, &cbPage);
3175 break;
3176 }
3177 default:
3178 rc = VERR_NOT_FOUND;
3179 }
3180
3181 if (rc == VERR_NOT_FOUND)
3182 {
3183 Log(("Page not found\n"));
3184 pReply->u8PageType = pConfigurationReq->u8PageType;
3185 pReply->u8PageNumber = pConfigurationReq->u8PageNumber;
3186 pReply->u8PageLength = pConfigurationReq->u8PageLength;
3187 pReply->u8PageVersion = pConfigurationReq->u8PageVersion;
3188 pReply->u16IOCStatus = MPT_IOCSTATUS_CONFIG_INVALID_PAGE;
3189 return VINF_SUCCESS;
3190 }
3191
3192 if (u8PageType == MPT_CONFIGURATION_PAGE_TYPE_EXTENDED)
3193 {
3194 pReply->u8PageType = pExtPageHeader->u8PageType;
3195 pReply->u8PageNumber = pExtPageHeader->u8PageNumber;
3196 pReply->u8PageVersion = pExtPageHeader->u8PageVersion;
3197 pReply->u8ExtPageType = pExtPageHeader->u8ExtPageType;
3198 pReply->u16ExtPageLength = pExtPageHeader->u16ExtPageLength;
3199
3200 for (int i = 0; i < pExtPageHeader->u16ExtPageLength; i++)
3201 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3202 }
3203 else
3204 {
3205 pReply->u8PageType = pPageHeader->u8PageType;
3206 pReply->u8PageNumber = pPageHeader->u8PageNumber;
3207 pReply->u8PageLength = pPageHeader->u8PageLength;
3208 pReply->u8PageVersion = pPageHeader->u8PageVersion;
3209
3210 for (int i = 0; i < pReply->u8PageLength; i++)
3211 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3212 }
3213
3214 /*
3215 * Don't use the scatter gather handling code as the configuration request always have only one
3216 * simple element.
3217 */
3218 switch (pConfigurationReq->u8Action)
3219 {
3220 case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT: /* Nothing to do. We are always using the defaults. */
3221 case MPT_CONFIGURATION_REQUEST_ACTION_HEADER:
3222 {
3223 /* Already copied above nothing to do. */
3224 break;
3225 }
3226 case MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM:
3227 case MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT:
3228 case MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT:
3229 {
3230 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3231 if (cbBuffer != 0)
3232 {
3233 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3234 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3235 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3236
3237 PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage));
3238 }
3239 break;
3240 }
3241 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT:
3242 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM:
3243 {
3244 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3245 if (cbBuffer != 0)
3246 {
3247 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3248 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3249 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3250
3251 LogFlow(("cbBuffer=%u cbPage=%u\n", cbBuffer, cbPage));
3252
3253 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysAddrPageBuffer, pbPageData,
3254 RT_MIN(cbBuffer, cbPage));
3255 }
3256 break;
3257 }
3258 default:
3259 AssertMsgFailed(("todo\n"));
3260 }
3261
3262 return VINF_SUCCESS;
3263}
3264
3265/**
3266 * Initializes the configuration pages for the SPI SCSI controller.
3267 *
3268 * @returns nothing
3269 * @param pThis Pointer to the LsiLogic device state.
3270 */
3271static void lsilogicR3InitializeConfigurationPagesSpi(PLSILOGICSCSI pThis)
3272{
3273 PMptConfigurationPagesSpi pPages = &pThis->pConfigurationPages->u.SpiPages;
3274
3275 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n"));
3276
3277 LogFlowFunc(("pThis=%#p\n", pThis));
3278
3279 /* Clear everything first. */
3280 memset(pPages, 0, sizeof(MptConfigurationPagesSpi));
3281
3282 for (unsigned i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++)
3283 {
3284 /* SCSI-SPI port page 0. */
3285 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3286 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3287 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageNumber = 0;
3288 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
3289 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fInformationUnitTransfersCapable = true;
3290 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fDTCapable = true;
3291 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fQASCapable = true;
3292 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MinimumSynchronousTransferPeriod = 0;
3293 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MaximumSynchronousOffset = 0xff;
3294 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fWide = true;
3295 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fAIPCapable = true;
3296 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u2SignalingType = 0x3; /* Single Ended. */
3297
3298 /* SCSI-SPI port page 1. */
3299 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3300 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3301 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageNumber = 1;
3302 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
3303 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u8SCSIID = 7;
3304 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u16PortResponseIDsBitmask = (1 << 7);
3305 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u32OnBusTimerValue = 0;
3306
3307 /* SCSI-SPI port page 2. */
3308 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3309 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3310 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageNumber = 2;
3311 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
3312 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u4HostSCSIID = 7;
3313 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u2InitializeHBA = 0x3;
3314 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.fTerminationDisabled = true;
3315 for (unsigned iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++)
3316 {
3317 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings[iDevice].fBootChoice = true;
3318 }
3319 /* Everything else 0 for now. */
3320 }
3321
3322 for (unsigned uBusCurr = 0; uBusCurr < RT_ELEMENTS(pPages->aBuses); uBusCurr++)
3323 {
3324 for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
3325 {
3326 /* SCSI-SPI device page 0. */
3327 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3328 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3329 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
3330 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
3331 /* Everything else 0 for now. */
3332
3333 /* SCSI-SPI device page 1. */
3334 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3335 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3336 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
3337 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
3338 /* Everything else 0 for now. */
3339
3340 /* SCSI-SPI device page 2. */
3341 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3342 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3343 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
3344 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
3345 /* Everything else 0 for now. */
3346
3347 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3348 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3349 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
3350 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
3351 /* Everything else 0 for now. */
3352 }
3353 }
3354}
3355
3356/**
3357 * Generates a handle.
3358 *
3359 * @returns the handle.
3360 * @param pThis Pointer to the LsiLogic device state.
3361 */
3362DECLINLINE(uint16_t) lsilogicGetHandle(PLSILOGICSCSI pThis)
3363{
3364 uint16_t u16Handle = pThis->u16NextHandle++;
3365 return u16Handle;
3366}
3367
3368/**
3369 * Generates a SAS address (WWID)
3370 *
3371 * @returns nothing.
3372 * @param pSASAddress Pointer to an unitialised SAS address.
3373 * @param iId iId which will go into the address.
3374 *
3375 * @todo Generate better SAS addresses. (Request a block from SUN probably)
3376 */
3377void lsilogicSASAddressGenerate(PSASADDRESS pSASAddress, unsigned iId)
3378{
3379 pSASAddress->u8Address[0] = (0x5 << 5);
3380 pSASAddress->u8Address[1] = 0x01;
3381 pSASAddress->u8Address[2] = 0x02;
3382 pSASAddress->u8Address[3] = 0x03;
3383 pSASAddress->u8Address[4] = 0x04;
3384 pSASAddress->u8Address[5] = 0x05;
3385 pSASAddress->u8Address[6] = 0x06;
3386 pSASAddress->u8Address[7] = iId;
3387}
3388
3389/**
3390 * Initializes the configuration pages for the SAS SCSI controller.
3391 *
3392 * @returns nothing
3393 * @param pThis Pointer to the LsiLogic device state.
3394 */
3395static void lsilogicR3InitializeConfigurationPagesSas(PLSILOGICSCSI pThis)
3396{
3397 PMptConfigurationPagesSas pPages = &pThis->pConfigurationPages->u.SasPages;
3398
3399 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS, ("Controller is not the SAS SCSI one\n"));
3400
3401 LogFlowFunc(("pThis=%#p\n", pThis));
3402
3403 /* Manufacturing Page 7 - Connector settings. */
3404 pPages->cbManufacturingPage7 = LSILOGICSCSI_MANUFACTURING7_GET_SIZE(pThis->cPorts);
3405 PMptConfigurationPageManufacturing7 pManufacturingPage7 = (PMptConfigurationPageManufacturing7)RTMemAllocZ(pPages->cbManufacturingPage7);
3406 AssertPtr(pManufacturingPage7);
3407 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pManufacturingPage7,
3408 0, 7,
3409 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3410 /* Set size manually. */
3411 if (pPages->cbManufacturingPage7 / 4 > 255)
3412 pManufacturingPage7->u.fields.Header.u8PageLength = 255;
3413 else
3414 pManufacturingPage7->u.fields.Header.u8PageLength = pPages->cbManufacturingPage7 / 4;
3415 pManufacturingPage7->u.fields.u8NumPhys = pThis->cPorts;
3416 pPages->pManufacturingPage7 = pManufacturingPage7;
3417
3418 /* SAS I/O unit page 0 - Port specific information. */
3419 pPages->cbSASIOUnitPage0 = LSILOGICSCSI_SASIOUNIT0_GET_SIZE(pThis->cPorts);
3420 PMptConfigurationPageSASIOUnit0 pSASPage0 = (PMptConfigurationPageSASIOUnit0)RTMemAllocZ(pPages->cbSASIOUnitPage0);
3421 AssertPtr(pSASPage0);
3422
3423 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage0, pPages->cbSASIOUnitPage0,
3424 0, MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY,
3425 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3426 pSASPage0->u.fields.u8NumPhys = pThis->cPorts;
3427 pPages->pSASIOUnitPage0 = pSASPage0;
3428
3429 /* SAS I/O unit page 1 - Port specific settings. */
3430 pPages->cbSASIOUnitPage1 = LSILOGICSCSI_SASIOUNIT1_GET_SIZE(pThis->cPorts);
3431 PMptConfigurationPageSASIOUnit1 pSASPage1 = (PMptConfigurationPageSASIOUnit1)RTMemAllocZ(pPages->cbSASIOUnitPage1);
3432 AssertPtr(pSASPage1);
3433
3434 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage1, pPages->cbSASIOUnitPage1,
3435 1, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE,
3436 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3437 pSASPage1->u.fields.u8NumPhys = pSASPage0->u.fields.u8NumPhys;
3438 pSASPage1->u.fields.u16ControlFlags = 0;
3439 pSASPage1->u.fields.u16AdditionalControlFlags = 0;
3440 pPages->pSASIOUnitPage1 = pSASPage1;
3441
3442 /* SAS I/O unit page 2 - Port specific information. */
3443 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3444 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3445 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageNumber = 2;
3446 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3447 pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit2) / 4;
3448
3449 /* SAS I/O unit page 3 - Port specific information. */
3450 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3451 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3452 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageNumber = 3;
3453 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3454 pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit3) / 4;
3455
3456 pPages->cPHYs = pThis->cPorts;
3457 pPages->paPHYs = (PMptPHY)RTMemAllocZ(pPages->cPHYs * sizeof(MptPHY));
3458 AssertPtr(pPages->paPHYs);
3459
3460 /* Initialize the PHY configuration */
3461 for (unsigned i = 0; i < pThis->cPorts; i++)
3462 {
3463 PMptPHY pPHYPages = &pPages->paPHYs[i];
3464 uint16_t u16ControllerHandle = lsilogicGetHandle(pThis);
3465
3466 pManufacturingPage7->u.fields.aPHY[i].u8Location = LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO;
3467
3468 pSASPage0->u.fields.aPHY[i].u8Port = i;
3469 pSASPage0->u.fields.aPHY[i].u8PortFlags = 0;
3470 pSASPage0->u.fields.aPHY[i].u8PhyFlags = 0;
3471 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED;
3472 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3473 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16ControllerHandle;
3474 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = 0; /* No device attached. */
3475 pSASPage0->u.fields.aPHY[i].u32DiscoveryStatus = 0; /* No errors */
3476
3477 pSASPage1->u.fields.aPHY[i].u8Port = i;
3478 pSASPage1->u.fields.aPHY[i].u8PortFlags = 0;
3479 pSASPage1->u.fields.aPHY[i].u8PhyFlags = 0;
3480 pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3481 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3482 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3483
3484 /* SAS PHY page 0. */
3485 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3486 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3487 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageNumber = 0;
3488 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3489 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY0) / 4;
3490 pPHYPages->SASPHYPage0.u.fields.u8AttachedPhyIdentifier = i;
3491 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
3492 pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3493 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3494 pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3495 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3496
3497 /* SAS PHY page 1. */
3498 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3499 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3500 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageNumber = 1;
3501 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3502 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY1) / 4;
3503
3504 /* Settings for present devices. */
3505 if (pThis->paDeviceStates[i].pDrvBase)
3506 {
3507 uint16_t u16DeviceHandle = lsilogicGetHandle(pThis);
3508 SASADDRESS SASAddress;
3509 PMptSASDevice pSASDevice = (PMptSASDevice)RTMemAllocZ(sizeof(MptSASDevice));
3510 AssertPtr(pSASDevice);
3511
3512 memset(&SASAddress, 0, sizeof(SASADDRESS));
3513 lsilogicSASAddressGenerate(&SASAddress, i);
3514
3515 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
3516 pSASPage0->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].u16AttachedDevHandle = u16DeviceHandle;
3519 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3520 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3521 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16DeviceHandle;
3522
3523 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
3524 pPHYPages->SASPHYPage0.u.fields.SASAddress = SASAddress;
3525 pPHYPages->SASPHYPage0.u.fields.u16OwnerDevHandle = u16DeviceHandle;
3526 pPHYPages->SASPHYPage0.u.fields.u16AttachedDevHandle = u16DeviceHandle;
3527
3528 /* SAS device page 0. */
3529 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3530 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3531 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageNumber = 0;
3532 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3533 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice0) / 4;
3534 pSASDevice->SASDevicePage0.u.fields.SASAddress = SASAddress;
3535 pSASDevice->SASDevicePage0.u.fields.u16ParentDevHandle = u16ControllerHandle;
3536 pSASDevice->SASDevicePage0.u.fields.u8PhyNum = i;
3537 pSASDevice->SASDevicePage0.u.fields.u8AccessStatus = LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS;
3538 pSASDevice->SASDevicePage0.u.fields.u16DevHandle = u16DeviceHandle;
3539 pSASDevice->SASDevicePage0.u.fields.u8TargetID = i;
3540 pSASDevice->SASDevicePage0.u.fields.u8Bus = 0;
3541 pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
3542 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3543 pSASDevice->SASDevicePage0.u.fields.u16Flags = LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT
3544 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID
3545 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT;
3546 pSASDevice->SASDevicePage0.u.fields.u8PhysicalPort = i;
3547
3548 /* SAS device page 1. */
3549 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3550 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3551 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageNumber = 1;
3552 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3553 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice1) / 4;
3554 pSASDevice->SASDevicePage1.u.fields.SASAddress = SASAddress;
3555 pSASDevice->SASDevicePage1.u.fields.u16DevHandle = u16DeviceHandle;
3556 pSASDevice->SASDevicePage1.u.fields.u8TargetID = i;
3557 pSASDevice->SASDevicePage1.u.fields.u8Bus = 0;
3558
3559 /* SAS device page 2. */
3560 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3561 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3562 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageNumber = 2;
3563 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3564 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice2) / 4;
3565 pSASDevice->SASDevicePage2.u.fields.SASAddress = SASAddress;
3566
3567 /* Link into device list. */
3568 if (!pPages->cDevices)
3569 {
3570 pPages->pSASDeviceHead = pSASDevice;
3571 pPages->pSASDeviceTail = pSASDevice;
3572 pPages->cDevices = 1;
3573 }
3574 else
3575 {
3576 pSASDevice->pPrev = pPages->pSASDeviceTail;
3577 pPages->pSASDeviceTail->pNext = pSASDevice;
3578 pPages->pSASDeviceTail = pSASDevice;
3579 pPages->cDevices++;
3580 }
3581 }
3582 }
3583}
3584
3585/**
3586 * Initializes the configuration pages.
3587 *
3588 * @returns nothing
3589 * @param pThis Pointer to the LsiLogic device state.
3590 */
3591static void lsilogicR3InitializeConfigurationPages(PLSILOGICSCSI pThis)
3592{
3593 /* Initialize the common pages. */
3594 PMptConfigurationPagesSupported pPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported));
3595
3596 pThis->pConfigurationPages = pPages;
3597
3598 LogFlowFunc(("pThis=%#p\n", pThis));
3599
3600 /* Clear everything first. */
3601 memset(pPages, 0, sizeof(MptConfigurationPagesSupported));
3602
3603 /* Manufacturing Page 0. */
3604 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage0,
3605 MptConfigurationPageManufacturing0, 0,
3606 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3607 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipName, "VBox MPT Fusion", 16);
3608 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipRevision, "1.0", 8);
3609 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardName, "VBox MPT Fusion", 16);
3610 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardAssembly, "SUN", 8);
3611 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardTracerNumber, "CAFECAFECAFECAFE", 16);
3612
3613 /* Manufacturing Page 1 - I don't know what this contains so we leave it 0 for now. */
3614 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage1,
3615 MptConfigurationPageManufacturing1, 1,
3616 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3617
3618 /* Manufacturing Page 2. */
3619 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage2,
3620 MptConfigurationPageManufacturing2, 2,
3621 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3622
3623 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3624 {
3625 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3626 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3627 }
3628 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3629 {
3630 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3631 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3632 }
3633
3634 /* Manufacturing Page 3. */
3635 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage3,
3636 MptConfigurationPageManufacturing3, 3,
3637 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3638
3639 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3640 {
3641 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3642 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3643 }
3644 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3645 {
3646 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3647 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3648 }
3649
3650 /* Manufacturing Page 4 - I don't know what this contains so we leave it 0 for now. */
3651 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage4,
3652 MptConfigurationPageManufacturing4, 4,
3653 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3654
3655 /* Manufacturing Page 5 - WWID settings. */
3656 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage5,
3657 MptConfigurationPageManufacturing5, 5,
3658 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3659
3660 /* Manufacturing Page 6 - Product specific settings. */
3661 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage6,
3662 MptConfigurationPageManufacturing6, 6,
3663 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3664
3665 /* Manufacturing Page 8 - Product specific settings. */
3666 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage8,
3667 MptConfigurationPageManufacturing8, 8,
3668 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3669
3670 /* Manufacturing Page 9 - Product specific settings. */
3671 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage9,
3672 MptConfigurationPageManufacturing9, 9,
3673 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3674
3675 /* Manufacturing Page 10 - Product specific settings. */
3676 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage10,
3677 MptConfigurationPageManufacturing10, 10,
3678 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3679
3680 /* I/O Unit page 0. */
3681 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage0,
3682 MptConfigurationPageIOUnit0, 0,
3683 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3684 pPages->IOUnitPage0.u.fields.u64UniqueIdentifier = 0xcafe;
3685
3686 /* I/O Unit page 1. */
3687 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage1,
3688 MptConfigurationPageIOUnit1, 1,
3689 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3690 pPages->IOUnitPage1.u.fields.fSingleFunction = true;
3691 pPages->IOUnitPage1.u.fields.fAllPathsMapped = false;
3692 pPages->IOUnitPage1.u.fields.fIntegratedRAIDDisabled = true;
3693 pPages->IOUnitPage1.u.fields.f32BitAccessForced = false;
3694
3695 /* I/O Unit page 2. */
3696 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage2,
3697 MptConfigurationPageIOUnit2, 2,
3698 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT);
3699 pPages->IOUnitPage2.u.fields.fPauseOnError = false;
3700 pPages->IOUnitPage2.u.fields.fVerboseModeEnabled = false;
3701 pPages->IOUnitPage2.u.fields.fDisableColorVideo = false;
3702 pPages->IOUnitPage2.u.fields.fNotHookInt40h = false;
3703 pPages->IOUnitPage2.u.fields.u32BIOSVersion = 0xcafecafe;
3704 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true;
3705 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true;
3706 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0;
3707 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pThis->PciDev.uDevFn;
3708
3709 /* I/O Unit page 3. */
3710 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
3711 MptConfigurationPageIOUnit3, 3,
3712 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3713 pPages->IOUnitPage3.u.fields.u8GPIOCount = 0;
3714
3715 /* I/O Unit page 4. */
3716 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage4,
3717 MptConfigurationPageIOUnit4, 4,
3718 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3719
3720 /* IOC page 0. */
3721 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage0,
3722 MptConfigurationPageIOC0, 0,
3723 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3724 pPages->IOCPage0.u.fields.u32TotalNVStore = 0;
3725 pPages->IOCPage0.u.fields.u32FreeNVStore = 0;
3726
3727 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3728 {
3729 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3730 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3731 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3732 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SPI_CLASS_CODE;
3733 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID;
3734 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID;
3735 }
3736 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3737 {
3738 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3739 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3740 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3741 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SAS_CLASS_CODE;
3742 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID;
3743 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID;
3744 }
3745
3746 /* IOC page 1. */
3747 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage1,
3748 MptConfigurationPageIOC1, 1,
3749 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3750 pPages->IOCPage1.u.fields.fReplyCoalescingEnabled = false;
3751 pPages->IOCPage1.u.fields.u32CoalescingTimeout = 0;
3752 pPages->IOCPage1.u.fields.u8CoalescingDepth = 0;
3753
3754 /* IOC page 2. */
3755 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage2,
3756 MptConfigurationPageIOC2, 2,
3757 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3758 /* Everything else here is 0. */
3759
3760 /* IOC page 3. */
3761 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage3,
3762 MptConfigurationPageIOC3, 3,
3763 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3764 /* Everything else here is 0. */
3765
3766 /* IOC page 4. */
3767 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage4,
3768 MptConfigurationPageIOC4, 4,
3769 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3770 /* Everything else here is 0. */
3771
3772 /* IOC page 6. */
3773 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage6,
3774 MptConfigurationPageIOC6, 6,
3775 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3776 /* Everything else here is 0. */
3777
3778 /* BIOS page 1. */
3779 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage1,
3780 MptConfigurationPageBIOS1, 1,
3781 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3782
3783 /* BIOS page 2. */
3784 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage2,
3785 MptConfigurationPageBIOS2, 2,
3786 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3787
3788 /* BIOS page 4. */
3789 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage4,
3790 MptConfigurationPageBIOS4, 4,
3791 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3792
3793 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3794 lsilogicR3InitializeConfigurationPagesSpi(pThis);
3795 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3796 lsilogicR3InitializeConfigurationPagesSas(pThis);
3797 else
3798 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
3799}
3800
3801/**
3802 * @callback_method_impl{FNPDMQUEUEDEV, Transmit queue consumer.}
3803 */
3804static DECLCALLBACK(bool) lsilogicR3NotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
3805{
3806 RT_NOREF(pItem);
3807 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3808 int rc = VINF_SUCCESS;
3809
3810 LogFlowFunc(("pDevIns=%#p pItem=%#p\n", pDevIns, pItem));
3811
3812 rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess);
3813 AssertRC(rc);
3814
3815 return true;
3816}
3817
3818/**
3819 * Sets the emulated controller type from a given string.
3820 *
3821 * @returns VBox status code.
3822 *
3823 * @param pThis Pointer to the LsiLogic device state.
3824 * @param pcszCtrlType The string to use.
3825 */
3826static int lsilogicR3GetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType)
3827{
3828 int rc = VERR_INVALID_PARAMETER;
3829
3830 if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME))
3831 {
3832 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SPI;
3833 rc = VINF_SUCCESS;
3834 }
3835 else if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SAS_CTRLNAME))
3836 {
3837 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SAS;
3838 rc = VINF_SUCCESS;
3839 }
3840
3841 return rc;
3842}
3843
3844/**
3845 * @callback_method_impl{FNIOMIOPORTIN, Legacy ISA port.}
3846 */
3847static DECLCALLBACK(int) lsilogicR3IsaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3848{
3849 RT_NOREF(pvUser, cb);
3850 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3851
3852 Assert(cb == 1);
3853
3854 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3855 ? Port - LSILOGIC_BIOS_IO_PORT
3856 : Port - LSILOGIC_SAS_BIOS_IO_PORT;
3857 int rc = vboxscsiReadRegister(&pThis->VBoxSCSI, iRegister, pu32);
3858
3859 Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n",
3860 __FUNCTION__, pu32, 1, pu32, iRegister, rc));
3861
3862 return rc;
3863}
3864
3865/**
3866 * Prepares a request from the BIOS.
3867 *
3868 * @returns VBox status code.
3869 * @param pThis Pointer to the LsiLogic device state.
3870 */
3871static int lsilogicR3PrepareBiosScsiRequest(PLSILOGICSCSI pThis)
3872{
3873 int rc;
3874 uint32_t uTargetDevice;
3875 uint32_t uLun;
3876 uint8_t *pbCdb;
3877 size_t cbCdb;
3878 size_t cbBuf;
3879
3880 rc = vboxscsiSetupRequest(&pThis->VBoxSCSI, &uLun, &pbCdb, &cbCdb, &cbBuf, &uTargetDevice);
3881 AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc);
3882
3883 if ( uTargetDevice < pThis->cDeviceStates
3884 && pThis->paDeviceStates[uTargetDevice].pDrvBase)
3885 {
3886 PLSILOGICDEVICE pTgtDev = &pThis->paDeviceStates[uTargetDevice];
3887 PDMMEDIAEXIOREQ hIoReq;
3888 PLSILOGICREQ pReq;
3889
3890 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pReq,
3891 0, PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
3892 AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc);
3893
3894 pReq->fBIOS = true;
3895 pReq->hIoReq = hIoReq;
3896 pReq->pTargetDevice = pTgtDev;
3897
3898 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
3899
3900 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pReq->hIoReq, uLun,
3901 pbCdb, cbCdb, PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN,
3902 cbBuf, NULL, 0, &pReq->u8ScsiSts, 30 * RT_MS_1SEC);
3903 if (rc == VINF_SUCCESS || rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3904 {
3905 uint8_t u8ScsiSts = pReq->u8ScsiSts;
3906 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
3907 rc = vboxscsiRequestFinished(&pThis->VBoxSCSI, u8ScsiSts);
3908 }
3909 else if (rc == VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3910 rc = VINF_SUCCESS;
3911
3912 return rc;
3913 }
3914
3915 /* Device is not present. */
3916 AssertMsg(pbCdb[0] == SCSI_INQUIRY,
3917 ("Device is not present but command is not inquiry\n"));
3918
3919 SCSIINQUIRYDATA ScsiInquiryData;
3920
3921 memset(&ScsiInquiryData, 0, sizeof(SCSIINQUIRYDATA));
3922 ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
3923 ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
3924
3925 memcpy(pThis->VBoxSCSI.pbBuf, &ScsiInquiryData, 5);
3926
3927 rc = vboxscsiRequestFinished(&pThis->VBoxSCSI, SCSI_STATUS_OK);
3928 AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc);
3929
3930 return rc;
3931}
3932
3933/**
3934 * @callback_method_impl{FNIOMIOPORTOUT, Legacy ISA port.}
3935 */
3936static DECLCALLBACK(int) lsilogicR3IsaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3937{
3938 RT_NOREF(pvUser, cb);
3939 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3940 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port));
3941
3942 Assert(cb == 1);
3943
3944 /*
3945 * If there is already a request form the BIOS pending ignore this write
3946 * because it should not happen.
3947 */
3948 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
3949 return VINF_SUCCESS;
3950
3951 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3952 ? Port - LSILOGIC_BIOS_IO_PORT
3953 : Port - LSILOGIC_SAS_BIOS_IO_PORT;
3954 int rc = vboxscsiWriteRegister(&pThis->VBoxSCSI, iRegister, (uint8_t)u32);
3955 if (rc == VERR_MORE_DATA)
3956 {
3957 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3958 /* Send a notifier to the PDM queue that there are pending requests. */
3959 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pNotificationQueue));
3960 AssertMsg(pItem, ("Allocating item for queue failed\n"));
3961 PDMQueueInsert(pThis->CTX_SUFF(pNotificationQueue), (PPDMQUEUEITEMCORE)pItem);
3962 }
3963 else if (RT_FAILURE(rc))
3964 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
3965
3966 return VINF_SUCCESS;
3967}
3968
3969/**
3970 * @callback_method_impl{FNIOMIOPORTOUTSTRING,
3971 * Port I/O Handler for primary port range OUT string operations.}
3972 */
3973static DECLCALLBACK(int) lsilogicR3IsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
3974 uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
3975{
3976 RT_NOREF(pvUser);
3977 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3978 Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
3979
3980 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3981 ? Port - LSILOGIC_BIOS_IO_PORT
3982 : Port - LSILOGIC_SAS_BIOS_IO_PORT;
3983 int rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister, pbSrc, pcTransfers, cb);
3984 if (rc == VERR_MORE_DATA)
3985 {
3986 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3987 /* Send a notifier to the PDM queue that there are pending requests. */
3988 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pNotificationQueue));
3989 AssertMsg(pItem, ("Allocating item for queue failed\n"));
3990 PDMQueueInsert(pThis->CTX_SUFF(pNotificationQueue), (PPDMQUEUEITEMCORE)pItem);
3991 }
3992 else if (RT_FAILURE(rc))
3993 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
3994
3995 return VINF_SUCCESS;
3996}
3997
3998/**
3999 * @callback_method_impl{FNIOMIOPORTINSTRING,
4000 * Port I/O Handler for primary port range IN string operations.}
4001 */
4002static DECLCALLBACK(int) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
4003 uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
4004{
4005 RT_NOREF(pvUser);
4006 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4007 LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
4008
4009 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4010 ? Port - LSILOGIC_BIOS_IO_PORT
4011 : Port - LSILOGIC_SAS_BIOS_IO_PORT;
4012 return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister, pbDst, pcTransfers, cb);
4013}
4014
4015/**
4016 * @callback_method_impl{FNPCIIOREGIONMAP}
4017 */
4018static DECLCALLBACK(int) lsilogicR3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
4019 RTGCPHYS GCPhysAddress, RTGCPHYS cb,
4020 PCIADDRESSSPACE enmType)
4021{
4022 RT_NOREF(pPciDev);
4023 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4024 int rc = VINF_SUCCESS;
4025 const char *pcszCtrl = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4026 ? "LsiLogic"
4027 : "LsiLogicSas";
4028 const char *pcszDiag = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4029 ? "LsiLogicDiag"
4030 : "LsiLogicSasDiag";
4031
4032 Log2(("%s: registering area at GCPhysAddr=%RGp cb=%RGp\n", __FUNCTION__, GCPhysAddress, cb));
4033
4034 AssertMsg( (enmType == PCI_ADDRESS_SPACE_MEM && cb >= LSILOGIC_PCI_SPACE_MEM_SIZE)
4035 || (enmType == PCI_ADDRESS_SPACE_IO && cb >= LSILOGIC_PCI_SPACE_IO_SIZE),
4036 ("PCI region type and size do not match\n"));
4037
4038 if (enmType == PCI_ADDRESS_SPACE_MEM && iRegion == 1)
4039 {
4040 /*
4041 * Non-4-byte read access to LSILOGIC_REG_REPLY_QUEUE may cause real strange behavior
4042 * because the data is part of a physical guest address. But some drivers use 1-byte
4043 * access to scan for SCSI controllers. So, we simplify our code by telling IOM to
4044 * read DWORDs.
4045 *
4046 * Regarding writes, we couldn't find anything specific in the specs about what should
4047 * happen. So far we've ignored unaligned writes and assumed the missing bytes of
4048 * byte and word access to be zero. We suspect that IOMMMIO_FLAGS_WRITE_ONLY_DWORD
4049 * or IOMMMIO_FLAGS_WRITE_DWORD_ZEROED would be the most appropriate here, but since we
4050 * don't have real hw to test one, the old behavior is kept exactly like it used to be.
4051 */
4052 /** @todo Check out unaligned writes and non-dword writes on real LsiLogic
4053 * hardware. */
4054 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
4055 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
4056 lsilogicMMIOWrite, lsilogicMMIORead, pcszCtrl);
4057 if (RT_FAILURE(rc))
4058 return rc;
4059
4060 if (pThis->fR0Enabled)
4061 {
4062 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
4063 "lsilogicMMIOWrite", "lsilogicMMIORead");
4064 if (RT_FAILURE(rc))
4065 return rc;
4066 }
4067
4068 if (pThis->fGCEnabled)
4069 {
4070 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
4071 "lsilogicMMIOWrite", "lsilogicMMIORead");
4072 if (RT_FAILURE(rc))
4073 return rc;
4074 }
4075
4076 pThis->GCPhysMMIOBase = GCPhysAddress;
4077 }
4078 else if (enmType == PCI_ADDRESS_SPACE_MEM && iRegion == 2)
4079 {
4080 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
4081 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
4082 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
4083 lsilogicDiagnosticWrite, lsilogicDiagnosticRead, pcszDiag);
4084 if (RT_FAILURE(rc))
4085 return rc;
4086
4087 if (pThis->fR0Enabled)
4088 {
4089 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
4090 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead");
4091 if (RT_FAILURE(rc))
4092 return rc;
4093 }
4094
4095 if (pThis->fGCEnabled)
4096 {
4097 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
4098 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead");
4099 if (RT_FAILURE(rc))
4100 return rc;
4101 }
4102 }
4103 else if (enmType == PCI_ADDRESS_SPACE_IO)
4104 {
4105 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
4106 NULL, lsilogicIOPortWrite, lsilogicIOPortRead, NULL, NULL, pcszCtrl);
4107 if (RT_FAILURE(rc))
4108 return rc;
4109
4110 if (pThis->fR0Enabled)
4111 {
4112 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
4113 0, "lsilogicIOPortWrite", "lsilogicIOPortRead", NULL, NULL, pcszCtrl);
4114 if (RT_FAILURE(rc))
4115 return rc;
4116 }
4117
4118 if (pThis->fGCEnabled)
4119 {
4120 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
4121 0, "lsilogicIOPortWrite", "lsilogicIOPortRead", NULL, NULL, pcszCtrl);
4122 if (RT_FAILURE(rc))
4123 return rc;
4124 }
4125
4126 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
4127 }
4128 else
4129 AssertMsgFailed(("Invalid enmType=%d iRegion=%d\n", enmType, iRegion));
4130
4131 return rc;
4132}
4133
4134/**
4135 * @callback_method_impl{PFNDBGFHANDLERDEV}
4136 */
4137static DECLCALLBACK(void) lsilogicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4138{
4139 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4140 bool fVerbose = false;
4141
4142 /*
4143 * Parse args.
4144 */
4145 if (pszArgs)
4146 fVerbose = strstr(pszArgs, "verbose") != NULL;
4147
4148 /*
4149 * Show info.
4150 */
4151 pHlp->pfnPrintf(pHlp,
4152 "%s#%d: port=%RTiop mmio=%RGp max-devices=%u GC=%RTbool R0=%RTbool\n",
4153 pDevIns->pReg->szName,
4154 pDevIns->iInstance,
4155 pThis->IOPortBase, pThis->GCPhysMMIOBase,
4156 pThis->cDeviceStates,
4157 pThis->fGCEnabled ? true : false,
4158 pThis->fR0Enabled ? true : false);
4159
4160 /*
4161 * Show general state.
4162 */
4163 pHlp->pfnPrintf(pHlp, "enmState=%u\n", pThis->enmState);
4164 pHlp->pfnPrintf(pHlp, "enmWhoInit=%u\n", pThis->enmWhoInit);
4165 pHlp->pfnPrintf(pHlp, "enmDoorbellState=%d\n", pThis->enmDoorbellState);
4166 pHlp->pfnPrintf(pHlp, "fDiagnosticEnabled=%RTbool\n", pThis->fDiagnosticEnabled);
4167 pHlp->pfnPrintf(pHlp, "fNotificationSent=%RTbool\n", pThis->fNotificationSent);
4168 pHlp->pfnPrintf(pHlp, "fEventNotificationEnabled=%RTbool\n", pThis->fEventNotificationEnabled);
4169 pHlp->pfnPrintf(pHlp, "uInterruptMask=%#x\n", pThis->uInterruptMask);
4170 pHlp->pfnPrintf(pHlp, "uInterruptStatus=%#x\n", pThis->uInterruptStatus);
4171 pHlp->pfnPrintf(pHlp, "u16IOCFaultCode=%#06x\n", pThis->u16IOCFaultCode);
4172 pHlp->pfnPrintf(pHlp, "u32HostMFAHighAddr=%#x\n", pThis->u32HostMFAHighAddr);
4173 pHlp->pfnPrintf(pHlp, "u32SenseBufferHighAddr=%#x\n", pThis->u32SenseBufferHighAddr);
4174 pHlp->pfnPrintf(pHlp, "cMaxDevices=%u\n", pThis->cMaxDevices);
4175 pHlp->pfnPrintf(pHlp, "cMaxBuses=%u\n", pThis->cMaxBuses);
4176 pHlp->pfnPrintf(pHlp, "cbReplyFrame=%u\n", pThis->cbReplyFrame);
4177 pHlp->pfnPrintf(pHlp, "cReplyQueueEntries=%u\n", pThis->cReplyQueueEntries);
4178 pHlp->pfnPrintf(pHlp, "cRequestQueueEntries=%u\n", pThis->cRequestQueueEntries);
4179 pHlp->pfnPrintf(pHlp, "cPorts=%u\n", pThis->cPorts);
4180
4181 /*
4182 * Show queue status.
4183 */
4184 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextEntryFreeWrite=%u\n", pThis->uReplyFreeQueueNextEntryFreeWrite);
4185 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextAddressRead=%u\n", pThis->uReplyFreeQueueNextAddressRead);
4186 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextEntryFreeWrite=%u\n", pThis->uReplyPostQueueNextEntryFreeWrite);
4187 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextAddressRead=%u\n", pThis->uReplyPostQueueNextAddressRead);
4188 pHlp->pfnPrintf(pHlp, "uRequestQueueNextEntryFreeWrite=%u\n", pThis->uRequestQueueNextEntryFreeWrite);
4189 pHlp->pfnPrintf(pHlp, "uRequestQueueNextAddressRead=%u\n", pThis->uRequestQueueNextAddressRead);
4190
4191 /*
4192 * Show queue content if verbose
4193 */
4194 if (fVerbose)
4195 {
4196 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4197 pHlp->pfnPrintf(pHlp, "RFQ[%u]=%#x\n", i, pThis->pReplyFreeQueueBaseR3[i]);
4198
4199 pHlp->pfnPrintf(pHlp, "\n");
4200
4201 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4202 pHlp->pfnPrintf(pHlp, "RPQ[%u]=%#x\n", i, pThis->pReplyPostQueueBaseR3[i]);
4203
4204 pHlp->pfnPrintf(pHlp, "\n");
4205
4206 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4207 pHlp->pfnPrintf(pHlp, "ReqQ[%u]=%#x\n", i, pThis->pRequestQueueBaseR3[i]);
4208 }
4209
4210 /*
4211 * Print the device status.
4212 */
4213 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4214 {
4215 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
4216
4217 pHlp->pfnPrintf(pHlp, "\n");
4218
4219 pHlp->pfnPrintf(pHlp, "Device[%u]: device-attached=%RTbool cOutstandingRequests=%u\n",
4220 i, pDevice->pDrvBase != NULL, pDevice->cOutstandingRequests);
4221 }
4222}
4223
4224/**
4225 * Allocate the queues.
4226 *
4227 * @returns VBox status code.
4228 *
4229 * @param pThis Pointer to the LsiLogic device state.
4230 */
4231static int lsilogicR3QueuesAlloc(PLSILOGICSCSI pThis)
4232{
4233 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
4234 uint32_t cbQueues;
4235
4236 Assert(!pThis->pReplyFreeQueueBaseR3);
4237
4238 cbQueues = 2*pThis->cReplyQueueEntries * sizeof(uint32_t);
4239 cbQueues += pThis->cRequestQueueEntries * sizeof(uint32_t);
4240 int rc = MMHyperAlloc(pVM, cbQueues, 1, MM_TAG_PDM_DEVICE_USER,
4241 (void **)&pThis->pReplyFreeQueueBaseR3);
4242 if (RT_FAILURE(rc))
4243 return VERR_NO_MEMORY;
4244 pThis->pReplyFreeQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
4245 pThis->pReplyFreeQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
4246
4247 pThis->pReplyPostQueueBaseR3 = pThis->pReplyFreeQueueBaseR3 + pThis->cReplyQueueEntries;
4248 pThis->pReplyPostQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pReplyPostQueueBaseR3);
4249 pThis->pReplyPostQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pReplyPostQueueBaseR3);
4250
4251 pThis->pRequestQueueBaseR3 = pThis->pReplyPostQueueBaseR3 + pThis->cReplyQueueEntries;
4252 pThis->pRequestQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pRequestQueueBaseR3);
4253 pThis->pRequestQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pRequestQueueBaseR3);
4254
4255 return VINF_SUCCESS;
4256}
4257
4258/**
4259 * Free the hyper memory used or the queues.
4260 *
4261 * @returns nothing.
4262 *
4263 * @param pThis Pointer to the LsiLogic device state.
4264 */
4265static void lsilogicR3QueuesFree(PLSILOGICSCSI pThis)
4266{
4267 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
4268 int rc = VINF_SUCCESS;
4269
4270 AssertPtr(pThis->pReplyFreeQueueBaseR3);
4271
4272 rc = MMHyperFree(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
4273 AssertRC(rc);
4274
4275 pThis->pReplyFreeQueueBaseR3 = NULL;
4276 pThis->pReplyPostQueueBaseR3 = NULL;
4277 pThis->pRequestQueueBaseR3 = NULL;
4278}
4279
4280
4281/* The worker thread. */
4282static DECLCALLBACK(int) lsilogicR3Worker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4283{
4284 PLSILOGICSCSI pThis = (PLSILOGICSCSI)pThread->pvUser;
4285 int rc = VINF_SUCCESS;
4286
4287 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
4288 return VINF_SUCCESS;
4289
4290 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4291 {
4292 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true);
4293 bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false);
4294 if (!fNotificationSent)
4295 {
4296 Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping));
4297 rc = SUPSemEventWaitNoResume(pThis->pSupDrvSession, pThis->hEvtProcess, RT_INDEFINITE_WAIT);
4298 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
4299 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
4300 break;
4301 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
4302 ASMAtomicWriteBool(&pThis->fNotificationSent, false);
4303 }
4304
4305 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false);
4306
4307 /* Check whether there is a BIOS request pending and process it first. */
4308 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
4309 {
4310 rc = lsilogicR3PrepareBiosScsiRequest(pThis);
4311 AssertRC(rc);
4312 ASMAtomicXchgBool(&pThis->fBiosReqPending, false);
4313 }
4314
4315 /* Only process request which arrived before we received the notification. */
4316 uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite);
4317
4318 /* Go through the messages now and process them. */
4319 while ( RT_LIKELY(pThis->enmState == LSILOGICSTATE_OPERATIONAL)
4320 && (pThis->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite))
4321 {
4322 MptRequestUnion GuestRequest;
4323 uint32_t u32RequestMessageFrameDesc = pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextAddressRead];
4324 RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr,
4325 (u32RequestMessageFrameDesc & ~0x07));
4326
4327 /* Read the message header from the guest first. */
4328 PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, sizeof(MptMessageHdr));
4329
4330 /* Determine the size of the request. */
4331 uint32_t cbRequest = 0;
4332 switch (GuestRequest.Header.u8Function)
4333 {
4334 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
4335 cbRequest = sizeof(MptSCSIIORequest);
4336 break;
4337 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
4338 cbRequest = sizeof(MptSCSITaskManagementRequest);
4339 break;
4340 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
4341 cbRequest = sizeof(MptIOCInitRequest);
4342 break;
4343 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
4344 cbRequest = sizeof(MptIOCFactsRequest);
4345 break;
4346 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
4347 cbRequest = sizeof(MptConfigurationRequest);
4348 break;
4349 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
4350 cbRequest = sizeof(MptPortFactsRequest);
4351 break;
4352 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
4353 cbRequest = sizeof(MptPortEnableRequest);
4354 break;
4355 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
4356 cbRequest = sizeof(MptEventNotificationRequest);
4357 break;
4358 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
4359 AssertMsgFailed(("todo\n"));
4360 //cbRequest = sizeof(MptEventAckRequest);
4361 break;
4362 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
4363 cbRequest = sizeof(MptFWDownloadRequest);
4364 break;
4365 case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
4366 cbRequest = sizeof(MptFWUploadRequest);
4367 break;
4368 default:
4369 AssertMsgFailed(("Unknown function issued %u\n", GuestRequest.Header.u8Function));
4370 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INVALID_FUNCTION);
4371 }
4372
4373 if (cbRequest != 0)
4374 {
4375 /* Read the complete message frame from guest memory now. */
4376 PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, cbRequest);
4377
4378 /* Handle SCSI I/O requests now. */
4379 if (GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST)
4380 {
4381 rc = lsilogicR3ProcessSCSIIORequest(pThis, GCPhysMessageFrameAddr, &GuestRequest);
4382 AssertRC(rc);
4383 }
4384 else
4385 {
4386 MptReplyUnion Reply;
4387 rc = lsilogicR3ProcessMessageRequest(pThis, &GuestRequest.Header, &Reply);
4388 AssertRC(rc);
4389 }
4390
4391 pThis->uRequestQueueNextAddressRead++;
4392 pThis->uRequestQueueNextAddressRead %= pThis->cRequestQueueEntries;
4393 }
4394 } /* While request frames available. */
4395 } /* While running */
4396
4397 return VINF_SUCCESS;
4398}
4399
4400
4401/**
4402 * Unblock the worker thread so it can respond to a state change.
4403 *
4404 * @returns VBox status code.
4405 * @param pDevIns The pcnet device instance.
4406 * @param pThread The send thread.
4407 */
4408static DECLCALLBACK(int) lsilogicR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4409{
4410 RT_NOREF(pThread);
4411 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4412 return SUPSemEventSignal(pThis->pSupDrvSession, pThis->hEvtProcess);
4413}
4414
4415
4416/**
4417 * Kicks the controller to process pending tasks after the VM was resumed
4418 * or loaded from a saved state.
4419 *
4420 * @returns nothing.
4421 * @param pThis Pointer to the LsiLogic device state.
4422 */
4423static void lsilogicR3Kick(PLSILOGICSCSI pThis)
4424{
4425 if (pThis->fNotificationSent)
4426 {
4427 /* Send a notifier to the PDM queue that there are pending requests. */
4428 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pThis->CTX_SUFF(pNotificationQueue));
4429 AssertMsg(pItem, ("Allocating item for queue failed\n"));
4430 PDMQueueInsert(pThis->CTX_SUFF(pNotificationQueue), (PPDMQUEUEITEMCORE)pItem);
4431 }
4432}
4433
4434
4435/*
4436 * Saved state.
4437 */
4438
4439/**
4440 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4441 */
4442static DECLCALLBACK(int) lsilogicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4443{
4444 RT_NOREF(uPass);
4445 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4446
4447 SSMR3PutU32(pSSM, pThis->enmCtrlType);
4448 SSMR3PutU32(pSSM, pThis->cDeviceStates);
4449 SSMR3PutU32(pSSM, pThis->cPorts);
4450
4451 /* Save the device config. */
4452 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4453 SSMR3PutBool(pSSM, pThis->paDeviceStates[i].pDrvBase != NULL);
4454
4455 return VINF_SSM_DONT_CALL_AGAIN;
4456}
4457
4458/**
4459 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4460 */
4461static DECLCALLBACK(int) lsilogicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4462{
4463 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4464
4465 /* Every device first. */
4466 lsilogicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4467 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4468 {
4469 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
4470
4471 AssertMsg(!pDevice->cOutstandingRequests,
4472 ("There are still outstanding requests on this device\n"));
4473 SSMR3PutU32(pSSM, pDevice->cOutstandingRequests);
4474
4475 /* Query all suspended requests and store them in the request queue. */
4476 if (pDevice->pDrvMediaEx)
4477 {
4478 uint32_t cReqsRedo = pDevice->pDrvMediaEx->pfnIoReqGetSuspendedCount(pDevice->pDrvMediaEx);
4479 if (cReqsRedo)
4480 {
4481 PDMMEDIAEXIOREQ hIoReq;
4482 PLSILOGICREQ pReq;
4483 int rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pDevice->pDrvMediaEx, &hIoReq,
4484 (void **)&pReq);
4485 AssertRCBreak(rc);
4486
4487 for (;;)
4488 {
4489 if (!pReq->fBIOS)
4490 {
4491 /* Write only the lower 32bit part of the address. */
4492 ASMAtomicWriteU32(&pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextEntryFreeWrite],
4493 pReq->GCPhysMessageFrameAddr & UINT32_C(0xffffffff));
4494
4495 pThis->uRequestQueueNextEntryFreeWrite++;
4496 pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries;
4497 }
4498 else
4499 {
4500 AssertMsg(!pReq->pRedoNext, ("Only one BIOS task can be active!\n"));
4501 vboxscsiSetRequestRedo(&pThis->VBoxSCSI);
4502 }
4503
4504 cReqsRedo--;
4505 if (!cReqsRedo)
4506 break;
4507
4508 rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pDevice->pDrvMediaEx, hIoReq,
4509 &hIoReq, (void **)&pReq);
4510 AssertRCBreak(rc);
4511 }
4512 }
4513 }
4514 }
4515
4516 /* Now the main device state. */
4517 SSMR3PutU32 (pSSM, pThis->enmState);
4518 SSMR3PutU32 (pSSM, pThis->enmWhoInit);
4519 SSMR3PutU32 (pSSM, pThis->enmDoorbellState);
4520 SSMR3PutBool (pSSM, pThis->fDiagnosticEnabled);
4521 SSMR3PutBool (pSSM, pThis->fNotificationSent);
4522 SSMR3PutBool (pSSM, pThis->fEventNotificationEnabled);
4523 SSMR3PutU32 (pSSM, pThis->uInterruptMask);
4524 SSMR3PutU32 (pSSM, pThis->uInterruptStatus);
4525 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4526 SSMR3PutU32 (pSSM, pThis->aMessage[i]);
4527 SSMR3PutU32 (pSSM, pThis->iMessage);
4528 SSMR3PutU32 (pSSM, pThis->cMessage);
4529 SSMR3PutMem (pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4530 SSMR3PutU32 (pSSM, pThis->uNextReplyEntryRead);
4531 SSMR3PutU32 (pSSM, pThis->cReplySize);
4532 SSMR3PutU16 (pSSM, pThis->u16IOCFaultCode);
4533 SSMR3PutU32 (pSSM, pThis->u32HostMFAHighAddr);
4534 SSMR3PutU32 (pSSM, pThis->u32SenseBufferHighAddr);
4535 SSMR3PutU8 (pSSM, pThis->cMaxDevices);
4536 SSMR3PutU8 (pSSM, pThis->cMaxBuses);
4537 SSMR3PutU16 (pSSM, pThis->cbReplyFrame);
4538 SSMR3PutU32 (pSSM, pThis->iDiagnosticAccess);
4539 SSMR3PutU32 (pSSM, pThis->cReplyQueueEntries);
4540 SSMR3PutU32 (pSSM, pThis->cRequestQueueEntries);
4541 SSMR3PutU32 (pSSM, pThis->uReplyFreeQueueNextEntryFreeWrite);
4542 SSMR3PutU32 (pSSM, pThis->uReplyFreeQueueNextAddressRead);
4543 SSMR3PutU32 (pSSM, pThis->uReplyPostQueueNextEntryFreeWrite);
4544 SSMR3PutU32 (pSSM, pThis->uReplyPostQueueNextAddressRead);
4545 SSMR3PutU32 (pSSM, pThis->uRequestQueueNextEntryFreeWrite);
4546 SSMR3PutU32 (pSSM, pThis->uRequestQueueNextAddressRead);
4547
4548 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4549 SSMR3PutU32(pSSM, pThis->pReplyFreeQueueBaseR3[i]);
4550 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4551 SSMR3PutU32(pSSM, pThis->pReplyPostQueueBaseR3[i]);
4552 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4553 SSMR3PutU32(pSSM, pThis->pRequestQueueBaseR3[i]);
4554
4555 SSMR3PutU16 (pSSM, pThis->u16NextHandle);
4556
4557 /* Save diagnostic memory register and data regions. */
4558 SSMR3PutU32 (pSSM, pThis->u32DiagMemAddr);
4559 SSMR3PutU32 (pSSM, lsilogicR3MemRegionsCount(pThis));
4560
4561 PLSILOGICMEMREGN pIt;
4562 RTListForEach(&pThis->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
4563 {
4564 SSMR3PutU32(pSSM, pIt->u32AddrStart);
4565 SSMR3PutU32(pSSM, pIt->u32AddrEnd);
4566 SSMR3PutMem(pSSM, &pIt->au32Data[0], (pIt->u32AddrEnd - pIt->u32AddrStart + 1) * sizeof(uint32_t));
4567 }
4568
4569 PMptConfigurationPagesSupported pPages = pThis->pConfigurationPages;
4570
4571 SSMR3PutMem (pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4572 SSMR3PutMem (pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4573 SSMR3PutMem (pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4574 SSMR3PutMem (pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4575 SSMR3PutMem (pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4576 SSMR3PutMem (pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4577 SSMR3PutMem (pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4578 SSMR3PutMem (pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4579 SSMR3PutMem (pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4580 SSMR3PutMem (pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4581 SSMR3PutMem (pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4582 SSMR3PutMem (pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4583 SSMR3PutMem (pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4584 SSMR3PutMem (pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4585 SSMR3PutMem (pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4586 SSMR3PutMem (pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4587 SSMR3PutMem (pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4588 SSMR3PutMem (pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4589 SSMR3PutMem (pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4590 SSMR3PutMem (pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4591 SSMR3PutMem (pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4592 SSMR3PutMem (pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4593 SSMR3PutMem (pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4594 SSMR3PutMem (pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4595
4596 /* Device dependent pages */
4597 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4598 {
4599 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4600
4601 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4602 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4603 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4604
4605 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4606 {
4607 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4608 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4609 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4610 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4611 }
4612 }
4613 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4614 {
4615 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4616
4617 SSMR3PutU32(pSSM, pSasPages->cbManufacturingPage7);
4618 SSMR3PutU32(pSSM, pSasPages->cbSASIOUnitPage0);
4619 SSMR3PutU32(pSSM, pSasPages->cbSASIOUnitPage1);
4620
4621 SSMR3PutMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4622 SSMR3PutMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4623 SSMR3PutMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4624
4625 SSMR3PutMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4626 SSMR3PutMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4627
4628 SSMR3PutU32(pSSM, pSasPages->cPHYs);
4629 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4630 {
4631 SSMR3PutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4632 SSMR3PutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4633 }
4634
4635 /* The number of devices first. */
4636 SSMR3PutU32(pSSM, pSasPages->cDevices);
4637
4638 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4639
4640 while (pCurr)
4641 {
4642 SSMR3PutMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4643 SSMR3PutMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4644 SSMR3PutMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4645
4646 pCurr = pCurr->pNext;
4647 }
4648 }
4649 else
4650 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4651
4652 vboxscsiR3SaveExec(&pThis->VBoxSCSI, pSSM);
4653 return SSMR3PutU32(pSSM, UINT32_MAX);
4654}
4655
4656/**
4657 * @callback_method_impl{FNSSMDEVLOADDONE}
4658 */
4659static DECLCALLBACK(int) lsilogicR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4660{
4661 RT_NOREF(pSSM);
4662 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4663
4664 lsilogicR3Kick(pThis);
4665 return VINF_SUCCESS;
4666}
4667
4668/**
4669 * @callback_method_impl{FNSSMDEVLOADEXEC}
4670 */
4671static DECLCALLBACK(int) lsilogicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4672{
4673 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4674 int rc;
4675
4676 if ( uVersion != LSILOGIC_SAVED_STATE_VERSION
4677 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM
4678 && uVersion != LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL
4679 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_SAS
4680 && uVersion != LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4681 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4682
4683 /* device config */
4684 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4685 {
4686 LSILOGICCTRLTYPE enmCtrlType;
4687 uint32_t cDeviceStates, cPorts;
4688
4689 rc = SSMR3GetU32(pSSM, (uint32_t *)&enmCtrlType);
4690 AssertRCReturn(rc, rc);
4691 rc = SSMR3GetU32(pSSM, &cDeviceStates);
4692 AssertRCReturn(rc, rc);
4693 rc = SSMR3GetU32(pSSM, &cPorts);
4694 AssertRCReturn(rc, rc);
4695
4696 if (enmCtrlType != pThis->enmCtrlType)
4697 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
4698 pThis->enmCtrlType, enmCtrlType);
4699 if (cDeviceStates != pThis->cDeviceStates)
4700 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
4701 pThis->cDeviceStates, cDeviceStates);
4702 if (cPorts != pThis->cPorts)
4703 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"),
4704 pThis->cPorts, cPorts);
4705 }
4706 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4707 {
4708 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4709 {
4710 bool fPresent;
4711 rc = SSMR3GetBool(pSSM, &fPresent);
4712 AssertRCReturn(rc, rc);
4713 if (fPresent != (pThis->paDeviceStates[i].pDrvBase != NULL))
4714 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
4715 i, pThis->paDeviceStates[i].pDrvBase != NULL, fPresent);
4716 }
4717 }
4718 if (uPass != SSM_PASS_FINAL)
4719 return VINF_SUCCESS;
4720
4721 /* Every device first. */
4722 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4723 {
4724 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
4725
4726 AssertMsg(!pDevice->cOutstandingRequests,
4727 ("There are still outstanding requests on this device\n"));
4728 SSMR3GetU32(pSSM, (uint32_t *)&pDevice->cOutstandingRequests);
4729 }
4730 /* Now the main device state. */
4731 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->enmState);
4732 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->enmWhoInit);
4733 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL)
4734 {
4735 bool fDoorbellInProgress = false;
4736
4737 /*
4738 * The doorbell status flag distinguishes only between
4739 * doorbell not in use or a Function handshake is currently in progress.
4740 */
4741 SSMR3GetBool (pSSM, &fDoorbellInProgress);
4742 if (fDoorbellInProgress)
4743 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE;
4744 else
4745 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
4746 }
4747 else
4748 SSMR3GetU32(pSSM, (uint32_t *)&pThis->enmDoorbellState);
4749 SSMR3GetBool (pSSM, &pThis->fDiagnosticEnabled);
4750 SSMR3GetBool (pSSM, &pThis->fNotificationSent);
4751 SSMR3GetBool (pSSM, &pThis->fEventNotificationEnabled);
4752 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uInterruptMask);
4753 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uInterruptStatus);
4754 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4755 SSMR3GetU32 (pSSM, &pThis->aMessage[i]);
4756 SSMR3GetU32 (pSSM, &pThis->iMessage);
4757 SSMR3GetU32 (pSSM, &pThis->cMessage);
4758 SSMR3GetMem (pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4759 SSMR3GetU32 (pSSM, &pThis->uNextReplyEntryRead);
4760 SSMR3GetU32 (pSSM, &pThis->cReplySize);
4761 SSMR3GetU16 (pSSM, &pThis->u16IOCFaultCode);
4762 SSMR3GetU32 (pSSM, &pThis->u32HostMFAHighAddr);
4763 SSMR3GetU32 (pSSM, &pThis->u32SenseBufferHighAddr);
4764 SSMR3GetU8 (pSSM, &pThis->cMaxDevices);
4765 SSMR3GetU8 (pSSM, &pThis->cMaxBuses);
4766 SSMR3GetU16 (pSSM, &pThis->cbReplyFrame);
4767 SSMR3GetU32 (pSSM, &pThis->iDiagnosticAccess);
4768
4769 uint32_t cReplyQueueEntries, cRequestQueueEntries;
4770 SSMR3GetU32 (pSSM, &cReplyQueueEntries);
4771 SSMR3GetU32 (pSSM, &cRequestQueueEntries);
4772
4773 if ( cReplyQueueEntries != pThis->cReplyQueueEntries
4774 || cRequestQueueEntries != pThis->cRequestQueueEntries)
4775 {
4776 LogFlow(("Reallocating queues cReplyQueueEntries=%u cRequestQueuEntries=%u\n",
4777 cReplyQueueEntries, cRequestQueueEntries));
4778 lsilogicR3QueuesFree(pThis);
4779 pThis->cReplyQueueEntries = cReplyQueueEntries;
4780 pThis->cRequestQueueEntries = cRequestQueueEntries;
4781 rc = lsilogicR3QueuesAlloc(pThis);
4782 if (RT_FAILURE(rc))
4783 return rc;
4784 }
4785
4786 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyFreeQueueNextEntryFreeWrite);
4787 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyFreeQueueNextAddressRead);
4788 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyPostQueueNextEntryFreeWrite);
4789 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uReplyPostQueueNextAddressRead);
4790 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uRequestQueueNextEntryFreeWrite);
4791 SSMR3GetU32 (pSSM, (uint32_t *)&pThis->uRequestQueueNextAddressRead);
4792
4793 PMptConfigurationPagesSupported pPages = pThis->pConfigurationPages;
4794
4795 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4796 {
4797 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4798 MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2;
4799
4800 if (pThis->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI)
4801 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller"));
4802
4803 SSMR3GetMem(pSSM, &ConfigPagesV2,
4804 sizeof(MptConfigurationPagesSupported_SSM_V2));
4805
4806 pPages->ManufacturingPage0 = ConfigPagesV2.ManufacturingPage0;
4807 pPages->ManufacturingPage1 = ConfigPagesV2.ManufacturingPage1;
4808 pPages->ManufacturingPage2 = ConfigPagesV2.ManufacturingPage2;
4809 pPages->ManufacturingPage3 = ConfigPagesV2.ManufacturingPage3;
4810 pPages->ManufacturingPage4 = ConfigPagesV2.ManufacturingPage4;
4811 pPages->IOUnitPage0 = ConfigPagesV2.IOUnitPage0;
4812 pPages->IOUnitPage1 = ConfigPagesV2.IOUnitPage1;
4813 pPages->IOUnitPage2 = ConfigPagesV2.IOUnitPage2;
4814 pPages->IOUnitPage3 = ConfigPagesV2.IOUnitPage3;
4815 pPages->IOCPage0 = ConfigPagesV2.IOCPage0;
4816 pPages->IOCPage1 = ConfigPagesV2.IOCPage1;
4817 pPages->IOCPage2 = ConfigPagesV2.IOCPage2;
4818 pPages->IOCPage3 = ConfigPagesV2.IOCPage3;
4819 pPages->IOCPage4 = ConfigPagesV2.IOCPage4;
4820 pPages->IOCPage6 = ConfigPagesV2.IOCPage6;
4821
4822 pSpiPages->aPortPages[0].SCSISPIPortPage0 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage0;
4823 pSpiPages->aPortPages[0].SCSISPIPortPage1 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage1;
4824 pSpiPages->aPortPages[0].SCSISPIPortPage2 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage2;
4825
4826 for (unsigned i = 0; i < RT_ELEMENTS(pPages->u.SpiPages.aBuses[0].aDevicePages); i++)
4827 {
4828 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
4829 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
4830 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
4831 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
4832 }
4833 }
4834 else
4835 {
4836 /* Queue content */
4837 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4838 SSMR3GetU32(pSSM, (uint32_t *)&pThis->pReplyFreeQueueBaseR3[i]);
4839 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4840 SSMR3GetU32(pSSM, (uint32_t *)&pThis->pReplyPostQueueBaseR3[i]);
4841 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4842 SSMR3GetU32(pSSM, (uint32_t *)&pThis->pRequestQueueBaseR3[i]);
4843
4844 SSMR3GetU16(pSSM, &pThis->u16NextHandle);
4845
4846 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM)
4847 {
4848 uint32_t cMemRegions = 0;
4849
4850 /* Save diagnostic memory register and data regions. */
4851 SSMR3GetU32 (pSSM, &pThis->u32DiagMemAddr);
4852 SSMR3GetU32 (pSSM, &cMemRegions);
4853
4854 while (cMemRegions)
4855 {
4856 uint32_t u32AddrStart = 0;
4857 uint32_t u32AddrEnd = 0;
4858 uint32_t cRegion = 0;
4859 PLSILOGICMEMREGN pRegion = NULL;
4860
4861 SSMR3GetU32(pSSM, &u32AddrStart);
4862 SSMR3GetU32(pSSM, &u32AddrEnd);
4863
4864 cRegion = u32AddrEnd - u32AddrStart + 1;
4865 pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_OFFSETOF(LSILOGICMEMREGN, au32Data[cRegion]));
4866 if (pRegion)
4867 {
4868 pRegion->u32AddrStart = u32AddrStart;
4869 pRegion->u32AddrEnd = u32AddrEnd;
4870 SSMR3GetMem(pSSM, &pRegion->au32Data[0], cRegion * sizeof(uint32_t));
4871 lsilogicR3MemRegionInsert(pThis, pRegion);
4872 pThis->cbMemRegns += cRegion * sizeof(uint32_t);
4873 }
4874 else
4875 {
4876 /* Leave a log message but continue. */
4877 LogRel(("LsiLogic: Out of memory while restoring the state, might not work as expected\n"));
4878 SSMR3Skip(pSSM, cRegion * sizeof(uint32_t));
4879 }
4880 cMemRegions--;
4881 }
4882 }
4883
4884 /* Configuration pages */
4885 SSMR3GetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4886 SSMR3GetMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4887 SSMR3GetMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4888 SSMR3GetMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4889 SSMR3GetMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4890 SSMR3GetMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4891 SSMR3GetMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4892 SSMR3GetMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4893 SSMR3GetMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4894 SSMR3GetMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4895 SSMR3GetMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4896 SSMR3GetMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4897 SSMR3GetMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4898 SSMR3GetMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4899 SSMR3GetMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4900 SSMR3GetMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4901 SSMR3GetMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4902 SSMR3GetMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4903 SSMR3GetMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4904 SSMR3GetMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4905 SSMR3GetMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4906 SSMR3GetMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4907 SSMR3GetMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4908 SSMR3GetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4909
4910 /* Device dependent pages */
4911 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4912 {
4913 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4914
4915 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4916 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4917 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4918
4919 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4920 {
4921 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4922 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4923 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4924 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4925 }
4926 }
4927 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4928 {
4929 uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7;
4930 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4931
4932 SSMR3GetU32(pSSM, &cbManufacturingPage7);
4933 SSMR3GetU32(pSSM, &cbPage0);
4934 SSMR3GetU32(pSSM, &cbPage1);
4935
4936 if ( (cbPage0 != pSasPages->cbSASIOUnitPage0)
4937 || (cbPage1 != pSasPages->cbSASIOUnitPage1)
4938 || (cbManufacturingPage7 != pSasPages->cbManufacturingPage7))
4939 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4940
4941 AssertPtr(pSasPages->pManufacturingPage7);
4942 AssertPtr(pSasPages->pSASIOUnitPage0);
4943 AssertPtr(pSasPages->pSASIOUnitPage1);
4944
4945 SSMR3GetMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4946 SSMR3GetMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4947 SSMR3GetMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4948
4949 SSMR3GetMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4950 SSMR3GetMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4951
4952 SSMR3GetU32(pSSM, &cPHYs);
4953 if (cPHYs != pSasPages->cPHYs)
4954 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4955
4956 AssertPtr(pSasPages->paPHYs);
4957 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4958 {
4959 SSMR3GetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4960 SSMR3GetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4961 }
4962
4963 /* The number of devices first. */
4964 SSMR3GetU32(pSSM, &pSasPages->cDevices);
4965
4966 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4967
4968 for (unsigned i = 0; i < pSasPages->cDevices; i++)
4969 {
4970 SSMR3GetMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4971 SSMR3GetMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4972 SSMR3GetMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4973
4974 pCurr = pCurr->pNext;
4975 }
4976
4977 Assert(!pCurr);
4978 }
4979 else
4980 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4981 }
4982
4983 rc = vboxscsiR3LoadExec(&pThis->VBoxSCSI, pSSM);
4984 if (RT_FAILURE(rc))
4985 {
4986 LogRel(("LsiLogic: Failed to restore BIOS state: %Rrc.\n", rc));
4987 return PDMDEV_SET_ERROR(pDevIns, rc,
4988 N_("LsiLogic: Failed to restore BIOS state\n"));
4989 }
4990
4991 uint32_t u32;
4992 rc = SSMR3GetU32(pSSM, &u32);
4993 if (RT_FAILURE(rc))
4994 return rc;
4995 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4996
4997 return VINF_SUCCESS;
4998}
4999
5000
5001/*
5002 * The device level IBASE and LED interfaces.
5003 */
5004
5005/**
5006 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed, For a SCSI device.}
5007 *
5008 * @remarks Called by the scsi driver, proxying the main calls.
5009 */
5010static DECLCALLBACK(int) lsilogicR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
5011{
5012 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ILed);
5013 if (iLUN == 0)
5014 {
5015 *ppLed = &pDevice->Led;
5016 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
5017 return VINF_SUCCESS;
5018 }
5019 return VERR_PDM_LUN_NOT_FOUND;
5020}
5021
5022
5023/**
5024 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
5025 */
5026static DECLCALLBACK(void *) lsilogicR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
5027{
5028 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IBase);
5029
5030 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
5031 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pDevice->IMediaPort);
5032 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pDevice->IMediaExPort);
5033 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
5034 return NULL;
5035}
5036
5037
5038/*
5039 * The controller level IBASE and LED interfaces.
5040 */
5041
5042/**
5043 * Gets the pointer to the status LED of a unit.
5044 *
5045 * @returns VBox status code.
5046 * @param pInterface Pointer to the interface structure containing the called function pointer.
5047 * @param iLUN The unit which status LED we desire.
5048 * @param ppLed Where to store the LED pointer.
5049 */
5050static DECLCALLBACK(int) lsilogicR3StatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
5051{
5052 PLSILOGICSCSI pThis = RT_FROM_MEMBER(pInterface, LSILOGICSCSI, ILeds);
5053 if (iLUN < pThis->cDeviceStates)
5054 {
5055 *ppLed = &pThis->paDeviceStates[iLUN].Led;
5056 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
5057 return VINF_SUCCESS;
5058 }
5059 return VERR_PDM_LUN_NOT_FOUND;
5060}
5061
5062/**
5063 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
5064 */
5065static DECLCALLBACK(void *) lsilogicR3StatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
5066{
5067 PLSILOGICSCSI pThis = RT_FROM_MEMBER(pInterface, LSILOGICSCSI, IBase);
5068 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
5069 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
5070 return NULL;
5071}
5072
5073
5074/*
5075 * The PDM device interface and some helpers.
5076 */
5077
5078/**
5079 * Checks if all asynchronous I/O is finished.
5080 *
5081 * Used by lsilogicR3Reset, lsilogicR3Suspend and lsilogicR3PowerOff.
5082 *
5083 * @returns true if quiesced, false if busy.
5084 * @param pDevIns The device instance.
5085 */
5086static bool lsilogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
5087{
5088 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5089
5090 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
5091 {
5092 PLSILOGICDEVICE pThisDevice = &pThis->paDeviceStates[i];
5093 if (pThisDevice->pDrvBase)
5094 {
5095 if (pThisDevice->cOutstandingRequests != 0)
5096 return false;
5097 }
5098 }
5099
5100 return true;
5101}
5102
5103/**
5104 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
5105 * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.}
5106 */
5107static DECLCALLBACK(bool) lsilogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
5108{
5109 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5110 return false;
5111
5112 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5113 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5114 return true;
5115}
5116
5117/**
5118 * Common worker for ahciR3Suspend and ahciR3PowerOff.
5119 */
5120static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
5121{
5122 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5123
5124 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
5125 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5126 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncSuspendOrPowerOffDone);
5127 else
5128 {
5129 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5130
5131 AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
5132 }
5133}
5134
5135/**
5136 * @interface_method_impl{PDMDEVREG,pfnSuspend}
5137 */
5138static DECLCALLBACK(void) lsilogicR3Suspend(PPDMDEVINS pDevIns)
5139{
5140 Log(("lsilogicR3Suspend\n"));
5141 lsilogicR3SuspendOrPowerOff(pDevIns);
5142}
5143
5144/**
5145 * @interface_method_impl{PDMDEVREG,pfnResume}
5146 */
5147static DECLCALLBACK(void) lsilogicR3Resume(PPDMDEVINS pDevIns)
5148{
5149 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5150
5151 Log(("lsilogicR3Resume\n"));
5152
5153 lsilogicR3Kick(pThis);
5154}
5155
5156/**
5157 * @interface_method_impl{PDMDEVREG,pfnDetach}
5158 *
5159 * One harddisk at one port has been unplugged.
5160 * The VM is suspended at this point.
5161 */
5162static DECLCALLBACK(void) lsilogicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5163{
5164 RT_NOREF(fFlags);
5165 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5166 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN];
5167
5168 if (iLUN >= pThis->cDeviceStates)
5169 return;
5170
5171 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5172 ("LsiLogic: Device does not support hotplugging\n"));
5173
5174 Log(("%s:\n", __FUNCTION__));
5175
5176 /*
5177 * Zero some important members.
5178 */
5179 pDevice->pDrvBase = NULL;
5180 pDevice->pDrvMedia = NULL;
5181 pDevice->pDrvMediaEx = NULL;
5182}
5183
5184/**
5185 * @interface_method_impl{PDMDEVREG,pfnAttach}
5186 */
5187static DECLCALLBACK(int) lsilogicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5188{
5189 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5190 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN];
5191 int rc;
5192
5193 if (iLUN >= pThis->cDeviceStates)
5194 return VERR_PDM_LUN_NOT_FOUND;
5195
5196 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5197 ("LsiLogic: Device does not support hotplugging\n"),
5198 VERR_INVALID_PARAMETER);
5199
5200 /* the usual paranoia */
5201 AssertRelease(!pDevice->pDrvBase);
5202 AssertRelease(!pDevice->pDrvMedia);
5203 AssertRelease(!pDevice->pDrvMediaEx);
5204 Assert(pDevice->iLUN == iLUN);
5205
5206 /*
5207 * Try attach the block device and get the interfaces,
5208 * required as well as optional.
5209 */
5210 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
5211 if (RT_SUCCESS(rc))
5212 {
5213 /* Query the media interface. */
5214 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5215 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5216 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5217 VERR_PDM_MISSING_INTERFACE);
5218
5219 /* Get the extended media interface. */
5220 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5221 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5222 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5223 VERR_PDM_MISSING_INTERFACE);
5224
5225 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5226 AssertMsgRCReturn(rc, ("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!", pDevice->iLUN),
5227 rc);
5228 }
5229 else
5230 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
5231
5232 if (RT_FAILURE(rc))
5233 {
5234 pDevice->pDrvBase = NULL;
5235 pDevice->pDrvMedia = NULL;
5236 pDevice->pDrvMediaEx = NULL;
5237 }
5238 return rc;
5239}
5240
5241/**
5242 * Common reset worker.
5243 *
5244 * @param pDevIns The device instance data.
5245 */
5246static void lsilogicR3ResetCommon(PPDMDEVINS pDevIns)
5247{
5248 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5249 int rc;
5250
5251 rc = lsilogicR3HardReset(pThis);
5252 AssertRC(rc);
5253
5254 vboxscsiInitialize(&pThis->VBoxSCSI);
5255}
5256
5257/**
5258 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
5259 * Callback employed by lsilogicR3Reset.}
5260 */
5261static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns)
5262{
5263 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5264
5265 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5266 return false;
5267 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5268
5269 lsilogicR3ResetCommon(pDevIns);
5270 return true;
5271}
5272
5273/**
5274 * @interface_method_impl{PDMDEVREG,pfnReset}
5275 */
5276static DECLCALLBACK(void) lsilogicR3Reset(PPDMDEVINS pDevIns)
5277{
5278 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5279
5280 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
5281 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5282 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncResetDone);
5283 else
5284 {
5285 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5286 lsilogicR3ResetCommon(pDevIns);
5287 }
5288}
5289
5290/**
5291 * @interface_method_impl{PDMDEVREG,pfnRelocate}
5292 */
5293static DECLCALLBACK(void) lsilogicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
5294{
5295 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5296
5297 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5298 pThis->pNotificationQueueRC = PDMQueueRCPtr(pThis->pNotificationQueueR3);
5299
5300 /* Relocate queues. */
5301 pThis->pReplyFreeQueueBaseRC += offDelta;
5302 pThis->pReplyPostQueueBaseRC += offDelta;
5303 pThis->pRequestQueueBaseRC += offDelta;
5304}
5305
5306/**
5307 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
5308 */
5309static DECLCALLBACK(void) lsilogicR3PowerOff(PPDMDEVINS pDevIns)
5310{
5311 Log(("lsilogicR3PowerOff\n"));
5312 lsilogicR3SuspendOrPowerOff(pDevIns);
5313}
5314
5315/**
5316 * @interface_method_impl{PDMDEVREG,pfnDestruct}
5317 */
5318static DECLCALLBACK(int) lsilogicR3Destruct(PPDMDEVINS pDevIns)
5319{
5320 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5321 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5322
5323 PDMR3CritSectDelete(&pThis->ReplyFreeQueueCritSect);
5324 PDMR3CritSectDelete(&pThis->ReplyPostQueueCritSect);
5325 PDMR3CritSectDelete(&pThis->RequestQueueCritSect);
5326 PDMR3CritSectDelete(&pThis->ReplyFreeQueueWriteCritSect);
5327
5328 RTMemFree(pThis->paDeviceStates);
5329 pThis->paDeviceStates = NULL;
5330
5331 if (pThis->hEvtProcess != NIL_SUPSEMEVENT)
5332 {
5333 SUPSemEventClose(pThis->pSupDrvSession, pThis->hEvtProcess);
5334 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5335 }
5336
5337 lsilogicR3ConfigurationPagesFree(pThis);
5338 lsilogicR3MemRegionsFree(pThis);
5339
5340 return VINF_SUCCESS;
5341}
5342
5343/**
5344 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5345 */
5346static DECLCALLBACK(int) lsilogicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5347{
5348 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
5349 int rc = VINF_SUCCESS;
5350 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5351
5352 /*
5353 * Initialize enought of the state to make the destructure not trip up.
5354 */
5355 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5356 pThis->fBiosReqPending = false;
5357 RTListInit(&pThis->ListMemRegns);
5358
5359 /*
5360 * Validate and read configuration.
5361 */
5362 rc = CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
5363 "R0Enabled\0"
5364 "ReplyQueueDepth\0"
5365 "RequestQueueDepth\0"
5366 "ControllerType\0"
5367 "NumPorts\0"
5368 "Bootable\0");
5369 if (RT_FAILURE(rc))
5370 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
5371 N_("LsiLogic configuration error: unknown option specified"));
5372 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
5373 if (RT_FAILURE(rc))
5374 return PDMDEV_SET_ERROR(pDevIns, rc,
5375 N_("LsiLogic configuration error: failed to read GCEnabled as boolean"));
5376 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, pThis->fGCEnabled));
5377
5378 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
5379 if (RT_FAILURE(rc))
5380 return PDMDEV_SET_ERROR(pDevIns, rc,
5381 N_("LsiLogic configuration error: failed to read R0Enabled as boolean"));
5382 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, pThis->fR0Enabled));
5383
5384 rc = CFGMR3QueryU32Def(pCfg, "ReplyQueueDepth",
5385 &pThis->cReplyQueueEntries,
5386 LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT);
5387 if (RT_FAILURE(rc))
5388 return PDMDEV_SET_ERROR(pDevIns, rc,
5389 N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
5390 Log(("%s: ReplyQueueDepth=%u\n", __FUNCTION__, pThis->cReplyQueueEntries));
5391
5392 rc = CFGMR3QueryU32Def(pCfg, "RequestQueueDepth",
5393 &pThis->cRequestQueueEntries,
5394 LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT);
5395 if (RT_FAILURE(rc))
5396 return PDMDEV_SET_ERROR(pDevIns, rc,
5397 N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
5398 Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries));
5399
5400 char *pszCtrlType;
5401 rc = CFGMR3QueryStringAllocDef(pCfg, "ControllerType",
5402 &pszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME);
5403 if (RT_FAILURE(rc))
5404 return PDMDEV_SET_ERROR(pDevIns, rc,
5405 N_("LsiLogic configuration error: failed to read ControllerType as string"));
5406 Log(("%s: ControllerType=%s\n", __FUNCTION__, pszCtrlType));
5407
5408 rc = lsilogicR3GetCtrlTypeFromString(pThis, pszCtrlType);
5409 MMR3HeapFree(pszCtrlType);
5410
5411 char szDevTag[20];
5412 RTStrPrintf(szDevTag, sizeof(szDevTag), "LSILOGIC%s-%u",
5413 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "SPI" : "SAS",
5414 iInstance);
5415
5416
5417 if (RT_FAILURE(rc))
5418 return PDMDEV_SET_ERROR(pDevIns, rc,
5419 N_("LsiLogic configuration error: failed to determine controller type from string"));
5420
5421 rc = CFGMR3QueryU8(pCfg, "NumPorts",
5422 &pThis->cPorts);
5423 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5424 {
5425 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5426 pThis->cPorts = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
5427 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5428 pThis->cPorts = LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT;
5429 else
5430 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5431 }
5432 else if (RT_FAILURE(rc))
5433 return PDMDEV_SET_ERROR(pDevIns, rc,
5434 N_("LsiLogic configuration error: failed to read NumPorts as integer"));
5435
5436 bool fBootable;
5437 rc = CFGMR3QueryBoolDef(pCfg, "Bootable", &fBootable, true);
5438 if (RT_FAILURE(rc))
5439 return PDMDEV_SET_ERROR(pDevIns, rc,
5440 N_("LsiLogic configuration error: failed to read Bootable as boolean"));
5441 Log(("%s: Bootable=%RTbool\n", __FUNCTION__, fBootable));
5442
5443 /* Init static parts. */
5444 PCIDevSetVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_VENDOR_ID); /* LsiLogic */
5445
5446 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5447 {
5448 PCIDevSetDeviceId (&pThis->PciDev, LSILOGICSCSI_PCI_SPI_DEVICE_ID); /* LSI53C1030 */
5449 PCIDevSetSubSystemVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID);
5450 PCIDevSetSubSystemId (&pThis->PciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID);
5451 }
5452 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5453 {
5454 PCIDevSetDeviceId (&pThis->PciDev, LSILOGICSCSI_PCI_SAS_DEVICE_ID); /* SAS1068 */
5455 PCIDevSetSubSystemVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID);
5456 PCIDevSetSubSystemId (&pThis->PciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID);
5457 }
5458 else
5459 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5460
5461 PCIDevSetClassProg (&pThis->PciDev, 0x00); /* SCSI */
5462 PCIDevSetClassSub (&pThis->PciDev, 0x00); /* SCSI */
5463 PCIDevSetClassBase (&pThis->PciDev, 0x01); /* Mass storage */
5464 PCIDevSetInterruptPin(&pThis->PciDev, 0x01); /* Interrupt pin A */
5465
5466# ifdef VBOX_WITH_MSI_DEVICES
5467 PCIDevSetStatus(&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST);
5468 PCIDevSetCapabilityList(&pThis->PciDev, 0x80);
5469# endif
5470
5471 pThis->pDevInsR3 = pDevIns;
5472 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
5473 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
5474 pThis->pSupDrvSession = PDMDevHlpGetSupDrvSession(pDevIns);
5475 pThis->IBase.pfnQueryInterface = lsilogicR3StatusQueryInterface;
5476 pThis->ILeds.pfnQueryStatusLed = lsilogicR3StatusQueryStatusLed;
5477
5478 /*
5479 * Create critical sections protecting the reply post and free queues.
5480 * Note! We do our own syncronization, so NOP the default crit sect for the device.
5481 */
5482 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5483 AssertRCReturn(rc, rc);
5484
5485 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag);
5486 if (RT_FAILURE(rc))
5487 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue"));
5488
5489 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag);
5490 if (RT_FAILURE(rc))
5491 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply post queue"));
5492
5493 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->RequestQueueCritSect, RT_SRC_POS, "%sRQ", szDevTag);
5494 if (RT_FAILURE(rc))
5495 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for request queue"));
5496
5497 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueWriteCritSect, RT_SRC_POS, "%sRFQW", szDevTag);
5498 if (RT_FAILURE(rc))
5499 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue write access"));
5500
5501 /*
5502 * Register the PCI device, it's I/O regions.
5503 */
5504 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
5505 if (RT_FAILURE(rc))
5506 return rc;
5507
5508# ifdef VBOX_WITH_MSI_DEVICES
5509 PDMMSIREG MsiReg;
5510 RT_ZERO(MsiReg);
5511 /* use this code for MSI-X support */
5512# if 0
5513 MsiReg.cMsixVectors = 1;
5514 MsiReg.iMsixCapOffset = 0x80;
5515 MsiReg.iMsixNextOffset = 0x00;
5516 MsiReg.iMsixBar = 3;
5517# else
5518 MsiReg.cMsiVectors = 1;
5519 MsiReg.iMsiCapOffset = 0x80;
5520 MsiReg.iMsiNextOffset = 0x00;
5521# endif
5522 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
5523 if (RT_FAILURE (rc))
5524 {
5525 /* That's OK, we can work without MSI */
5526 PCIDevSetCapabilityList(&pThis->PciDev, 0x0);
5527 }
5528# endif
5529
5530 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicR3Map);
5531 if (RT_FAILURE(rc))
5532 return rc;
5533
5534 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicR3Map);
5535 if (RT_FAILURE(rc))
5536 return rc;
5537
5538 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicR3Map);
5539 if (RT_FAILURE(rc))
5540 return rc;
5541
5542 /* Initialize task queue. (Need two items to handle SMP guest concurrency.) */
5543 char szTaggedText[64];
5544 RTStrPrintf(szTaggedText, sizeof(szTaggedText), "%s-Task", szDevTag);
5545 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 2, 0,
5546 lsilogicR3NotifyQueueConsumer, true,
5547 szTaggedText,
5548 &pThis->pNotificationQueueR3);
5549 if (RT_FAILURE(rc))
5550 return rc;
5551 pThis->pNotificationQueueR0 = PDMQueueR0Ptr(pThis->pNotificationQueueR3);
5552 pThis->pNotificationQueueRC = PDMQueueRCPtr(pThis->pNotificationQueueR3);
5553
5554 /*
5555 * We need one entry free in the queue.
5556 */
5557 pThis->cReplyQueueEntries++;
5558 pThis->cRequestQueueEntries++;
5559
5560 /*
5561 * Allocate memory for the queues.
5562 */
5563 rc = lsilogicR3QueuesAlloc(pThis);
5564 if (RT_FAILURE(rc))
5565 return rc;
5566
5567 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5568 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
5569 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5570 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
5571 else
5572 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5573
5574 /*
5575 * Create event semaphore and worker thread.
5576 */
5577 rc = PDMDevHlpThreadCreate(pDevIns, &pThis->pThreadWrk, pThis, lsilogicR3Worker,
5578 lsilogicR3WorkerWakeUp, 0, RTTHREADTYPE_IO, szDevTag);
5579 if (RT_FAILURE(rc))
5580 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5581 N_("LsiLogic: Failed to create worker thread %s"), szDevTag);
5582
5583 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hEvtProcess);
5584 if (RT_FAILURE(rc))
5585 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5586 N_("LsiLogic: Failed to create SUP event semaphore"));
5587
5588 /*
5589 * Allocate device states.
5590 */
5591 pThis->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
5592 if (!pThis->paDeviceStates)
5593 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate memory for device states"));
5594
5595 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
5596 {
5597 char szName[24];
5598 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
5599
5600 /* Initialize static parts of the device. */
5601 pDevice->iLUN = i;
5602 pDevice->pLsiLogicR3 = pThis;
5603 pDevice->Led.u32Magic = PDMLED_MAGIC;
5604 pDevice->IBase.pfnQueryInterface = lsilogicR3DeviceQueryInterface;
5605 pDevice->IMediaPort.pfnQueryDeviceLocation = lsilogicR3QueryDeviceLocation;
5606 pDevice->IMediaExPort.pfnIoReqCompleteNotify = lsilogicR3IoReqCompleteNotify;
5607 pDevice->IMediaExPort.pfnIoReqCopyFromBuf = lsilogicR3IoReqCopyFromBuf;
5608 pDevice->IMediaExPort.pfnIoReqCopyToBuf = lsilogicR3IoReqCopyToBuf;
5609 pDevice->IMediaExPort.pfnIoReqQueryBuf = NULL;
5610 pDevice->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
5611 pDevice->IMediaExPort.pfnIoReqStateChanged = lsilogicR3IoReqStateChanged;
5612 pDevice->IMediaExPort.pfnMediumEjected = lsilogicR3MediumEjected;
5613 pDevice->ILed.pfnQueryStatusLed = lsilogicR3DeviceQueryStatusLed;
5614
5615 RTStrPrintf(szName, sizeof(szName), "Device%u", i);
5616
5617 /* Attach SCSI driver. */
5618 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, szName);
5619 if (RT_SUCCESS(rc))
5620 {
5621 /* Query the media interface. */
5622 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5623 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5624 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5625 VERR_PDM_MISSING_INTERFACE);
5626
5627 /* Get the extended media interface. */
5628 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5629 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5630 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5631 VERR_PDM_MISSING_INTERFACE);
5632
5633 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5634 if (RT_FAILURE(rc))
5635 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5636 N_("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!"),
5637 pDevice->iLUN);
5638 }
5639 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5640 {
5641 pDevice->pDrvBase = NULL;
5642 rc = VINF_SUCCESS;
5643 Log(("LsiLogic: no driver attached to device %s\n", szName));
5644 }
5645 else
5646 {
5647 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", szName));
5648 return rc;
5649 }
5650 }
5651
5652 /*
5653 * Attach status driver (optional).
5654 */
5655 PPDMIBASE pBase;
5656 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
5657 if (RT_SUCCESS(rc))
5658 {
5659 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5660 pThis->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
5661 }
5662 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
5663 {
5664 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5665 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver"));
5666 }
5667
5668 /* Initialize the SCSI emulation for the BIOS. */
5669 rc = vboxscsiInitialize(&pThis->VBoxSCSI);
5670 AssertRC(rc);
5671
5672 /*
5673 * Register I/O port space in ISA region for BIOS access
5674 * if the controller is marked as bootable.
5675 */
5676 if (fBootable)
5677 {
5678 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5679 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_BIOS_IO_PORT, 4, NULL,
5680 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5681 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr,
5682 "LsiLogic BIOS");
5683 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5684 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_SAS_BIOS_IO_PORT, 4, NULL,
5685 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5686 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr,
5687 "LsiLogic SAS BIOS");
5688 else
5689 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
5690
5691 if (RT_FAILURE(rc))
5692 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register legacy I/O handlers"));
5693 }
5694
5695 /* Register save state handlers. */
5696 rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5697 NULL, lsilogicR3LiveExec, NULL,
5698 NULL, lsilogicR3SaveExec, NULL,
5699 NULL, lsilogicR3LoadExec, lsilogicR3LoadDone);
5700 if (RT_FAILURE(rc))
5701 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
5702
5703 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
5704
5705 /*
5706 * Register the info item.
5707 */
5708 char szTmp[128];
5709 RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
5710 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp,
5711 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
5712 ? "LsiLogic SPI info."
5713 : "LsiLogic SAS info.", lsilogicR3Info);
5714
5715 /* Perform hard reset. */
5716 rc = lsilogicR3HardReset(pThis);
5717 AssertRC(rc);
5718
5719 return rc;
5720}
5721
5722/**
5723 * The device registration structure - SPI SCSI controller.
5724 */
5725const PDMDEVREG g_DeviceLsiLogicSCSI =
5726{
5727 /* u32Version */
5728 PDM_DEVREG_VERSION,
5729 /* szName */
5730 "lsilogicscsi",
5731 /* szRCMod */
5732 "VBoxDDRC.rc",
5733 /* szR0Mod */
5734 "VBoxDDR0.r0",
5735 /* pszDescription */
5736 "LSI Logic 53c1030 SCSI controller.\n",
5737 /* fFlags */
5738 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
5739 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
5740 /* fClass */
5741 PDM_DEVREG_CLASS_STORAGE,
5742 /* cMaxInstances */
5743 ~0U,
5744 /* cbInstance */
5745 sizeof(LSILOGICSCSI),
5746 /* pfnConstruct */
5747 lsilogicR3Construct,
5748 /* pfnDestruct */
5749 lsilogicR3Destruct,
5750 /* pfnRelocate */
5751 lsilogicR3Relocate,
5752 /* pfnMemSetup */
5753 NULL,
5754 /* pfnPowerOn */
5755 NULL,
5756 /* pfnReset */
5757 lsilogicR3Reset,
5758 /* pfnSuspend */
5759 lsilogicR3Suspend,
5760 /* pfnResume */
5761 lsilogicR3Resume,
5762 /* pfnAttach */
5763 lsilogicR3Attach,
5764 /* pfnDetach */
5765 lsilogicR3Detach,
5766 /* pfnQueryInterface. */
5767 NULL,
5768 /* pfnInitComplete */
5769 NULL,
5770 /* pfnPowerOff */
5771 lsilogicR3PowerOff,
5772 /* pfnSoftReset */
5773 NULL,
5774 /* u32VersionEnd */
5775 PDM_DEVREG_VERSION
5776};
5777
5778/**
5779 * The device registration structure - SAS controller.
5780 */
5781const PDMDEVREG g_DeviceLsiLogicSAS =
5782{
5783 /* u32Version */
5784 PDM_DEVREG_VERSION,
5785 /* szName */
5786 "lsilogicsas",
5787 /* szRCMod */
5788 "VBoxDDRC.rc",
5789 /* szR0Mod */
5790 "VBoxDDR0.r0",
5791 /* pszDescription */
5792 "LSI Logic SAS1068 controller.\n",
5793 /* fFlags */
5794 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
5795 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION |
5796 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
5797 /* fClass */
5798 PDM_DEVREG_CLASS_STORAGE,
5799 /* cMaxInstances */
5800 ~0U,
5801 /* cbInstance */
5802 sizeof(LSILOGICSCSI),
5803 /* pfnConstruct */
5804 lsilogicR3Construct,
5805 /* pfnDestruct */
5806 lsilogicR3Destruct,
5807 /* pfnRelocate */
5808 lsilogicR3Relocate,
5809 /* pfnMemSetup */
5810 NULL,
5811 /* pfnPowerOn */
5812 NULL,
5813 /* pfnReset */
5814 lsilogicR3Reset,
5815 /* pfnSuspend */
5816 lsilogicR3Suspend,
5817 /* pfnResume */
5818 lsilogicR3Resume,
5819 /* pfnAttach */
5820 lsilogicR3Attach,
5821 /* pfnDetach */
5822 lsilogicR3Detach,
5823 /* pfnQueryInterface. */
5824 NULL,
5825 /* pfnInitComplete */
5826 NULL,
5827 /* pfnPowerOff */
5828 lsilogicR3PowerOff,
5829 /* pfnSoftReset */
5830 NULL,
5831 /* u32VersionEnd */
5832 PDM_DEVREG_VERSION
5833};
5834
5835#endif /* IN_RING3 */
5836#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