VirtualBox

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

Last change on this file since 87164 was 87164, checked in by vboxsync, 4 years ago

Devices/DevLsiLogicSCSI: Stricter range check, bugref:9897

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