VirtualBox

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

Last change on this file since 81301 was 81031, checked in by vboxsync, 5 years ago

PDM,Devices: Moving the PDMPCIDEV structures into the PDMDEVINS allocation. Preps for extending the config space to 4KB. bugref:9218

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