VirtualBox

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

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

Devices/Storage/DevLsiLogicSCSI: Don't copy the sense buffer over if the guest has no sense buffer allocated, fixes debug assertion with the EFI MPT driver

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 249.1 KB
Line 
1/* $Id: DevLsiLogicSCSI.cpp 85994 2020-09-02 11:06:04Z 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 /* Check for a valid firmware image in the IOC memory which was downlaoded by tzhe guest earlier. */
1121 PLSILOGICMEMREGN pRegion = lsilogicR3MemRegionFindByAddr(pThisCC, LSILOGIC_FWIMGHDR_LOAD_ADDRESS);
1122
1123 if (pRegion)
1124 {
1125 uint32_t offImgHdr = (LSILOGIC_FWIMGHDR_LOAD_ADDRESS - pRegion->u32AddrStart) / 4;
1126 PFwImageHdr pFwImgHdr = (PFwImageHdr)&pRegion->au32Data[offImgHdr];
1127
1128 /* Check for the signature. */
1129 /** @todo Checksum validation. */
1130 if ( pFwImgHdr->u32Signature1 == LSILOGIC_FWIMGHDR_SIGNATURE1
1131 && pFwImgHdr->u32Signature2 == LSILOGIC_FWIMGHDR_SIGNATURE2
1132 && pFwImgHdr->u32Signature3 == LSILOGIC_FWIMGHDR_SIGNATURE3)
1133 {
1134 LogFlowFunc(("IOC Facts: Found valid firmware image header in memory, using version (%#x), size (%d) and product ID (%#x) from there\n",
1135 pFwImgHdr->u32FwVersion, pFwImgHdr->u32ImageSize, pFwImgHdr->u16ProductId));
1136
1137 pReply->IOCFacts.u16ProductID = pFwImgHdr->u16ProductId;
1138 pReply->IOCFacts.u32FwImageSize = pFwImgHdr->u32ImageSize;
1139 pReply->IOCFacts.u32FWVersion = pFwImgHdr->u32FwVersion;
1140 }
1141 }
1142 else
1143 {
1144 pReply->IOCFacts.u16ProductID = 0xcafe; /* Our own product ID :) */
1145 pReply->IOCFacts.u32FwImageSize = 0; /* No image needed. */
1146 pReply->IOCFacts.u32FWVersion = 0;
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 PDMDevHlpPhysReadUser(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 PDMDevHlpPhysReadMeta(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 PDMDevHlpPhysReadMeta(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.u32MessageContext = pGuestReq->SCSIIO.u32MessageContext;
2330 IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK;
2331 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED;
2332 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2333 IOCReply.SCSIIOError.u32TransferCount = 0;
2334 IOCReply.SCSIIOError.u32SenseCount = 0;
2335 IOCReply.SCSIIOError.u32ResponseInfo = 0;
2336
2337 lsilogicFinishAddressReply(pDevIns, pThis, &IOCReply, false);
2338
2339 return rc;
2340}
2341
2342
2343/**
2344 * @interface_method_impl{PDMIMEDIAPORT,pfnQueryDeviceLocation}
2345 */
2346static DECLCALLBACK(int) lsilogicR3QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
2347 uint32_t *piInstance, uint32_t *piLUN)
2348{
2349 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaPort);
2350 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2351
2352 AssertPtrReturn(ppcszController, VERR_INVALID_POINTER);
2353 AssertPtrReturn(piInstance, VERR_INVALID_POINTER);
2354 AssertPtrReturn(piLUN, VERR_INVALID_POINTER);
2355
2356 *ppcszController = pDevIns->pReg->szName;
2357 *piInstance = pDevIns->iInstance;
2358 *piLUN = pTgtDev->iLUN;
2359
2360 return VINF_SUCCESS;
2361}
2362
2363
2364/**
2365 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
2366 */
2367static DECLCALLBACK(int) lsilogicR3IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2368 void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
2369 size_t cbCopy)
2370{
2371 RT_NOREF1(hIoReq);
2372 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2373 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2374 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
2375 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
2376
2377 size_t cbCopied = 0;
2378 if (!pReq->fBIOS)
2379 cbCopied = lsilogicR3CopySgBufToGuest(pDevIns, pReq, pSgBuf, offDst, cbCopy);
2380 else
2381 cbCopied = vboxscsiCopyToBuf(&pThisCC->VBoxSCSI, pSgBuf, offDst, cbCopy);
2382 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
2383}
2384
2385/**
2386 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
2387 */
2388static DECLCALLBACK(int) lsilogicR3IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2389 void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
2390 size_t cbCopy)
2391{
2392 RT_NOREF1(hIoReq);
2393 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2394 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2395 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
2396 PLSILOGICREQ pReq = (PLSILOGICREQ)pvIoReqAlloc;
2397
2398 size_t cbCopied = 0;
2399 if (!pReq->fBIOS)
2400 cbCopied = lsilogicR3CopySgBufFromGuest(pDevIns, pReq, pSgBuf, offSrc, cbCopy);
2401 else
2402 cbCopied = vboxscsiCopyFromBuf(&pThisCC->VBoxSCSI, pSgBuf, offSrc, cbCopy);
2403 return cbCopied == cbCopy ? VINF_SUCCESS : VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
2404}
2405
2406/**
2407 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
2408 */
2409static DECLCALLBACK(int) lsilogicR3IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2410 void *pvIoReqAlloc, int rcReq)
2411{
2412 RT_NOREF(hIoReq);
2413 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2414 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2415 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
2416 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
2417 lsilogicR3ReqComplete(pDevIns, pThis, pThisCC, (PLSILOGICREQ)pvIoReqAlloc, rcReq);
2418 return VINF_SUCCESS;
2419}
2420
2421/**
2422 * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
2423 */
2424static DECLCALLBACK(void) lsilogicR3IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
2425 void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
2426{
2427 RT_NOREF3(hIoReq, pvIoReqAlloc, enmState);
2428 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2429
2430 switch (enmState)
2431 {
2432 case PDMMEDIAEXIOREQSTATE_SUSPENDED:
2433 {
2434 /* Make sure the request is not accounted for so the VM can suspend successfully. */
2435 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2436 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
2437 uint32_t cTasksActive = ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
2438 if (!cTasksActive && pThis->fSignalIdle)
2439 PDMDevHlpAsyncNotificationCompleted(pDevIns);
2440 break;
2441 }
2442 case PDMMEDIAEXIOREQSTATE_ACTIVE:
2443 /* Make sure the request is accounted for so the VM suspends only when the request is complete. */
2444 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2445 break;
2446 default:
2447 AssertMsgFailed(("Invalid request state given %u\n", enmState));
2448 }
2449}
2450
2451/**
2452 * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
2453 */
2454static DECLCALLBACK(void) lsilogicR3MediumEjected(PPDMIMEDIAEXPORT pInterface)
2455{
2456 PLSILOGICDEVICE pTgtDev = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IMediaExPort);
2457 PPDMDEVINS pDevIns = pTgtDev->pDevIns;
2458 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
2459
2460 if (pThisCC->pMediaNotify)
2461 {
2462 int rc = VMR3ReqCallNoWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
2463 (PFNRT)pThisCC->pMediaNotify->pfnEjected, 2,
2464 pThisCC->pMediaNotify, pTgtDev->iLUN);
2465 AssertRC(rc);
2466 }
2467}
2468
2469
2470/**
2471 * Return the configuration page header and data
2472 * which matches the given page type and number.
2473 *
2474 * @returns VINF_SUCCESS if successful
2475 * VERR_NOT_FOUND if the requested page could be found.
2476 * @param pThis Pointer to the shared LsiLogic device state. data.
2477 * @param pPages The pages supported by the controller.
2478 * @param u8PageNumber Number of the page to get.
2479 * @param ppPageHeader Where to store the pointer to the page header.
2480 * @param ppbPageData Where to store the pointer to the page data.
2481 * @param pcbPage Where to store the size of the page data in bytes on success.
2482 */
2483static int lsilogicR3ConfigurationIOUnitPageGetFromNumber(PLSILOGICSCSI pThis,
2484 PMptConfigurationPagesSupported pPages,
2485 uint8_t u8PageNumber,
2486 PMptConfigurationPageHeader *ppPageHeader,
2487 uint8_t **ppbPageData, size_t *pcbPage)
2488{
2489 RT_NOREF(pThis);
2490 int rc = VINF_SUCCESS;
2491
2492 AssertPtr(ppPageHeader); Assert(ppbPageData);
2493
2494 switch (u8PageNumber)
2495 {
2496 case 0:
2497 *ppPageHeader = &pPages->IOUnitPage0.u.fields.Header;
2498 *ppbPageData = pPages->IOUnitPage0.u.abPageData;
2499 *pcbPage = sizeof(pPages->IOUnitPage0);
2500 break;
2501 case 1:
2502 *ppPageHeader = &pPages->IOUnitPage1.u.fields.Header;
2503 *ppbPageData = pPages->IOUnitPage1.u.abPageData;
2504 *pcbPage = sizeof(pPages->IOUnitPage1);
2505 break;
2506 case 2:
2507 *ppPageHeader = &pPages->IOUnitPage2.u.fields.Header;
2508 *ppbPageData = pPages->IOUnitPage2.u.abPageData;
2509 *pcbPage = sizeof(pPages->IOUnitPage2);
2510 break;
2511 case 3:
2512 *ppPageHeader = &pPages->IOUnitPage3.u.fields.Header;
2513 *ppbPageData = pPages->IOUnitPage3.u.abPageData;
2514 *pcbPage = sizeof(pPages->IOUnitPage3);
2515 break;
2516 case 4:
2517 *ppPageHeader = &pPages->IOUnitPage4.u.fields.Header;
2518 *ppbPageData = pPages->IOUnitPage4.u.abPageData;
2519 *pcbPage = sizeof(pPages->IOUnitPage4);
2520 break;
2521 default:
2522 rc = VERR_NOT_FOUND;
2523 }
2524
2525 return rc;
2526}
2527
2528/**
2529 * Return the configuration page header and data
2530 * which matches the given page type and number.
2531 *
2532 * @returns VINF_SUCCESS if successful
2533 * VERR_NOT_FOUND if the requested page could be found.
2534 * @param pThis Pointer to the shared LsiLogic device state. data.
2535 * @param pPages The pages supported by the controller.
2536 * @param u8PageNumber Number of the page to get.
2537 * @param ppPageHeader Where to store the pointer to the page header.
2538 * @param ppbPageData Where to store the pointer to the page data.
2539 * @param pcbPage Where to store the size of the page data in bytes on success.
2540 */
2541static int lsilogicR3ConfigurationIOCPageGetFromNumber(PLSILOGICSCSI pThis,
2542 PMptConfigurationPagesSupported pPages,
2543 uint8_t u8PageNumber,
2544 PMptConfigurationPageHeader *ppPageHeader,
2545 uint8_t **ppbPageData, size_t *pcbPage)
2546{
2547 RT_NOREF(pThis);
2548 int rc = VINF_SUCCESS;
2549
2550 AssertPtr(ppPageHeader); Assert(ppbPageData);
2551
2552 switch (u8PageNumber)
2553 {
2554 case 0:
2555 *ppPageHeader = &pPages->IOCPage0.u.fields.Header;
2556 *ppbPageData = pPages->IOCPage0.u.abPageData;
2557 *pcbPage = sizeof(pPages->IOCPage0);
2558 break;
2559 case 1:
2560 *ppPageHeader = &pPages->IOCPage1.u.fields.Header;
2561 *ppbPageData = pPages->IOCPage1.u.abPageData;
2562 *pcbPage = sizeof(pPages->IOCPage1);
2563 break;
2564 case 2:
2565 *ppPageHeader = &pPages->IOCPage2.u.fields.Header;
2566 *ppbPageData = pPages->IOCPage2.u.abPageData;
2567 *pcbPage = sizeof(pPages->IOCPage2);
2568 break;
2569 case 3:
2570 *ppPageHeader = &pPages->IOCPage3.u.fields.Header;
2571 *ppbPageData = pPages->IOCPage3.u.abPageData;
2572 *pcbPage = sizeof(pPages->IOCPage3);
2573 break;
2574 case 4:
2575 *ppPageHeader = &pPages->IOCPage4.u.fields.Header;
2576 *ppbPageData = pPages->IOCPage4.u.abPageData;
2577 *pcbPage = sizeof(pPages->IOCPage4);
2578 break;
2579 case 6:
2580 *ppPageHeader = &pPages->IOCPage6.u.fields.Header;
2581 *ppbPageData = pPages->IOCPage6.u.abPageData;
2582 *pcbPage = sizeof(pPages->IOCPage6);
2583 break;
2584 default:
2585 rc = VERR_NOT_FOUND;
2586 }
2587
2588 return rc;
2589}
2590
2591/**
2592 * Return the configuration page header and data
2593 * which matches the given page type and number.
2594 *
2595 * @returns VINF_SUCCESS if successful
2596 * VERR_NOT_FOUND if the requested page could be found.
2597 * @param pThis Pointer to the shared LsiLogic device state. data.
2598 * @param pPages The pages supported by the controller.
2599 * @param u8PageNumber Number of the page to get.
2600 * @param ppPageHeader Where to store the pointer to the page header.
2601 * @param ppbPageData Where to store the pointer to the page data.
2602 * @param pcbPage Where to store the size of the page data in bytes on success.
2603 */
2604static int lsilogicR3ConfigurationManufacturingPageGetFromNumber(PLSILOGICSCSI pThis,
2605 PMptConfigurationPagesSupported pPages,
2606 uint8_t u8PageNumber,
2607 PMptConfigurationPageHeader *ppPageHeader,
2608 uint8_t **ppbPageData, size_t *pcbPage)
2609{
2610 int rc = VINF_SUCCESS;
2611
2612 AssertPtr(ppPageHeader); Assert(ppbPageData);
2613
2614 switch (u8PageNumber)
2615 {
2616 case 0:
2617 *ppPageHeader = &pPages->ManufacturingPage0.u.fields.Header;
2618 *ppbPageData = pPages->ManufacturingPage0.u.abPageData;
2619 *pcbPage = sizeof(pPages->ManufacturingPage0);
2620 break;
2621 case 1:
2622 *ppPageHeader = &pPages->ManufacturingPage1.u.fields.Header;
2623 *ppbPageData = pPages->ManufacturingPage1.u.abPageData;
2624 *pcbPage = sizeof(pPages->ManufacturingPage1);
2625 break;
2626 case 2:
2627 *ppPageHeader = &pPages->ManufacturingPage2.u.fields.Header;
2628 *ppbPageData = pPages->ManufacturingPage2.u.abPageData;
2629 *pcbPage = sizeof(pPages->ManufacturingPage2);
2630 break;
2631 case 3:
2632 *ppPageHeader = &pPages->ManufacturingPage3.u.fields.Header;
2633 *ppbPageData = pPages->ManufacturingPage3.u.abPageData;
2634 *pcbPage = sizeof(pPages->ManufacturingPage3);
2635 break;
2636 case 4:
2637 *ppPageHeader = &pPages->ManufacturingPage4.u.fields.Header;
2638 *ppbPageData = pPages->ManufacturingPage4.u.abPageData;
2639 *pcbPage = sizeof(pPages->ManufacturingPage4);
2640 break;
2641 case 5:
2642 *ppPageHeader = &pPages->ManufacturingPage5.u.fields.Header;
2643 *ppbPageData = pPages->ManufacturingPage5.u.abPageData;
2644 *pcbPage = sizeof(pPages->ManufacturingPage5);
2645 break;
2646 case 6:
2647 *ppPageHeader = &pPages->ManufacturingPage6.u.fields.Header;
2648 *ppbPageData = pPages->ManufacturingPage6.u.abPageData;
2649 *pcbPage = sizeof(pPages->ManufacturingPage6);
2650 break;
2651 case 7:
2652 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
2653 {
2654 *ppPageHeader = &pPages->u.SasPages.pManufacturingPage7->u.fields.Header;
2655 *ppbPageData = pPages->u.SasPages.pManufacturingPage7->u.abPageData;
2656 *pcbPage = pPages->u.SasPages.cbManufacturingPage7;
2657 }
2658 else
2659 rc = VERR_NOT_FOUND;
2660 break;
2661 case 8:
2662 *ppPageHeader = &pPages->ManufacturingPage8.u.fields.Header;
2663 *ppbPageData = pPages->ManufacturingPage8.u.abPageData;
2664 *pcbPage = sizeof(pPages->ManufacturingPage8);
2665 break;
2666 case 9:
2667 *ppPageHeader = &pPages->ManufacturingPage9.u.fields.Header;
2668 *ppbPageData = pPages->ManufacturingPage9.u.abPageData;
2669 *pcbPage = sizeof(pPages->ManufacturingPage9);
2670 break;
2671 case 10:
2672 *ppPageHeader = &pPages->ManufacturingPage10.u.fields.Header;
2673 *ppbPageData = pPages->ManufacturingPage10.u.abPageData;
2674 *pcbPage = sizeof(pPages->ManufacturingPage10);
2675 break;
2676 default:
2677 rc = VERR_NOT_FOUND;
2678 }
2679
2680 return rc;
2681}
2682
2683/**
2684 * Return the configuration page header and data
2685 * which matches the given page type and number.
2686 *
2687 * @returns VINF_SUCCESS if successful
2688 * VERR_NOT_FOUND if the requested page could be found.
2689 * @param pThis Pointer to the shared LsiLogic device state. data.
2690 * @param pPages The pages supported by the controller.
2691 * @param u8PageNumber Number of the page to get.
2692 * @param ppPageHeader Where to store the pointer to the page header.
2693 * @param ppbPageData Where to store the pointer to the page data.
2694 * @param pcbPage Where to store the size of the page data in bytes on success.
2695 */
2696static int lsilogicR3ConfigurationBiosPageGetFromNumber(PLSILOGICSCSI pThis,
2697 PMptConfigurationPagesSupported pPages,
2698 uint8_t u8PageNumber,
2699 PMptConfigurationPageHeader *ppPageHeader,
2700 uint8_t **ppbPageData, size_t *pcbPage)
2701{
2702 RT_NOREF(pThis);
2703 int rc = VINF_SUCCESS;
2704
2705 AssertPtr(ppPageHeader); Assert(ppbPageData);
2706
2707 switch (u8PageNumber)
2708 {
2709 case 1:
2710 *ppPageHeader = &pPages->BIOSPage1.u.fields.Header;
2711 *ppbPageData = pPages->BIOSPage1.u.abPageData;
2712 *pcbPage = sizeof(pPages->BIOSPage1);
2713 break;
2714 case 2:
2715 *ppPageHeader = &pPages->BIOSPage2.u.fields.Header;
2716 *ppbPageData = pPages->BIOSPage2.u.abPageData;
2717 *pcbPage = sizeof(pPages->BIOSPage2);
2718 break;
2719 case 4:
2720 *ppPageHeader = &pPages->BIOSPage4.u.fields.Header;
2721 *ppbPageData = pPages->BIOSPage4.u.abPageData;
2722 *pcbPage = sizeof(pPages->BIOSPage4);
2723 break;
2724 default:
2725 rc = VERR_NOT_FOUND;
2726 }
2727
2728 return rc;
2729}
2730
2731/**
2732 * Return the configuration page header and data
2733 * which matches the given page type and number.
2734 *
2735 * @returns VINF_SUCCESS if successful
2736 * VERR_NOT_FOUND if the requested page could be found.
2737 * @param pThis Pointer to the shared LsiLogic device state. data.
2738 * @param pPages The pages supported by the controller.
2739 * @param u8Port The port to retrieve the page for.
2740 * @param u8PageNumber Number of the page to get.
2741 * @param ppPageHeader Where to store the pointer to the page header.
2742 * @param ppbPageData Where to store the pointer to the page data.
2743 * @param pcbPage Where to store the size of the page data in bytes on success.
2744 */
2745static int lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(PLSILOGICSCSI pThis,
2746 PMptConfigurationPagesSupported pPages,
2747 uint8_t u8Port,
2748 uint8_t u8PageNumber,
2749 PMptConfigurationPageHeader *ppPageHeader,
2750 uint8_t **ppbPageData, size_t *pcbPage)
2751{
2752 RT_NOREF(pThis);
2753 int rc = VINF_SUCCESS;
2754 AssertPtr(ppPageHeader); Assert(ppbPageData);
2755
2756
2757 if (u8Port >= RT_ELEMENTS(pPages->u.SpiPages.aPortPages))
2758 return VERR_NOT_FOUND;
2759
2760 switch (u8PageNumber)
2761 {
2762 case 0:
2763 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.fields.Header;
2764 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0.u.abPageData;
2765 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage0);
2766 break;
2767 case 1:
2768 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.fields.Header;
2769 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1.u.abPageData;
2770 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage1);
2771 break;
2772 case 2:
2773 *ppPageHeader = &pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.fields.Header;
2774 *ppbPageData = pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2.u.abPageData;
2775 *pcbPage = sizeof(pPages->u.SpiPages.aPortPages[u8Port].SCSISPIPortPage2);
2776 break;
2777 default:
2778 rc = VERR_NOT_FOUND;
2779 }
2780
2781 return rc;
2782}
2783
2784/**
2785 * Return the configuration page header and data
2786 * which matches the given page type and number.
2787 *
2788 * @returns VINF_SUCCESS if successful
2789 * VERR_NOT_FOUND if the requested page could be found.
2790 * @param pThis Pointer to the shared LsiLogic device state. data.
2791 * @param pPages The pages supported by the controller.
2792 * @param u8Bus The bus the device is on the page should be returned.
2793 * @param u8TargetID The target ID of the device to return the page for.
2794 * @param u8PageNumber Number of the page to get.
2795 * @param ppPageHeader Where to store the pointer to the page header.
2796 * @param ppbPageData Where to store the pointer to the page data.
2797 * @param pcbPage Where to store the size of the page data in bytes on success.
2798 */
2799static int lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(PLSILOGICSCSI pThis,
2800 PMptConfigurationPagesSupported pPages,
2801 uint8_t u8Bus,
2802 uint8_t u8TargetID, uint8_t u8PageNumber,
2803 PMptConfigurationPageHeader *ppPageHeader,
2804 uint8_t **ppbPageData, size_t *pcbPage)
2805{
2806 RT_NOREF(pThis);
2807 int rc = VINF_SUCCESS;
2808 AssertPtr(ppPageHeader); Assert(ppbPageData);
2809
2810 if (u8Bus >= RT_ELEMENTS(pPages->u.SpiPages.aBuses))
2811 return VERR_NOT_FOUND;
2812
2813 if (u8TargetID >= RT_ELEMENTS(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages))
2814 return VERR_NOT_FOUND;
2815
2816 switch (u8PageNumber)
2817 {
2818 case 0:
2819 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.fields.Header;
2820 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0.u.abPageData;
2821 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage0);
2822 break;
2823 case 1:
2824 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.fields.Header;
2825 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1.u.abPageData;
2826 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage1);
2827 break;
2828 case 2:
2829 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.fields.Header;
2830 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2.u.abPageData;
2831 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage2);
2832 break;
2833 case 3:
2834 *ppPageHeader = &pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.fields.Header;
2835 *ppbPageData = pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3.u.abPageData;
2836 *pcbPage = sizeof(pPages->u.SpiPages.aBuses[u8Bus].aDevicePages[u8TargetID].SCSISPIDevicePage3);
2837 break;
2838 default:
2839 rc = VERR_NOT_FOUND;
2840 }
2841
2842 return rc;
2843}
2844
2845static int lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(PMptConfigurationPagesSupported pPages,
2846 uint8_t u8PageNumber,
2847 PMptExtendedConfigurationPageHeader *ppPageHeader,
2848 uint8_t **ppbPageData, size_t *pcbPage)
2849{
2850 int rc = VINF_SUCCESS;
2851
2852 switch (u8PageNumber)
2853 {
2854 case 0:
2855 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage0->u.fields.ExtHeader;
2856 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage0->u.abPageData;
2857 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage0;
2858 break;
2859 case 1:
2860 *ppPageHeader = &pPages->u.SasPages.pSASIOUnitPage1->u.fields.ExtHeader;
2861 *ppbPageData = pPages->u.SasPages.pSASIOUnitPage1->u.abPageData;
2862 *pcbPage = pPages->u.SasPages.cbSASIOUnitPage1;
2863 break;
2864 case 2:
2865 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage2.u.fields.ExtHeader;
2866 *ppbPageData = pPages->u.SasPages.SASIOUnitPage2.u.abPageData;
2867 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage2);
2868 break;
2869 case 3:
2870 *ppPageHeader = &pPages->u.SasPages.SASIOUnitPage3.u.fields.ExtHeader;
2871 *ppbPageData = pPages->u.SasPages.SASIOUnitPage3.u.abPageData;
2872 *pcbPage = sizeof(pPages->u.SasPages.SASIOUnitPage3);
2873 break;
2874 default:
2875 rc = VERR_NOT_FOUND;
2876 }
2877
2878 return rc;
2879}
2880
2881static int lsilogicR3ConfigurationSASPHYPageGetFromNumber(PMptConfigurationPagesSupported pPages,
2882 uint8_t u8PageNumber,
2883 MptConfigurationPageAddress PageAddress,
2884 PMptExtendedConfigurationPageHeader *ppPageHeader,
2885 uint8_t **ppbPageData, size_t *pcbPage)
2886{
2887 int rc = VINF_SUCCESS;
2888 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2889 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
2890 PMptPHY pPHYPages = NULL;
2891
2892 Log(("Address form %d\n", uAddressForm));
2893
2894 if (uAddressForm == 0) /* PHY number */
2895 {
2896 uint8_t u8PhyNumber = PageAddress.SASPHY.Form0.u8PhyNumber;
2897
2898 Log(("PHY number %d\n", u8PhyNumber));
2899
2900 if (u8PhyNumber >= pPagesSas->cPHYs)
2901 return VERR_NOT_FOUND;
2902
2903 pPHYPages = &pPagesSas->paPHYs[u8PhyNumber];
2904 }
2905 else if (uAddressForm == 1) /* Index form */
2906 {
2907 uint16_t u16Index = PageAddress.SASPHY.Form1.u16Index;
2908
2909 Log(("PHY index %d\n", u16Index));
2910
2911 if (u16Index >= pPagesSas->cPHYs)
2912 return VERR_NOT_FOUND;
2913
2914 pPHYPages = &pPagesSas->paPHYs[u16Index];
2915 }
2916 else
2917 rc = VERR_NOT_FOUND; /* Correct? */
2918
2919 if (pPHYPages)
2920 {
2921 switch (u8PageNumber)
2922 {
2923 case 0:
2924 *ppPageHeader = &pPHYPages->SASPHYPage0.u.fields.ExtHeader;
2925 *ppbPageData = pPHYPages->SASPHYPage0.u.abPageData;
2926 *pcbPage = sizeof(pPHYPages->SASPHYPage0);
2927 break;
2928 case 1:
2929 *ppPageHeader = &pPHYPages->SASPHYPage1.u.fields.ExtHeader;
2930 *ppbPageData = pPHYPages->SASPHYPage1.u.abPageData;
2931 *pcbPage = sizeof(pPHYPages->SASPHYPage1);
2932 break;
2933 default:
2934 rc = VERR_NOT_FOUND;
2935 }
2936 }
2937 else
2938 rc = VERR_NOT_FOUND;
2939
2940 return rc;
2941}
2942
2943static int lsilogicR3ConfigurationSASDevicePageGetFromNumber(PMptConfigurationPagesSupported pPages,
2944 uint8_t u8PageNumber,
2945 MptConfigurationPageAddress PageAddress,
2946 PMptExtendedConfigurationPageHeader *ppPageHeader,
2947 uint8_t **ppbPageData, size_t *pcbPage)
2948{
2949 int rc = VINF_SUCCESS;
2950 uint8_t uAddressForm = MPT_CONFIGURATION_PAGE_ADDRESS_GET_SAS_FORM(PageAddress);
2951 PMptConfigurationPagesSas pPagesSas = &pPages->u.SasPages;
2952 PMptSASDevice pSASDevice = NULL;
2953
2954 Log(("Address form %d\n", uAddressForm));
2955
2956 if (uAddressForm == 0)
2957 {
2958 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
2959
2960 Log(("Get next handle %#x\n", u16Handle));
2961
2962 pSASDevice = pPagesSas->pSASDeviceHead;
2963
2964 /* Get the first device? */
2965 if (u16Handle != 0xffff)
2966 {
2967 /* No, search for the right one. */
2968
2969 while ( pSASDevice
2970 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
2971 pSASDevice = pSASDevice->pNext;
2972
2973 if (pSASDevice)
2974 pSASDevice = pSASDevice->pNext;
2975 }
2976 }
2977 else if (uAddressForm == 1)
2978 {
2979 uint8_t u8TargetID = PageAddress.SASDevice.Form1.u8TargetID;
2980 uint8_t u8Bus = PageAddress.SASDevice.Form1.u8Bus;
2981
2982 Log(("u8TargetID=%d u8Bus=%d\n", u8TargetID, u8Bus));
2983
2984 pSASDevice = pPagesSas->pSASDeviceHead;
2985
2986 while ( pSASDevice
2987 && ( pSASDevice->SASDevicePage0.u.fields.u8TargetID != u8TargetID
2988 || pSASDevice->SASDevicePage0.u.fields.u8Bus != u8Bus))
2989 pSASDevice = pSASDevice->pNext;
2990 }
2991 else if (uAddressForm == 2)
2992 {
2993 uint16_t u16Handle = PageAddress.SASDevice.Form0And2.u16Handle;
2994
2995 Log(("Handle %#x\n", u16Handle));
2996
2997 pSASDevice = pPagesSas->pSASDeviceHead;
2998
2999 while ( pSASDevice
3000 && pSASDevice->SASDevicePage0.u.fields.u16DevHandle != u16Handle)
3001 pSASDevice = pSASDevice->pNext;
3002 }
3003
3004 if (pSASDevice)
3005 {
3006 switch (u8PageNumber)
3007 {
3008 case 0:
3009 *ppPageHeader = &pSASDevice->SASDevicePage0.u.fields.ExtHeader;
3010 *ppbPageData = pSASDevice->SASDevicePage0.u.abPageData;
3011 *pcbPage = sizeof(pSASDevice->SASDevicePage0);
3012 break;
3013 case 1:
3014 *ppPageHeader = &pSASDevice->SASDevicePage1.u.fields.ExtHeader;
3015 *ppbPageData = pSASDevice->SASDevicePage1.u.abPageData;
3016 *pcbPage = sizeof(pSASDevice->SASDevicePage1);
3017 break;
3018 case 2:
3019 *ppPageHeader = &pSASDevice->SASDevicePage2.u.fields.ExtHeader;
3020 *ppbPageData = pSASDevice->SASDevicePage2.u.abPageData;
3021 *pcbPage = sizeof(pSASDevice->SASDevicePage2);
3022 break;
3023 default:
3024 rc = VERR_NOT_FOUND;
3025 }
3026 }
3027 else
3028 rc = VERR_NOT_FOUND;
3029
3030 return rc;
3031}
3032
3033/**
3034 * Returns the extended configuration page header and data.
3035 * @returns VINF_SUCCESS if successful
3036 * VERR_NOT_FOUND if the requested page could be found.
3037 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3038 * @param pConfigurationReq The configuration request.
3039 * @param ppPageHeader Where to return the pointer to the page header on success.
3040 * @param ppbPageData Where to store the pointer to the page data.
3041 * @param pcbPage Where to store the size of the page in bytes.
3042 */
3043static int lsilogicR3ConfigurationPageGetExtended(PLSILOGICSCSICC pThisCC, PMptConfigurationRequest pConfigurationReq,
3044 PMptExtendedConfigurationPageHeader *ppPageHeader,
3045 uint8_t **ppbPageData, size_t *pcbPage)
3046{
3047 int rc = VINF_SUCCESS;
3048
3049 Log(("Extended page requested:\n"));
3050 Log(("u8ExtPageType=%#x\n", pConfigurationReq->u8ExtPageType));
3051 Log(("u8ExtPageLength=%d\n", pConfigurationReq->u16ExtPageLength));
3052
3053 switch (pConfigurationReq->u8ExtPageType)
3054 {
3055 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT:
3056 {
3057 rc = lsilogicR3ConfigurationSASIOUnitPageGetFromNumber(pThisCC->pConfigurationPages,
3058 pConfigurationReq->u8PageNumber,
3059 ppPageHeader, ppbPageData, pcbPage);
3060 break;
3061 }
3062 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS:
3063 {
3064 rc = lsilogicR3ConfigurationSASPHYPageGetFromNumber(pThisCC->pConfigurationPages,
3065 pConfigurationReq->u8PageNumber,
3066 pConfigurationReq->PageAddress,
3067 ppPageHeader, ppbPageData, pcbPage);
3068 break;
3069 }
3070 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE:
3071 {
3072 rc = lsilogicR3ConfigurationSASDevicePageGetFromNumber(pThisCC->pConfigurationPages,
3073 pConfigurationReq->u8PageNumber,
3074 pConfigurationReq->PageAddress,
3075 ppPageHeader, ppbPageData, pcbPage);
3076 break;
3077 }
3078 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASEXPANDER: /* No expanders supported */
3079 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_ENCLOSURE: /* No enclosures supported */
3080 default:
3081 rc = VERR_NOT_FOUND;
3082 }
3083
3084 return rc;
3085}
3086
3087/**
3088 * Processes a Configuration request.
3089 *
3090 * @returns VBox status code.
3091 * @param pDevIns The device instance.
3092 * @param pThis Pointer to the shared LsiLogic device state.
3093 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3094 * @param pConfigurationReq Pointer to the request structure.
3095 * @param pReply Pointer to the reply message frame
3096 */
3097static int lsilogicR3ProcessConfigurationRequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
3098 PMptConfigurationRequest pConfigurationReq, PMptConfigurationReply pReply)
3099{
3100 int rc = VINF_SUCCESS;
3101 uint8_t *pbPageData = NULL;
3102 PMptConfigurationPageHeader pPageHeader = NULL;
3103 PMptExtendedConfigurationPageHeader pExtPageHeader = NULL;
3104 uint8_t u8PageType;
3105 uint8_t u8PageAttribute;
3106 size_t cbPage = 0;
3107
3108 LogFlowFunc(("pThis=%#p\n", pThis));
3109
3110 u8PageType = MPT_CONFIGURATION_PAGE_TYPE_GET(pConfigurationReq->u8PageType);
3111 u8PageAttribute = MPT_CONFIGURATION_PAGE_ATTRIBUTE_GET(pConfigurationReq->u8PageType);
3112
3113 Log(("GuestRequest:\n"));
3114 Log(("u8Action=%#x\n", pConfigurationReq->u8Action));
3115 Log(("u8PageType=%#x\n", u8PageType));
3116 Log(("u8PageNumber=%d\n", pConfigurationReq->u8PageNumber));
3117 Log(("u8PageLength=%d\n", pConfigurationReq->u8PageLength));
3118 Log(("u8PageVersion=%d\n", pConfigurationReq->u8PageVersion));
3119
3120 /* Copy common bits from the request into the reply. */
3121 pReply->u8MessageLength = 6; /* 6 32bit D-Words. */
3122 pReply->u8Action = pConfigurationReq->u8Action;
3123 pReply->u8Function = pConfigurationReq->u8Function;
3124 pReply->u32MessageContext = pConfigurationReq->u32MessageContext;
3125
3126 switch (u8PageType)
3127 {
3128 case MPT_CONFIGURATION_PAGE_TYPE_IO_UNIT:
3129 {
3130 /* Get the page data. */
3131 rc = lsilogicR3ConfigurationIOUnitPageGetFromNumber(pThis,
3132 pThisCC->pConfigurationPages,
3133 pConfigurationReq->u8PageNumber,
3134 &pPageHeader, &pbPageData, &cbPage);
3135 break;
3136 }
3137 case MPT_CONFIGURATION_PAGE_TYPE_IOC:
3138 {
3139 /* Get the page data. */
3140 rc = lsilogicR3ConfigurationIOCPageGetFromNumber(pThis,
3141 pThisCC->pConfigurationPages,
3142 pConfigurationReq->u8PageNumber,
3143 &pPageHeader, &pbPageData, &cbPage);
3144 break;
3145 }
3146 case MPT_CONFIGURATION_PAGE_TYPE_MANUFACTURING:
3147 {
3148 /* Get the page data. */
3149 rc = lsilogicR3ConfigurationManufacturingPageGetFromNumber(pThis,
3150 pThisCC->pConfigurationPages,
3151 pConfigurationReq->u8PageNumber,
3152 &pPageHeader, &pbPageData, &cbPage);
3153 break;
3154 }
3155 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT:
3156 {
3157 /* Get the page data. */
3158 rc = lsilogicR3ConfigurationSCSISPIPortPageGetFromNumber(pThis,
3159 pThisCC->pConfigurationPages,
3160 pConfigurationReq->PageAddress.MPIPortNumber.u8PortNumber,
3161 pConfigurationReq->u8PageNumber,
3162 &pPageHeader, &pbPageData, &cbPage);
3163 break;
3164 }
3165 case MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE:
3166 {
3167 /* Get the page data. */
3168 rc = lsilogicR3ConfigurationSCSISPIDevicePageGetFromNumber(pThis,
3169 pThisCC->pConfigurationPages,
3170 pConfigurationReq->PageAddress.BusAndTargetId.u8Bus,
3171 pConfigurationReq->PageAddress.BusAndTargetId.u8TargetID,
3172 pConfigurationReq->u8PageNumber,
3173 &pPageHeader, &pbPageData, &cbPage);
3174 break;
3175 }
3176 case MPT_CONFIGURATION_PAGE_TYPE_BIOS:
3177 {
3178 rc = lsilogicR3ConfigurationBiosPageGetFromNumber(pThis,
3179 pThisCC->pConfigurationPages,
3180 pConfigurationReq->u8PageNumber,
3181 &pPageHeader, &pbPageData, &cbPage);
3182 break;
3183 }
3184 case MPT_CONFIGURATION_PAGE_TYPE_EXTENDED:
3185 {
3186 rc = lsilogicR3ConfigurationPageGetExtended(pThisCC,
3187 pConfigurationReq,
3188 &pExtPageHeader, &pbPageData, &cbPage);
3189 break;
3190 }
3191 default:
3192 rc = VERR_NOT_FOUND;
3193 }
3194
3195 if (rc == VERR_NOT_FOUND)
3196 {
3197 Log(("Page not found\n"));
3198 pReply->u8PageType = pConfigurationReq->u8PageType;
3199 pReply->u8PageNumber = pConfigurationReq->u8PageNumber;
3200 pReply->u8PageLength = pConfigurationReq->u8PageLength;
3201 pReply->u8PageVersion = pConfigurationReq->u8PageVersion;
3202 pReply->u16IOCStatus = MPT_IOCSTATUS_CONFIG_INVALID_PAGE;
3203 return VINF_SUCCESS;
3204 }
3205
3206 if (u8PageType == MPT_CONFIGURATION_PAGE_TYPE_EXTENDED)
3207 {
3208 pReply->u8PageType = pExtPageHeader->u8PageType;
3209 pReply->u8PageNumber = pExtPageHeader->u8PageNumber;
3210 pReply->u8PageVersion = pExtPageHeader->u8PageVersion;
3211 pReply->u8ExtPageType = pExtPageHeader->u8ExtPageType;
3212 pReply->u16ExtPageLength = pExtPageHeader->u16ExtPageLength;
3213
3214 for (int i = 0; i < pExtPageHeader->u16ExtPageLength; i++)
3215 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3216 }
3217 else
3218 {
3219 pReply->u8PageType = pPageHeader->u8PageType;
3220 pReply->u8PageNumber = pPageHeader->u8PageNumber;
3221 pReply->u8PageLength = pPageHeader->u8PageLength;
3222 pReply->u8PageVersion = pPageHeader->u8PageVersion;
3223
3224 for (int i = 0; i < pReply->u8PageLength; i++)
3225 LogFlowFunc(("PageData[%d]=%#x\n", i, ((uint32_t *)pbPageData)[i]));
3226 }
3227
3228 /*
3229 * Don't use the scatter gather handling code as the configuration request always have only one
3230 * simple element.
3231 */
3232 switch (pConfigurationReq->u8Action)
3233 {
3234 case MPT_CONFIGURATION_REQUEST_ACTION_DEFAULT: /* Nothing to do. We are always using the defaults. */
3235 case MPT_CONFIGURATION_REQUEST_ACTION_HEADER:
3236 {
3237 /* Already copied above nothing to do. */
3238 break;
3239 }
3240 case MPT_CONFIGURATION_REQUEST_ACTION_READ_NVRAM:
3241 case MPT_CONFIGURATION_REQUEST_ACTION_READ_CURRENT:
3242 case MPT_CONFIGURATION_REQUEST_ACTION_READ_DEFAULT:
3243 {
3244 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3245 if (cbBuffer != 0)
3246 {
3247 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3248 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3249 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3250
3251 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage));
3252 }
3253 break;
3254 }
3255 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_CURRENT:
3256 case MPT_CONFIGURATION_REQUEST_ACTION_WRITE_NVRAM:
3257 {
3258 uint32_t cbBuffer = pConfigurationReq->SimpleSGElement.u24Length;
3259 if (cbBuffer != 0)
3260 {
3261 RTGCPHYS GCPhysAddrPageBuffer = pConfigurationReq->SimpleSGElement.u32DataBufferAddressLow;
3262 if (pConfigurationReq->SimpleSGElement.f64BitAddress)
3263 GCPhysAddrPageBuffer |= (uint64_t)pConfigurationReq->SimpleSGElement.u32DataBufferAddressHigh << 32;
3264
3265 LogFlow(("cbBuffer=%u cbPage=%u\n", cbBuffer, cbPage));
3266
3267 PDMDevHlpPhysReadMeta(pDevIns, GCPhysAddrPageBuffer, pbPageData,
3268 RT_MIN(cbBuffer, cbPage));
3269 }
3270 break;
3271 }
3272 default:
3273 AssertMsgFailed(("todo\n"));
3274 }
3275
3276 return VINF_SUCCESS;
3277}
3278
3279/**
3280 * Initializes the configuration pages for the SPI SCSI controller.
3281 *
3282 * @returns nothing
3283 * @param pThis Pointer to the shared LsiLogic device state.
3284 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3285 */
3286static void lsilogicR3InitializeConfigurationPagesSpi(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3287{
3288 PMptConfigurationPagesSpi pPages = &pThisCC->pConfigurationPages->u.SpiPages;
3289
3290 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n"));
3291 LogFlowFunc(("pThis=%#p\n", pThis));
3292 RT_NOREF(pThis);
3293
3294 /* Clear everything first. */
3295 memset(pPages, 0, sizeof(MptConfigurationPagesSpi));
3296
3297 for (unsigned i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++)
3298 {
3299 /* SCSI-SPI port page 0. */
3300 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3301 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3302 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageNumber = 0;
3303 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
3304 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fInformationUnitTransfersCapable = true;
3305 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fDTCapable = true;
3306 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fQASCapable = true;
3307 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MinimumSynchronousTransferPeriod = 0;
3308 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MaximumSynchronousOffset = 0xff;
3309 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fWide = true;
3310 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fAIPCapable = true;
3311 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u2SignalingType = 0x3; /* Single Ended. */
3312
3313 /* SCSI-SPI port page 1. */
3314 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3315 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3316 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageNumber = 1;
3317 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
3318 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u8SCSIID = 7;
3319 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u16PortResponseIDsBitmask = (1 << 7);
3320 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u32OnBusTimerValue = 0;
3321
3322 /* SCSI-SPI port page 2. */
3323 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3324 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3325 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageNumber = 2;
3326 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
3327 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u4HostSCSIID = 7;
3328 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u2InitializeHBA = 0x3;
3329 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.fTerminationDisabled = true;
3330 for (unsigned iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++)
3331 {
3332 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings[iDevice].fBootChoice = true;
3333 }
3334 /* Everything else 0 for now. */
3335 }
3336
3337 for (unsigned uBusCurr = 0; uBusCurr < RT_ELEMENTS(pPages->aBuses); uBusCurr++)
3338 {
3339 for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
3340 {
3341 /* SCSI-SPI device page 0. */
3342 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3343 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3344 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
3345 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
3346 /* Everything else 0 for now. */
3347
3348 /* SCSI-SPI device page 1. */
3349 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3350 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3351 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
3352 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
3353 /* Everything else 0 for now. */
3354
3355 /* SCSI-SPI device page 2. */
3356 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3357 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3358 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
3359 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
3360 /* Everything else 0 for now. */
3361
3362 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3363 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3364 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
3365 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
3366 /* Everything else 0 for now. */
3367 }
3368 }
3369}
3370
3371/**
3372 * Generates a handle.
3373 *
3374 * @returns the handle.
3375 * @param pThis Pointer to the shared LsiLogic device state.
3376 */
3377DECLINLINE(uint16_t) lsilogicGetHandle(PLSILOGICSCSI pThis)
3378{
3379 uint16_t u16Handle = pThis->u16NextHandle++;
3380 return u16Handle;
3381}
3382
3383/**
3384 * Generates a SAS address (WWID)
3385 *
3386 * @returns nothing.
3387 * @param pSASAddress Pointer to an unitialised SAS address.
3388 * @param iId iId which will go into the address.
3389 *
3390 * @todo Generate better SAS addresses. (Request a block from SUN probably)
3391 */
3392void lsilogicSASAddressGenerate(PSASADDRESS pSASAddress, unsigned iId)
3393{
3394 pSASAddress->u8Address[0] = (0x5 << 5);
3395 pSASAddress->u8Address[1] = 0x01;
3396 pSASAddress->u8Address[2] = 0x02;
3397 pSASAddress->u8Address[3] = 0x03;
3398 pSASAddress->u8Address[4] = 0x04;
3399 pSASAddress->u8Address[5] = 0x05;
3400 pSASAddress->u8Address[6] = 0x06;
3401 pSASAddress->u8Address[7] = iId;
3402}
3403
3404/**
3405 * Initializes the configuration pages for the SAS SCSI controller.
3406 *
3407 * @returns nothing
3408 * @param pThis Pointer to the shared LsiLogic device state.
3409 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3410 */
3411static void lsilogicR3InitializeConfigurationPagesSas(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3412{
3413 PMptConfigurationPagesSas pPages = &pThisCC->pConfigurationPages->u.SasPages;
3414
3415 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS, ("Controller is not the SAS SCSI one\n"));
3416
3417 LogFlowFunc(("pThis=%#p\n", pThis));
3418
3419 /* Manufacturing Page 7 - Connector settings. */
3420 pPages->cbManufacturingPage7 = LSILOGICSCSI_MANUFACTURING7_GET_SIZE(pThis->cPorts);
3421 PMptConfigurationPageManufacturing7 pManufacturingPage7 = (PMptConfigurationPageManufacturing7)RTMemAllocZ(pPages->cbManufacturingPage7);
3422 AssertPtr(pManufacturingPage7);
3423 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pManufacturingPage7,
3424 0, 7,
3425 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3426 /* Set size manually. */
3427 if (pPages->cbManufacturingPage7 / 4 > 255)
3428 pManufacturingPage7->u.fields.Header.u8PageLength = 255;
3429 else
3430 pManufacturingPage7->u.fields.Header.u8PageLength = pPages->cbManufacturingPage7 / 4;
3431 pManufacturingPage7->u.fields.u8NumPhys = pThis->cPorts;
3432 pPages->pManufacturingPage7 = pManufacturingPage7;
3433
3434 /* SAS I/O unit page 0 - Port specific information. */
3435 pPages->cbSASIOUnitPage0 = LSILOGICSCSI_SASIOUNIT0_GET_SIZE(pThis->cPorts);
3436 PMptConfigurationPageSASIOUnit0 pSASPage0 = (PMptConfigurationPageSASIOUnit0)RTMemAllocZ(pPages->cbSASIOUnitPage0);
3437 AssertPtr(pSASPage0);
3438
3439 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage0, pPages->cbSASIOUnitPage0,
3440 0, MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY,
3441 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3442 pSASPage0->u.fields.u8NumPhys = pThis->cPorts;
3443 pPages->pSASIOUnitPage0 = pSASPage0;
3444
3445 /* SAS I/O unit page 1 - Port specific settings. */
3446 pPages->cbSASIOUnitPage1 = LSILOGICSCSI_SASIOUNIT1_GET_SIZE(pThis->cPorts);
3447 PMptConfigurationPageSASIOUnit1 pSASPage1 = (PMptConfigurationPageSASIOUnit1)RTMemAllocZ(pPages->cbSASIOUnitPage1);
3448 AssertPtr(pSASPage1);
3449
3450 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage1, pPages->cbSASIOUnitPage1,
3451 1, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE,
3452 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3453 pSASPage1->u.fields.u8NumPhys = pSASPage0->u.fields.u8NumPhys;
3454 pSASPage1->u.fields.u16ControlFlags = 0;
3455 pSASPage1->u.fields.u16AdditionalControlFlags = 0;
3456 pPages->pSASIOUnitPage1 = pSASPage1;
3457
3458 /* SAS I/O unit page 2 - Port specific information. */
3459 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3460 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3461 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageNumber = 2;
3462 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3463 pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit2) / 4;
3464
3465 /* SAS I/O unit page 3 - Port specific information. */
3466 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3467 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3468 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageNumber = 3;
3469 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3470 pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit3) / 4;
3471
3472 pPages->cPHYs = pThis->cPorts;
3473 pPages->paPHYs = (PMptPHY)RTMemAllocZ(pPages->cPHYs * sizeof(MptPHY));
3474 AssertPtr(pPages->paPHYs);
3475
3476 /* Initialize the PHY configuration */
3477 for (unsigned i = 0; i < pThis->cPorts; i++)
3478 {
3479 PMptPHY pPHYPages = &pPages->paPHYs[i];
3480 uint16_t u16ControllerHandle = lsilogicGetHandle(pThis);
3481
3482 pManufacturingPage7->u.fields.aPHY[i].u8Location = LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO;
3483
3484 pSASPage0->u.fields.aPHY[i].u8Port = i;
3485 pSASPage0->u.fields.aPHY[i].u8PortFlags = 0;
3486 pSASPage0->u.fields.aPHY[i].u8PhyFlags = 0;
3487 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED;
3488 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3489 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16ControllerHandle;
3490 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = 0; /* No device attached. */
3491 pSASPage0->u.fields.aPHY[i].u32DiscoveryStatus = 0; /* No errors */
3492
3493 pSASPage1->u.fields.aPHY[i].u8Port = i;
3494 pSASPage1->u.fields.aPHY[i].u8PortFlags = 0;
3495 pSASPage1->u.fields.aPHY[i].u8PhyFlags = 0;
3496 pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3497 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3498 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3499
3500 /* SAS PHY page 0. */
3501 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3502 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3503 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageNumber = 0;
3504 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3505 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY0) / 4;
3506 pPHYPages->SASPHYPage0.u.fields.u8AttachedPhyIdentifier = i;
3507 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
3508 pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3509 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3510 pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3511 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3512
3513 /* SAS PHY page 1. */
3514 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3515 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3516 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageNumber = 1;
3517 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3518 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY1) / 4;
3519
3520 /* Settings for present devices. */
3521 if (pThisCC->paDeviceStates[i].pDrvBase)
3522 {
3523 uint16_t u16DeviceHandle = lsilogicGetHandle(pThis);
3524 SASADDRESS SASAddress;
3525 PMptSASDevice pSASDevice = (PMptSASDevice)RTMemAllocZ(sizeof(MptSASDevice));
3526 AssertPtr(pSASDevice);
3527
3528 memset(&SASAddress, 0, sizeof(SASADDRESS));
3529 lsilogicSASAddressGenerate(&SASAddress, i);
3530
3531 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
3532 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3533 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3534 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = u16DeviceHandle;
3535 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3536 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3537 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16DeviceHandle;
3538
3539 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
3540 pPHYPages->SASPHYPage0.u.fields.SASAddress = SASAddress;
3541 pPHYPages->SASPHYPage0.u.fields.u16OwnerDevHandle = u16DeviceHandle;
3542 pPHYPages->SASPHYPage0.u.fields.u16AttachedDevHandle = u16DeviceHandle;
3543
3544 /* SAS device page 0. */
3545 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3546 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3547 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageNumber = 0;
3548 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3549 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice0) / 4;
3550 pSASDevice->SASDevicePage0.u.fields.SASAddress = SASAddress;
3551 pSASDevice->SASDevicePage0.u.fields.u16ParentDevHandle = u16ControllerHandle;
3552 pSASDevice->SASDevicePage0.u.fields.u8PhyNum = i;
3553 pSASDevice->SASDevicePage0.u.fields.u8AccessStatus = LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS;
3554 pSASDevice->SASDevicePage0.u.fields.u16DevHandle = u16DeviceHandle;
3555 pSASDevice->SASDevicePage0.u.fields.u8TargetID = i;
3556 pSASDevice->SASDevicePage0.u.fields.u8Bus = 0;
3557 pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
3558 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3559 pSASDevice->SASDevicePage0.u.fields.u16Flags = LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT
3560 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID
3561 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT;
3562 pSASDevice->SASDevicePage0.u.fields.u8PhysicalPort = i;
3563
3564 /* SAS device page 1. */
3565 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3566 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3567 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageNumber = 1;
3568 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3569 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice1) / 4;
3570 pSASDevice->SASDevicePage1.u.fields.SASAddress = SASAddress;
3571 pSASDevice->SASDevicePage1.u.fields.u16DevHandle = u16DeviceHandle;
3572 pSASDevice->SASDevicePage1.u.fields.u8TargetID = i;
3573 pSASDevice->SASDevicePage1.u.fields.u8Bus = 0;
3574
3575 /* SAS device page 2. */
3576 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3577 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3578 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageNumber = 2;
3579 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3580 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice2) / 4;
3581 pSASDevice->SASDevicePage2.u.fields.SASAddress = SASAddress;
3582
3583 /* Link into device list. */
3584 if (!pPages->cDevices)
3585 {
3586 pPages->pSASDeviceHead = pSASDevice;
3587 pPages->pSASDeviceTail = pSASDevice;
3588 pPages->cDevices = 1;
3589 }
3590 else
3591 {
3592 pSASDevice->pPrev = pPages->pSASDeviceTail;
3593 pPages->pSASDeviceTail->pNext = pSASDevice;
3594 pPages->pSASDeviceTail = pSASDevice;
3595 pPages->cDevices++;
3596 }
3597 }
3598 }
3599}
3600
3601/**
3602 * Initializes the configuration pages.
3603 *
3604 * @returns nothing
3605 * @param pDevIns The device instance.
3606 * @param pThis Pointer to the shared LsiLogic device state.
3607 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3608 */
3609static void lsilogicR3InitializeConfigurationPages(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3610{
3611 /* Initialize the common pages. */
3612 PMptConfigurationPagesSupported pPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported));
3613 /** @todo r=bird: Missing alloc failure check. Why do we allocate this
3614 * structure? It's fixed size... */
3615
3616 pThisCC->pConfigurationPages = pPages;
3617
3618 LogFlowFunc(("pThis=%#p\n", pThis));
3619
3620 /* Clear everything first. */
3621 memset(pPages, 0, sizeof(MptConfigurationPagesSupported));
3622
3623 /* Manufacturing Page 0. */
3624 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage0,
3625 MptConfigurationPageManufacturing0, 0,
3626 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3627 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipName, "VBox MPT Fusion", 16);
3628 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipRevision, "1.0", 8);
3629 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardName, "VBox MPT Fusion", 16);
3630 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardAssembly, "SUN", 8);
3631 memcpy(pPages->ManufacturingPage0.u.fields.abBoardTracerNumber, "CAFECAFECAFECAFE", 16);
3632
3633 /* Manufacturing Page 1 - I don't know what this contains so we leave it 0 for now. */
3634 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage1,
3635 MptConfigurationPageManufacturing1, 1,
3636 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3637
3638 /* Manufacturing Page 2. */
3639 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage2,
3640 MptConfigurationPageManufacturing2, 2,
3641 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3642
3643 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3644 {
3645 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3646 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3647 }
3648 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3649 {
3650 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3651 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3652 }
3653
3654 /* Manufacturing Page 3. */
3655 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage3,
3656 MptConfigurationPageManufacturing3, 3,
3657 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3658
3659 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3660 {
3661 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3662 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3663 }
3664 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3665 {
3666 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3667 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3668 }
3669
3670 /* Manufacturing Page 4 - I don't know what this contains so we leave it 0 for now. */
3671 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage4,
3672 MptConfigurationPageManufacturing4, 4,
3673 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3674
3675 /* Manufacturing Page 5 - WWID settings. */
3676 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage5,
3677 MptConfigurationPageManufacturing5, 5,
3678 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3679
3680 /* Manufacturing Page 6 - Product specific settings. */
3681 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage6,
3682 MptConfigurationPageManufacturing6, 6,
3683 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3684
3685 /* Manufacturing Page 8 - Product specific settings. */
3686 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage8,
3687 MptConfigurationPageManufacturing8, 8,
3688 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3689
3690 /* Manufacturing Page 9 - Product specific settings. */
3691 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage9,
3692 MptConfigurationPageManufacturing9, 9,
3693 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3694
3695 /* Manufacturing Page 10 - Product specific settings. */
3696 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage10,
3697 MptConfigurationPageManufacturing10, 10,
3698 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3699
3700 /* I/O Unit page 0. */
3701 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage0,
3702 MptConfigurationPageIOUnit0, 0,
3703 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3704 pPages->IOUnitPage0.u.fields.u64UniqueIdentifier = 0xcafe;
3705
3706 /* I/O Unit page 1. */
3707 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage1,
3708 MptConfigurationPageIOUnit1, 1,
3709 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3710 pPages->IOUnitPage1.u.fields.fSingleFunction = true;
3711 pPages->IOUnitPage1.u.fields.fAllPathsMapped = false;
3712 pPages->IOUnitPage1.u.fields.fIntegratedRAIDDisabled = true;
3713 pPages->IOUnitPage1.u.fields.f32BitAccessForced = false;
3714
3715 /* I/O Unit page 2. */
3716 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage2,
3717 MptConfigurationPageIOUnit2, 2,
3718 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT);
3719 pPages->IOUnitPage2.u.fields.fPauseOnError = false;
3720 pPages->IOUnitPage2.u.fields.fVerboseModeEnabled = false;
3721 pPages->IOUnitPage2.u.fields.fDisableColorVideo = false;
3722 pPages->IOUnitPage2.u.fields.fNotHookInt40h = false;
3723 pPages->IOUnitPage2.u.fields.u32BIOSVersion = 0xcafecafe;
3724 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true;
3725 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true;
3726 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0;
3727 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pDevIns->apPciDevs[0]->uDevFn;
3728
3729 /* I/O Unit page 3. */
3730 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
3731 MptConfigurationPageIOUnit3, 3,
3732 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3733 pPages->IOUnitPage3.u.fields.u8GPIOCount = 0;
3734
3735 /* I/O Unit page 4. */
3736 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage4,
3737 MptConfigurationPageIOUnit4, 4,
3738 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3739
3740 /* IOC page 0. */
3741 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage0,
3742 MptConfigurationPageIOC0, 0,
3743 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3744 pPages->IOCPage0.u.fields.u32TotalNVStore = 0;
3745 pPages->IOCPage0.u.fields.u32FreeNVStore = 0;
3746
3747 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3748 {
3749 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3750 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3751 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3752 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SPI_CLASS_CODE;
3753 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID;
3754 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID;
3755 }
3756 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3757 {
3758 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3759 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3760 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3761 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SAS_CLASS_CODE;
3762 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID;
3763 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID;
3764 }
3765
3766 /* IOC page 1. */
3767 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage1,
3768 MptConfigurationPageIOC1, 1,
3769 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3770 pPages->IOCPage1.u.fields.fReplyCoalescingEnabled = false;
3771 pPages->IOCPage1.u.fields.u32CoalescingTimeout = 0;
3772 pPages->IOCPage1.u.fields.u8CoalescingDepth = 0;
3773
3774 /* IOC page 2. */
3775 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage2,
3776 MptConfigurationPageIOC2, 2,
3777 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3778 /* Everything else here is 0. */
3779
3780 /* IOC page 3. */
3781 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage3,
3782 MptConfigurationPageIOC3, 3,
3783 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3784 /* Everything else here is 0. */
3785
3786 /* IOC page 4. */
3787 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage4,
3788 MptConfigurationPageIOC4, 4,
3789 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3790 /* Everything else here is 0. */
3791
3792 /* IOC page 6. */
3793 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage6,
3794 MptConfigurationPageIOC6, 6,
3795 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3796 /* Everything else here is 0. */
3797
3798 /* BIOS page 1. */
3799 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage1,
3800 MptConfigurationPageBIOS1, 1,
3801 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3802
3803 /* BIOS page 2. */
3804 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage2,
3805 MptConfigurationPageBIOS2, 2,
3806 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3807
3808 /* BIOS page 4. */
3809 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage4,
3810 MptConfigurationPageBIOS4, 4,
3811 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3812
3813 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3814 lsilogicR3InitializeConfigurationPagesSpi(pThis, pThisCC);
3815 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3816 lsilogicR3InitializeConfigurationPagesSas(pThis, pThisCC);
3817 else
3818 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
3819}
3820
3821/**
3822 * Sets the emulated controller type from a given string.
3823 *
3824 * @returns VBox status code.
3825 *
3826 * @param pThis Pointer to the shared LsiLogic device state.
3827 * @param pcszCtrlType The string to use.
3828 */
3829static int lsilogicR3GetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType)
3830{
3831 int rc = VERR_INVALID_PARAMETER;
3832
3833 if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME))
3834 {
3835 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SPI;
3836 rc = VINF_SUCCESS;
3837 }
3838 else if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SAS_CTRLNAME))
3839 {
3840 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SAS;
3841 rc = VINF_SUCCESS;
3842 }
3843
3844 return rc;
3845}
3846
3847/**
3848 * @callback_method_impl{FNIOMIOPORTIN, Legacy ISA port.}
3849 */
3850static DECLCALLBACK(VBOXSTRICTRC)
3851lsilogicR3IsaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3852{
3853 RT_NOREF(pvUser, cb);
3854 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3855
3856 ASSERT_GUEST(cb == 1);
3857
3858 int rc = vboxscsiReadRegister(&pThisCC->VBoxSCSI, offPort, pu32);
3859 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register read status: %Rrc\n", rc));
3860
3861 Log2(("%s: pu32=%p:{%.*Rhxs} offPort=%d rc=%Rrc\n", __FUNCTION__, pu32, 1, pu32, offPort, rc));
3862
3863 return rc;
3864}
3865
3866/**
3867 * Prepares a request from the BIOS.
3868 *
3869 * @returns VBox status code.
3870 * @param pThis Pointer to the shared LsiLogic device state.
3871 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3872 */
3873static int lsilogicR3PrepareBiosScsiRequest(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3874{
3875 int rc;
3876 uint32_t uTargetDevice;
3877 uint32_t uLun;
3878 uint8_t *pbCdb;
3879 size_t cbCdb;
3880 size_t cbBuf;
3881
3882 rc = vboxscsiSetupRequest(&pThisCC->VBoxSCSI, &uLun, &pbCdb, &cbCdb, &cbBuf, &uTargetDevice);
3883 AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc);
3884
3885 if ( uTargetDevice < pThis->cDeviceStates
3886 && pThisCC->paDeviceStates[uTargetDevice].pDrvBase)
3887 {
3888 PLSILOGICDEVICE pTgtDev = &pThisCC->paDeviceStates[uTargetDevice];
3889 PDMMEDIAEXIOREQ hIoReq;
3890 PLSILOGICREQ pReq;
3891
3892 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pReq,
3893 0, PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
3894 AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc);
3895
3896 pReq->fBIOS = true;
3897 pReq->hIoReq = hIoReq;
3898 pReq->pTargetDevice = pTgtDev;
3899
3900 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
3901
3902 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pReq->hIoReq, uLun,
3903 pbCdb, cbCdb, PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, NULL,
3904 cbBuf, NULL, 0, NULL, &pReq->u8ScsiSts, 30 * RT_MS_1SEC);
3905 if (rc == VINF_SUCCESS || rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3906 {
3907 uint8_t u8ScsiSts = pReq->u8ScsiSts;
3908 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
3909 rc = vboxscsiRequestFinished(&pThisCC->VBoxSCSI, u8ScsiSts);
3910 }
3911 else if (rc == VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3912 rc = VINF_SUCCESS;
3913
3914 return rc;
3915 }
3916
3917 /* Device is not present. */
3918 AssertMsg(pbCdb[0] == SCSI_INQUIRY,
3919 ("Device is not present but command is not inquiry\n"));
3920
3921 SCSIINQUIRYDATA ScsiInquiryData;
3922
3923 memset(&ScsiInquiryData, 0, sizeof(SCSIINQUIRYDATA));
3924 ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
3925 ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
3926
3927 memcpy(pThisCC->VBoxSCSI.pbBuf, &ScsiInquiryData, 5);
3928
3929 rc = vboxscsiRequestFinished(&pThisCC->VBoxSCSI, SCSI_STATUS_OK);
3930 AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc);
3931
3932 return rc;
3933}
3934
3935/**
3936 * @callback_method_impl{FNIOMIOPORTNEWOUT, Legacy ISA port.}
3937 */
3938static DECLCALLBACK(VBOXSTRICTRC)
3939lsilogicR3IsaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3940{
3941 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3942 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3943 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, offPort));
3944 RT_NOREF(pvUser, cb);
3945
3946 ASSERT_GUEST(cb == 1);
3947
3948 /*
3949 * If there is already a request form the BIOS pending ignore this write
3950 * because it should not happen.
3951 */
3952 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
3953 return VINF_SUCCESS;
3954
3955 int rc = vboxscsiWriteRegister(&pThisCC->VBoxSCSI, offPort, (uint8_t)u32);
3956 if (rc == VERR_MORE_DATA)
3957 {
3958 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3959 /* Notify the worker thread that there are pending requests. */
3960 LogFlowFunc(("Signal event semaphore\n"));
3961 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
3962 AssertRC(rc);
3963 }
3964 else
3965 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register write status: %Rrc\n", rc));
3966
3967 return VINF_SUCCESS;
3968}
3969
3970/**
3971 * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,
3972 * Port I/O Handler for primary port range OUT string operations.}
3973 */
3974static DECLCALLBACK(VBOXSTRICTRC) lsilogicR3IsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort,
3975 uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
3976{
3977 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3978 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3979 Log2(("#%d %s: pvUser=%#p cb=%d offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, offPort));
3980 RT_NOREF(pvUser);
3981
3982 int rc = vboxscsiWriteString(pDevIns, &pThisCC->VBoxSCSI, offPort, pbSrc, pcTransfers, cb);
3983 if (rc == VERR_MORE_DATA)
3984 {
3985 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3986 /* Notify the worker thread that there are pending requests. */
3987 LogFlowFunc(("Signal event semaphore\n"));
3988 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
3989 AssertRC(rc);
3990 }
3991 else
3992 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register write status: %Rrc\n", rc));
3993
3994 return VINF_SUCCESS;
3995}
3996
3997/**
3998 * @callback_method_impl{FNIOMIOPORTINSTRING,
3999 * Port I/O Handler for primary port range IN string operations.}
4000 */
4001static DECLCALLBACK(VBOXSTRICTRC) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort,
4002 uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
4003{
4004 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4005 LogFlowFunc(("#%d %s: pvUser=%#p cb=%d offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, offPort));
4006 RT_NOREF(pvUser);
4007
4008 int rc = vboxscsiReadString(pDevIns, &pThisCC->VBoxSCSI, offPort, pbDst, pcTransfers, cb);
4009 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register read status: %Rrc\n", rc));
4010 return rc;
4011}
4012
4013/**
4014 * @callback_method_impl{PFNDBGFHANDLERDEV}
4015 */
4016static DECLCALLBACK(void) lsilogicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4017{
4018 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4019 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4020
4021 /*
4022 * Parse args.
4023 */
4024 bool const fVerbose = pszArgs && strstr(pszArgs, "verbose") != NULL;
4025
4026 /*
4027 * Show info.
4028 */
4029 pHlp->pfnPrintf(pHlp,
4030 "%s#%d: port=%04x mmio=%RGp max-devices=%u GC=%RTbool R0=%RTbool\n",
4031 pDevIns->pReg->szName, pDevIns->iInstance,
4032 PDMDevHlpIoPortGetMappingAddress(pDevIns, pThis->hIoPortsReg),
4033 PDMDevHlpMmioGetMappingAddress(pDevIns, pThis->hMmioReg),
4034 pThis->cDeviceStates, pDevIns->fRCEnabled, pDevIns->fR0Enabled);
4035
4036 /*
4037 * Show general state.
4038 */
4039 pHlp->pfnPrintf(pHlp, "enmState=%u\n", pThis->enmState);
4040 pHlp->pfnPrintf(pHlp, "enmWhoInit=%u\n", pThis->enmWhoInit);
4041 pHlp->pfnPrintf(pHlp, "enmDoorbellState=%d\n", pThis->enmDoorbellState);
4042 pHlp->pfnPrintf(pHlp, "fDiagnosticEnabled=%RTbool\n", pThis->fDiagnosticEnabled);
4043 pHlp->pfnPrintf(pHlp, "fNotificationSent=%RTbool\n", pThis->fNotificationSent);
4044 pHlp->pfnPrintf(pHlp, "fEventNotificationEnabled=%RTbool\n", pThis->fEventNotificationEnabled);
4045 pHlp->pfnPrintf(pHlp, "uInterruptMask=%#x\n", pThis->uInterruptMask);
4046 pHlp->pfnPrintf(pHlp, "uInterruptStatus=%#x\n", pThis->uInterruptStatus);
4047 pHlp->pfnPrintf(pHlp, "u16IOCFaultCode=%#06x\n", pThis->u16IOCFaultCode);
4048 pHlp->pfnPrintf(pHlp, "u32HostMFAHighAddr=%#x\n", pThis->u32HostMFAHighAddr);
4049 pHlp->pfnPrintf(pHlp, "u32SenseBufferHighAddr=%#x\n", pThis->u32SenseBufferHighAddr);
4050 pHlp->pfnPrintf(pHlp, "cMaxDevices=%u\n", pThis->cMaxDevices);
4051 pHlp->pfnPrintf(pHlp, "cMaxBuses=%u\n", pThis->cMaxBuses);
4052 pHlp->pfnPrintf(pHlp, "cbReplyFrame=%u\n", pThis->cbReplyFrame);
4053 pHlp->pfnPrintf(pHlp, "cReplyQueueEntries=%u\n", pThis->cReplyQueueEntries);
4054 pHlp->pfnPrintf(pHlp, "cRequestQueueEntries=%u\n", pThis->cRequestQueueEntries);
4055 pHlp->pfnPrintf(pHlp, "cPorts=%u\n", pThis->cPorts);
4056
4057 /*
4058 * Show queue status.
4059 */
4060 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextEntryFreeWrite=%u\n", pThis->uReplyFreeQueueNextEntryFreeWrite);
4061 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextAddressRead=%u\n", pThis->uReplyFreeQueueNextAddressRead);
4062 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextEntryFreeWrite=%u\n", pThis->uReplyPostQueueNextEntryFreeWrite);
4063 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextAddressRead=%u\n", pThis->uReplyPostQueueNextAddressRead);
4064 pHlp->pfnPrintf(pHlp, "uRequestQueueNextEntryFreeWrite=%u\n", pThis->uRequestQueueNextEntryFreeWrite);
4065 pHlp->pfnPrintf(pHlp, "uRequestQueueNextAddressRead=%u\n", pThis->uRequestQueueNextAddressRead);
4066
4067 /*
4068 * Show queue content if verbose
4069 */
4070 if (fVerbose)
4071 {
4072 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4073 pHlp->pfnPrintf(pHlp, "RFQ[%u]=%#x\n", i, pThis->aReplyFreeQueue[i]);
4074
4075 pHlp->pfnPrintf(pHlp, "\n");
4076
4077 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4078 pHlp->pfnPrintf(pHlp, "RPQ[%u]=%#x\n", i, pThis->aReplyPostQueue[i]);
4079
4080 pHlp->pfnPrintf(pHlp, "\n");
4081
4082 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4083 pHlp->pfnPrintf(pHlp, "ReqQ[%u]=%#x\n", i, pThis->aRequestQueue[i]);
4084 }
4085
4086 /*
4087 * Print the device status.
4088 */
4089 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4090 {
4091 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4092
4093 pHlp->pfnPrintf(pHlp, "\n");
4094
4095 pHlp->pfnPrintf(pHlp, "Device[%u]: device-attached=%RTbool cOutstandingRequests=%u\n",
4096 i, pDevice->pDrvBase != NULL, pDevice->cOutstandingRequests);
4097 }
4098}
4099
4100
4101/**
4102 * @callback_method_impl{FNPDMTHREADDEV}
4103 */
4104static DECLCALLBACK(int) lsilogicR3Worker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4105{
4106 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4107 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4108 int rc = VINF_SUCCESS;
4109
4110 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
4111 return VINF_SUCCESS;
4112
4113 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4114 {
4115 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true);
4116 bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false);
4117 if (!fNotificationSent)
4118 {
4119 Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping));
4120 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtProcess, RT_INDEFINITE_WAIT);
4121 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
4122 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
4123 break;
4124 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
4125 ASMAtomicWriteBool(&pThis->fNotificationSent, false);
4126 }
4127
4128 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false);
4129
4130 /* Check whether there is a BIOS request pending and process it first. */
4131 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
4132 {
4133 rc = lsilogicR3PrepareBiosScsiRequest(pThis, pThisCC);
4134 AssertRC(rc);
4135 ASMAtomicXchgBool(&pThis->fBiosReqPending, false);
4136 }
4137
4138 /* Only process request which arrived before we received the notification. */
4139 uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite);
4140
4141 /* Go through the messages now and process them. */
4142 while ( RT_LIKELY(pThis->enmState == LSILOGICSTATE_OPERATIONAL)
4143 && (pThis->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite))
4144 {
4145 MptRequestUnion GuestRequest;
4146 uint32_t u32RequestMessageFrameDesc = pThis->aRequestQueue[pThis->uRequestQueueNextAddressRead];
4147 RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr,
4148 (u32RequestMessageFrameDesc & ~0x07));
4149
4150 /* Read the message header from the guest first. */
4151 PDMDevHlpPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, sizeof(MptMessageHdr));
4152
4153 /* Determine the size of the request. */
4154 uint32_t cbRequest = 0;
4155 switch (GuestRequest.Header.u8Function)
4156 {
4157 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
4158 cbRequest = sizeof(MptSCSIIORequest);
4159 break;
4160 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
4161 cbRequest = sizeof(MptSCSITaskManagementRequest);
4162 break;
4163 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
4164 cbRequest = sizeof(MptIOCInitRequest);
4165 break;
4166 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
4167 cbRequest = sizeof(MptIOCFactsRequest);
4168 break;
4169 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
4170 cbRequest = sizeof(MptConfigurationRequest);
4171 break;
4172 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
4173 cbRequest = sizeof(MptPortFactsRequest);
4174 break;
4175 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
4176 cbRequest = sizeof(MptPortEnableRequest);
4177 break;
4178 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
4179 cbRequest = sizeof(MptEventNotificationRequest);
4180 break;
4181 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
4182 AssertMsgFailed(("todo\n"));
4183 //cbRequest = sizeof(MptEventAckRequest);
4184 break;
4185 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
4186 cbRequest = sizeof(MptFWDownloadRequest);
4187 break;
4188 case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
4189 cbRequest = sizeof(MptFWUploadRequest);
4190 break;
4191 default:
4192 AssertMsgFailed(("Unknown function issued %u\n", GuestRequest.Header.u8Function));
4193 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INVALID_FUNCTION);
4194 }
4195
4196 if (cbRequest != 0)
4197 {
4198 /* Read the complete message frame from guest memory now. */
4199 PDMDevHlpPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, cbRequest);
4200
4201 /* Handle SCSI I/O requests now. */
4202 if (GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST)
4203 {
4204 rc = lsilogicR3ProcessSCSIIORequest(pDevIns, pThis, pThisCC, GCPhysMessageFrameAddr, &GuestRequest);
4205 AssertRC(rc);
4206 }
4207 else
4208 {
4209 MptReplyUnion Reply;
4210 rc = lsilogicR3ProcessMessageRequest(pDevIns, pThis, pThisCC, &GuestRequest.Header, &Reply);
4211 AssertRC(rc);
4212 }
4213
4214 pThis->uRequestQueueNextAddressRead++;
4215 pThis->uRequestQueueNextAddressRead %= pThis->cRequestQueueEntries;
4216 }
4217 } /* While request frames available. */
4218 } /* While running */
4219
4220 return VINF_SUCCESS;
4221}
4222
4223
4224/**
4225 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
4226 */
4227static DECLCALLBACK(int) lsilogicR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4228{
4229 RT_NOREF(pThread);
4230 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4231 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
4232}
4233
4234
4235/**
4236 * Kicks the controller to process pending tasks after the VM was resumed
4237 * or loaded from a saved state.
4238 *
4239 * @returns nothing.
4240 * @param pDevIns The device instance.
4241 * @param pThis Pointer to the shared LsiLogic device state.
4242 */
4243static void lsilogicR3Kick(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis)
4244{
4245 if (pThis->fNotificationSent)
4246 {
4247 /* Notify the worker thread that there are pending requests. */
4248 LogFlowFunc(("Signal event semaphore\n"));
4249 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
4250 AssertRC(rc);
4251 }
4252}
4253
4254
4255/*
4256 * Saved state.
4257 */
4258
4259/**
4260 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4261 */
4262static DECLCALLBACK(int) lsilogicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4263{
4264 RT_NOREF(uPass);
4265 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4266 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4267 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4268
4269 pHlp->pfnSSMPutU32(pSSM, pThis->enmCtrlType);
4270 pHlp->pfnSSMPutU32(pSSM, pThis->cDeviceStates);
4271 pHlp->pfnSSMPutU32(pSSM, pThis->cPorts);
4272
4273 /* Save the device config. */
4274 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4275 pHlp->pfnSSMPutBool(pSSM, pThisCC->paDeviceStates[i].pDrvBase != NULL);
4276
4277 return VINF_SSM_DONT_CALL_AGAIN;
4278}
4279
4280/**
4281 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4282 */
4283static DECLCALLBACK(int) lsilogicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4284{
4285 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4286 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4287 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4288
4289 /* Every device first. */
4290 lsilogicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4291 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4292 {
4293 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4294
4295 AssertMsg(!pDevice->cOutstandingRequests,
4296 ("There are still outstanding requests on this device\n"));
4297 pHlp->pfnSSMPutU32(pSSM, pDevice->cOutstandingRequests);
4298
4299 /* Query all suspended requests and store them in the request queue. */
4300 if (pDevice->pDrvMediaEx)
4301 {
4302 uint32_t cReqsRedo = pDevice->pDrvMediaEx->pfnIoReqGetSuspendedCount(pDevice->pDrvMediaEx);
4303 if (cReqsRedo)
4304 {
4305 PDMMEDIAEXIOREQ hIoReq;
4306 PLSILOGICREQ pReq;
4307 int rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pDevice->pDrvMediaEx, &hIoReq,
4308 (void **)&pReq);
4309 AssertRCBreak(rc);
4310
4311 for (;;)
4312 {
4313 if (!pReq->fBIOS)
4314 {
4315 /* Write only the lower 32bit part of the address. */
4316 ASMAtomicWriteU32(&pThis->aRequestQueue[pThis->uRequestQueueNextEntryFreeWrite],
4317 pReq->GCPhysMessageFrameAddr & UINT32_C(0xffffffff));
4318
4319 pThis->uRequestQueueNextEntryFreeWrite++;
4320 pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries;
4321 }
4322 else
4323 {
4324 AssertMsg(!pReq->pRedoNext, ("Only one BIOS task can be active!\n"));
4325 vboxscsiSetRequestRedo(&pThisCC->VBoxSCSI);
4326 }
4327
4328 cReqsRedo--;
4329 if (!cReqsRedo)
4330 break;
4331
4332 rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pDevice->pDrvMediaEx, hIoReq,
4333 &hIoReq, (void **)&pReq);
4334 AssertRCBreak(rc);
4335 }
4336 }
4337 }
4338 }
4339
4340 /* Now the main device state. */
4341 pHlp->pfnSSMPutU32(pSSM, pThis->enmState);
4342 pHlp->pfnSSMPutU32(pSSM, pThis->enmWhoInit);
4343 pHlp->pfnSSMPutU32(pSSM, pThis->enmDoorbellState);
4344 pHlp->pfnSSMPutBool(pSSM, pThis->fDiagnosticEnabled);
4345 pHlp->pfnSSMPutBool(pSSM, pThis->fNotificationSent);
4346 pHlp->pfnSSMPutBool(pSSM, pThis->fEventNotificationEnabled);
4347 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptMask);
4348 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptStatus);
4349 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4350 pHlp->pfnSSMPutU32(pSSM, pThis->aMessage[i]);
4351 pHlp->pfnSSMPutU32(pSSM, pThis->iMessage);
4352 pHlp->pfnSSMPutU32(pSSM, pThis->cMessage);
4353 pHlp->pfnSSMPutMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4354 pHlp->pfnSSMPutU32(pSSM, pThis->uNextReplyEntryRead);
4355 pHlp->pfnSSMPutU32(pSSM, pThis->cReplySize);
4356 pHlp->pfnSSMPutU16(pSSM, pThis->u16IOCFaultCode);
4357 pHlp->pfnSSMPutU32(pSSM, pThis->u32HostMFAHighAddr);
4358 pHlp->pfnSSMPutU32(pSSM, pThis->u32SenseBufferHighAddr);
4359 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxDevices);
4360 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxBuses);
4361 pHlp->pfnSSMPutU16(pSSM, pThis->cbReplyFrame);
4362 pHlp->pfnSSMPutU32(pSSM, pThis->iDiagnosticAccess);
4363 pHlp->pfnSSMPutU32(pSSM, pThis->cReplyQueueEntries);
4364 pHlp->pfnSSMPutU32(pSSM, pThis->cRequestQueueEntries);
4365 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextEntryFreeWrite);
4366 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextAddressRead);
4367 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextEntryFreeWrite);
4368 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextAddressRead);
4369 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextEntryFreeWrite);
4370 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextAddressRead);
4371
4372 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4373 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyFreeQueue[i]);
4374 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4375 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyPostQueue[i]);
4376 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4377 pHlp->pfnSSMPutU32(pSSM, pThis->aRequestQueue[i]);
4378
4379 pHlp->pfnSSMPutU16(pSSM, pThis->u16NextHandle);
4380
4381 /* Save diagnostic memory register and data regions. */
4382 pHlp->pfnSSMPutU32(pSSM, pThis->u32DiagMemAddr);
4383 pHlp->pfnSSMPutU32(pSSM, lsilogicR3MemRegionsCount(pThisCC));
4384
4385 PLSILOGICMEMREGN pIt;
4386 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
4387 {
4388 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrStart);
4389 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrEnd);
4390 pHlp->pfnSSMPutMem(pSSM, &pIt->au32Data[0], (pIt->u32AddrEnd - pIt->u32AddrStart + 1) * sizeof(uint32_t));
4391 }
4392
4393 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
4394
4395 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4396 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4397 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4398 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4399 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4400 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4401 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4402 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4403 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4404 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4405 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4406 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4407 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4408 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4409 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4410 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4411 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4412 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4413 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4414 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4415 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4416 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4417 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4418 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4419
4420 /* Device dependent pages */
4421 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4422 {
4423 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4424
4425 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4426 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4427 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4428
4429 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4430 {
4431 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4432 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4433 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4434 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4435 }
4436 }
4437 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4438 {
4439 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4440
4441 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbManufacturingPage7);
4442 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage0);
4443 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage1);
4444
4445 pHlp->pfnSSMPutMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4446 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4447 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4448
4449 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4450 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4451
4452 pHlp->pfnSSMPutU32(pSSM, pSasPages->cPHYs);
4453 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4454 {
4455 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4456 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4457 }
4458
4459 /* The number of devices first. */
4460 pHlp->pfnSSMPutU32(pSSM, pSasPages->cDevices);
4461
4462 for (PMptSASDevice pCurr = pSasPages->pSASDeviceHead; pCurr; pCurr = pCurr->pNext)
4463 {
4464 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4465 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4466 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4467 }
4468 }
4469 else
4470 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4471
4472 vboxscsiR3SaveExec(pHlp, &pThisCC->VBoxSCSI, pSSM);
4473 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
4474}
4475
4476/**
4477 * @callback_method_impl{FNSSMDEVLOADDONE}
4478 */
4479static DECLCALLBACK(int) lsilogicR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4480{
4481 RT_NOREF(pSSM);
4482 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4483
4484 lsilogicR3Kick(pDevIns, pThis);
4485 return VINF_SUCCESS;
4486}
4487
4488/**
4489 * @callback_method_impl{FNSSMDEVLOADEXEC}
4490 */
4491static DECLCALLBACK(int) lsilogicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4492{
4493 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4494 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4495 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4496 int rc;
4497
4498 if ( uVersion != LSILOGIC_SAVED_STATE_VERSION
4499 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM
4500 && uVersion != LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL
4501 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_SAS
4502 && uVersion != LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4503 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4504
4505 /* device config */
4506 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4507 {
4508 LSILOGICCTRLTYPE enmCtrlType;
4509 uint32_t cDeviceStates, cPorts;
4510
4511 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, enmCtrlType, LSILOGICCTRLTYPE);
4512 pHlp->pfnSSMGetU32(pSSM, &cDeviceStates);
4513 rc = pHlp->pfnSSMGetU32(pSSM, &cPorts);
4514 AssertRCReturn(rc, rc);
4515
4516 if (enmCtrlType != pThis->enmCtrlType)
4517 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
4518 pThis->enmCtrlType, enmCtrlType);
4519 if (cDeviceStates != pThis->cDeviceStates)
4520 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
4521 pThis->cDeviceStates, cDeviceStates);
4522 if (cPorts != pThis->cPorts)
4523 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"),
4524 pThis->cPorts, cPorts);
4525 }
4526 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4527 {
4528 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4529 {
4530 bool fPresent;
4531 rc = pHlp->pfnSSMGetBool(pSSM, &fPresent);
4532 AssertRCReturn(rc, rc);
4533 if (fPresent != (pThisCC->paDeviceStates[i].pDrvBase != NULL))
4534 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
4535 i, pThisCC->paDeviceStates[i].pDrvBase != NULL, fPresent);
4536 }
4537 }
4538 if (uPass != SSM_PASS_FINAL)
4539 return VINF_SUCCESS;
4540
4541 /* Every device first. */
4542 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4543 {
4544 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4545
4546 AssertMsg(!pDevice->cOutstandingRequests,
4547 ("There are still outstanding requests on this device\n"));
4548 pHlp->pfnSSMGetU32V(pSSM, &pDevice->cOutstandingRequests);
4549 }
4550 /* Now the main device state. */
4551 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmState, LSILOGICSTATE);
4552 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmWhoInit, LSILOGICWHOINIT);
4553 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL)
4554 {
4555 /*
4556 * The doorbell status flag distinguishes only between
4557 * doorbell not in use or a Function handshake is currently in progress.
4558 */
4559 bool fDoorbellInProgress = false;
4560 rc = pHlp->pfnSSMGetBool(pSSM, &fDoorbellInProgress);
4561 AssertRCReturn(rc, rc);
4562 if (fDoorbellInProgress)
4563 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE;
4564 else
4565 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
4566 }
4567 else
4568 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmDoorbellState, LSILOGICDOORBELLSTATE);
4569 pHlp->pfnSSMGetBool(pSSM, &pThis->fDiagnosticEnabled);
4570 pHlp->pfnSSMGetBool(pSSM, &pThis->fNotificationSent);
4571 pHlp->pfnSSMGetBool(pSSM, &pThis->fEventNotificationEnabled);
4572 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptMask);
4573 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptStatus);
4574 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4575 pHlp->pfnSSMGetU32(pSSM, &pThis->aMessage[i]);
4576 pHlp->pfnSSMGetU32(pSSM, &pThis->iMessage);
4577 pHlp->pfnSSMGetU32(pSSM, &pThis->cMessage);
4578 pHlp->pfnSSMGetMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4579 pHlp->pfnSSMGetU32(pSSM, &pThis->uNextReplyEntryRead);
4580 pHlp->pfnSSMGetU32(pSSM, &pThis->cReplySize);
4581 pHlp->pfnSSMGetU16(pSSM, &pThis->u16IOCFaultCode);
4582 pHlp->pfnSSMGetU32(pSSM, &pThis->u32HostMFAHighAddr);
4583 pHlp->pfnSSMGetU32(pSSM, &pThis->u32SenseBufferHighAddr);
4584 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxDevices);
4585 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxBuses);
4586 pHlp->pfnSSMGetU16(pSSM, &pThis->cbReplyFrame);
4587 pHlp->pfnSSMGetU32(pSSM, &pThis->iDiagnosticAccess);
4588
4589 uint32_t cReplyQueueEntries, cRequestQueueEntries;
4590 pHlp->pfnSSMGetU32(pSSM, &cReplyQueueEntries);
4591 rc = pHlp->pfnSSMGetU32(pSSM, &cRequestQueueEntries);
4592 AssertRCReturn(rc, rc);
4593
4594 if ( cReplyQueueEntries != pThis->cReplyQueueEntries
4595 || cRequestQueueEntries != pThis->cRequestQueueEntries)
4596 {
4597 LogRel(("Changing queue sizes: cReplyQueueEntries=%u cRequestQueuEntries=%u\n", cReplyQueueEntries, cRequestQueueEntries));
4598 if ( cReplyQueueEntries > RT_ELEMENTS(pThis->aReplyFreeQueue)
4599 || cReplyQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
4600 || cRequestQueueEntries > RT_ELEMENTS(pThis->aRequestQueue)
4601 || cRequestQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN)
4602 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Out of bounds: cReplyQueueEntries=%u cRequestQueueEntries=%u"),
4603 cReplyQueueEntries, cRequestQueueEntries);
4604 pThis->cReplyQueueEntries = cReplyQueueEntries;
4605 pThis->cRequestQueueEntries = cRequestQueueEntries;
4606 }
4607
4608 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextEntryFreeWrite);
4609 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextAddressRead);
4610 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextEntryFreeWrite);
4611 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextAddressRead);
4612 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextEntryFreeWrite);
4613 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextAddressRead);
4614
4615 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
4616
4617 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4618 {
4619 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4620 MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2;
4621
4622 if (pThis->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI)
4623 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller"));
4624
4625 pHlp->pfnSSMGetMem(pSSM, &ConfigPagesV2, sizeof(MptConfigurationPagesSupported_SSM_V2));
4626
4627 pPages->ManufacturingPage0 = ConfigPagesV2.ManufacturingPage0;
4628 pPages->ManufacturingPage1 = ConfigPagesV2.ManufacturingPage1;
4629 pPages->ManufacturingPage2 = ConfigPagesV2.ManufacturingPage2;
4630 pPages->ManufacturingPage3 = ConfigPagesV2.ManufacturingPage3;
4631 pPages->ManufacturingPage4 = ConfigPagesV2.ManufacturingPage4;
4632 pPages->IOUnitPage0 = ConfigPagesV2.IOUnitPage0;
4633 pPages->IOUnitPage1 = ConfigPagesV2.IOUnitPage1;
4634 pPages->IOUnitPage2 = ConfigPagesV2.IOUnitPage2;
4635 pPages->IOUnitPage3 = ConfigPagesV2.IOUnitPage3;
4636 pPages->IOCPage0 = ConfigPagesV2.IOCPage0;
4637 pPages->IOCPage1 = ConfigPagesV2.IOCPage1;
4638 pPages->IOCPage2 = ConfigPagesV2.IOCPage2;
4639 pPages->IOCPage3 = ConfigPagesV2.IOCPage3;
4640 pPages->IOCPage4 = ConfigPagesV2.IOCPage4;
4641 pPages->IOCPage6 = ConfigPagesV2.IOCPage6;
4642
4643 pSpiPages->aPortPages[0].SCSISPIPortPage0 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage0;
4644 pSpiPages->aPortPages[0].SCSISPIPortPage1 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage1;
4645 pSpiPages->aPortPages[0].SCSISPIPortPage2 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage2;
4646
4647 for (unsigned i = 0; i < RT_ELEMENTS(pPages->u.SpiPages.aBuses[0].aDevicePages); i++)
4648 {
4649 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
4650 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
4651 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
4652 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
4653 }
4654 }
4655 else
4656 {
4657 /* Queue content */
4658 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4659 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyFreeQueue[i]);
4660 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4661 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyPostQueue[i]);
4662 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4663 pHlp->pfnSSMGetU32V(pSSM, &pThis->aRequestQueue[i]);
4664
4665 pHlp->pfnSSMGetU16(pSSM, &pThis->u16NextHandle);
4666
4667 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM)
4668 {
4669
4670 /* Save diagnostic memory register and data regions. */
4671 pHlp->pfnSSMGetU32(pSSM, &pThis->u32DiagMemAddr);
4672 uint32_t cMemRegions = 0;
4673 rc = pHlp->pfnSSMGetU32(pSSM, &cMemRegions);
4674 AssertLogRelRCReturn(rc, rc);
4675
4676 while (cMemRegions)
4677 {
4678 uint32_t u32AddrStart = 0;
4679 pHlp->pfnSSMGetU32(pSSM, &u32AddrStart);
4680 uint32_t u32AddrEnd = 0;
4681 rc = pHlp->pfnSSMGetU32(pSSM, &u32AddrEnd);
4682 AssertLogRelRCReturn(rc, rc);
4683
4684 uint32_t cRegion = u32AddrEnd - u32AddrStart + 1;
4685 PLSILOGICMEMREGN pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_UOFFSETOF_DYN(LSILOGICMEMREGN, au32Data[cRegion]));
4686 if (pRegion)
4687 {
4688 pRegion->u32AddrStart = u32AddrStart;
4689 pRegion->u32AddrEnd = u32AddrEnd;
4690 pHlp->pfnSSMGetMem(pSSM, &pRegion->au32Data[0], cRegion * sizeof(uint32_t));
4691 lsilogicR3MemRegionInsert(pThisCC, pRegion);
4692 pThisCC->cbMemRegns += cRegion * sizeof(uint32_t);
4693 }
4694 else
4695 {
4696 /* Leave a log message but continue. */
4697 LogRel(("LsiLogic: Out of memory while restoring the state, might not work as expected\n"));
4698 pHlp->pfnSSMSkip(pSSM, cRegion * sizeof(uint32_t));
4699 }
4700 cMemRegions--;
4701 }
4702 }
4703
4704 /* Configuration pages */
4705 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4706 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4707 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4708 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4709 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4710 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4711 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4712 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4713 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4714 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4715 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4716 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4717 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4718 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4719 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4720 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4721 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4722 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4723 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4724 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4725 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4726 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4727 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4728 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4729
4730 /* Device dependent pages */
4731 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4732 {
4733 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4734
4735 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4736 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4737 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4738
4739 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4740 {
4741 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4742 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4743 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4744 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4745 }
4746 }
4747 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4748 {
4749 uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7;
4750 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4751
4752 pHlp->pfnSSMGetU32(pSSM, &cbManufacturingPage7);
4753 pHlp->pfnSSMGetU32(pSSM, &cbPage0);
4754 rc = pHlp->pfnSSMGetU32(pSSM, &cbPage1);
4755 AssertRCReturn(rc, rc);
4756
4757 if ( (cbPage0 != pSasPages->cbSASIOUnitPage0)
4758 || (cbPage1 != pSasPages->cbSASIOUnitPage1)
4759 || (cbManufacturingPage7 != pSasPages->cbManufacturingPage7))
4760 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4761
4762 AssertPtr(pSasPages->pManufacturingPage7);
4763 AssertPtr(pSasPages->pSASIOUnitPage0);
4764 AssertPtr(pSasPages->pSASIOUnitPage1);
4765
4766 pHlp->pfnSSMGetMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4767 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4768 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4769
4770 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4771 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4772
4773 rc = pHlp->pfnSSMGetU32(pSSM, &cPHYs);
4774 AssertRCReturn(rc, rc);
4775 if (cPHYs != pSasPages->cPHYs)
4776 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4777
4778 AssertPtr(pSasPages->paPHYs);
4779 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4780 {
4781 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4782 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4783 }
4784
4785 /* The number of devices first. */
4786 rc = pHlp->pfnSSMGetU32(pSSM, &pSasPages->cDevices);
4787 AssertRCReturn(rc, rc);
4788
4789 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4790
4791 for (unsigned i = 0; i < pSasPages->cDevices; i++)
4792 {
4793 AssertReturn(pCurr, VERR_SSM_LOAD_CONFIG_MISMATCH);
4794
4795 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4796 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4797 rc = pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4798 AssertRCReturn(rc, rc);
4799
4800 pCurr = pCurr->pNext;
4801 }
4802
4803 Assert(!pCurr);
4804 }
4805 else
4806 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4807 }
4808
4809 rc = vboxscsiR3LoadExec(pHlp, &pThisCC->VBoxSCSI, pSSM);
4810 if (RT_FAILURE(rc))
4811 {
4812 LogRel(("LsiLogic: Failed to restore BIOS state: %Rrc.\n", rc));
4813 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: Failed to restore BIOS state\n"));
4814 }
4815
4816 uint32_t u32;
4817 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
4818 if (RT_FAILURE(rc))
4819 return rc;
4820 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4821
4822 return VINF_SUCCESS;
4823}
4824
4825
4826/*
4827 * The device level IBASE and LED interfaces.
4828 */
4829
4830/**
4831 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed, For a SCSI device.}
4832 *
4833 * @remarks Called by the scsi driver, proxying the main calls.
4834 */
4835static DECLCALLBACK(int) lsilogicR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4836{
4837 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ILed);
4838 if (iLUN == 0)
4839 {
4840 *ppLed = &pDevice->Led;
4841 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4842 return VINF_SUCCESS;
4843 }
4844 return VERR_PDM_LUN_NOT_FOUND;
4845}
4846
4847
4848/**
4849 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4850 */
4851static DECLCALLBACK(void *) lsilogicR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4852{
4853 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IBase);
4854
4855 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
4856 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pDevice->IMediaPort);
4857 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pDevice->IMediaExPort);
4858 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
4859 return NULL;
4860}
4861
4862
4863/*
4864 * The controller level IBASE and LED interfaces.
4865 */
4866
4867/**
4868 * Gets the pointer to the status LED of a unit.
4869 *
4870 * @returns VBox status code.
4871 * @param pInterface Pointer to the interface structure containing the called function pointer.
4872 * @param iLUN The unit which status LED we desire.
4873 * @param ppLed Where to store the LED pointer.
4874 */
4875static DECLCALLBACK(int) lsilogicR3StatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4876{
4877 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, ILeds);
4878 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PLSILOGICSCSI);
4879 if (iLUN < pThis->cDeviceStates)
4880 {
4881 *ppLed = &pThisCC->paDeviceStates[iLUN].Led;
4882 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4883 return VINF_SUCCESS;
4884 }
4885 return VERR_PDM_LUN_NOT_FOUND;
4886}
4887
4888/**
4889 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4890 */
4891static DECLCALLBACK(void *) lsilogicR3StatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4892{
4893 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, IBase);
4894 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4895 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds);
4896 return NULL;
4897}
4898
4899
4900/*
4901 * The PDM device interface and some helpers.
4902 */
4903
4904/**
4905 * Checks if all asynchronous I/O is finished.
4906 *
4907 * Used by lsilogicR3Reset, lsilogicR3Suspend and lsilogicR3PowerOff.
4908 *
4909 * @returns true if quiesced, false if busy.
4910 * @param pDevIns The device instance.
4911 */
4912static bool lsilogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
4913{
4914 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4915 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4916
4917 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4918 {
4919 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
4920 if (pThisDevice->pDrvBase)
4921 {
4922 if (pThisDevice->cOutstandingRequests != 0)
4923 return false;
4924 }
4925 }
4926
4927 return true;
4928}
4929
4930/**
4931 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
4932 * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.}
4933 */
4934static DECLCALLBACK(bool) lsilogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
4935{
4936 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4937 return false;
4938
4939 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4940 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4941 return true;
4942}
4943
4944/**
4945 * Common worker for ahciR3Suspend and ahciR3PowerOff.
4946 */
4947static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
4948{
4949 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4950 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4951
4952 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
4953 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4954 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncSuspendOrPowerOffDone);
4955 else
4956 {
4957 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4958
4959 AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
4960 }
4961
4962 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4963 {
4964 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
4965 if (pThisDevice->pDrvMediaEx)
4966 pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
4967 }
4968}
4969
4970/**
4971 * @interface_method_impl{PDMDEVREG,pfnSuspend}
4972 */
4973static DECLCALLBACK(void) lsilogicR3Suspend(PPDMDEVINS pDevIns)
4974{
4975 Log(("lsilogicR3Suspend\n"));
4976 lsilogicR3SuspendOrPowerOff(pDevIns);
4977}
4978
4979/**
4980 * @interface_method_impl{PDMDEVREG,pfnResume}
4981 */
4982static DECLCALLBACK(void) lsilogicR3Resume(PPDMDEVINS pDevIns)
4983{
4984 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4985
4986 Log(("lsilogicR3Resume\n"));
4987
4988 lsilogicR3Kick(pDevIns, pThis);
4989}
4990
4991/**
4992 * @interface_method_impl{PDMDEVREG,pfnDetach}
4993 *
4994 * One harddisk at one port has been unplugged.
4995 * The VM is suspended at this point.
4996 */
4997static DECLCALLBACK(void) lsilogicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4998{
4999 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5000 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5001 Log(("%s: iLUN=%#x\n", __FUNCTION__, iLUN));
5002 RT_NOREF(fFlags);
5003
5004 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG, ("LsiLogic: Device does not support hotplugging\n"));
5005
5006 if (iLUN >= pThis->cDeviceStates)
5007 return;
5008
5009 /*
5010 * Zero some important members.
5011 */
5012 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
5013 pDevice->pDrvBase = NULL;
5014 pDevice->pDrvMedia = NULL;
5015 pDevice->pDrvMediaEx = NULL;
5016}
5017
5018/**
5019 * @interface_method_impl{PDMDEVREG,pfnAttach}
5020 */
5021static DECLCALLBACK(int) lsilogicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5022{
5023 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5024 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5025 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
5026 int rc;
5027
5028 if (iLUN >= pThis->cDeviceStates)
5029 return VERR_PDM_LUN_NOT_FOUND;
5030
5031 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5032 ("LsiLogic: Device does not support hotplugging\n"),
5033 VERR_INVALID_PARAMETER);
5034
5035 /* the usual paranoia */
5036 AssertRelease(!pDevice->pDrvBase);
5037 AssertRelease(!pDevice->pDrvMedia);
5038 AssertRelease(!pDevice->pDrvMediaEx);
5039 Assert(pDevice->iLUN == iLUN);
5040
5041 /*
5042 * Try attach the block device and get the interfaces,
5043 * required as well as optional.
5044 */
5045 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
5046 if (RT_SUCCESS(rc))
5047 {
5048 /* Query the media interface. */
5049 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5050 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5051 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5052 VERR_PDM_MISSING_INTERFACE);
5053
5054 /* Get the extended media interface. */
5055 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5056 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5057 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5058 VERR_PDM_MISSING_INTERFACE);
5059
5060 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5061 AssertMsgRCReturn(rc, ("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!", pDevice->iLUN),
5062 rc);
5063 }
5064 else
5065 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
5066
5067 if (RT_FAILURE(rc))
5068 {
5069 pDevice->pDrvBase = NULL;
5070 pDevice->pDrvMedia = NULL;
5071 pDevice->pDrvMediaEx = NULL;
5072 }
5073 return rc;
5074}
5075
5076/**
5077 * Common reset worker.
5078 *
5079 * @param pDevIns The device instance data.
5080 */
5081static void lsilogicR3ResetCommon(PPDMDEVINS pDevIns)
5082{
5083 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5084 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5085 int rc;
5086
5087 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
5088 AssertRC(rc);
5089
5090 vboxscsiHwReset(&pThisCC->VBoxSCSI);
5091}
5092
5093/**
5094 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
5095 * Callback employed by lsilogicR3Reset.}
5096 */
5097static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns)
5098{
5099 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5100
5101 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5102 return false;
5103 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5104
5105 lsilogicR3ResetCommon(pDevIns);
5106 return true;
5107}
5108
5109/**
5110 * @interface_method_impl{PDMDEVREG,pfnReset}
5111 */
5112static DECLCALLBACK(void) lsilogicR3Reset(PPDMDEVINS pDevIns)
5113{
5114 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5115
5116 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
5117 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5118 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncResetDone);
5119 else
5120 {
5121 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5122 lsilogicR3ResetCommon(pDevIns);
5123 }
5124}
5125
5126/**
5127 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
5128 */
5129static DECLCALLBACK(void) lsilogicR3PowerOff(PPDMDEVINS pDevIns)
5130{
5131 Log(("lsilogicR3PowerOff\n"));
5132 lsilogicR3SuspendOrPowerOff(pDevIns);
5133}
5134
5135/**
5136 * @interface_method_impl{PDMDEVREG,pfnDestruct}
5137 */
5138static DECLCALLBACK(int) lsilogicR3Destruct(PPDMDEVINS pDevIns)
5139{
5140 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5141 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5142 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5143
5144 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueCritSect);
5145 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyPostQueueCritSect);
5146 PDMDevHlpCritSectDelete(pDevIns, &pThis->RequestQueueCritSect);
5147 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueWriteCritSect);
5148
5149 RTMemFree(pThisCC->paDeviceStates);
5150 pThisCC->paDeviceStates = NULL;
5151
5152 if (pThis->hEvtProcess != NIL_SUPSEMEVENT)
5153 {
5154 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtProcess);
5155 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5156 }
5157
5158 lsilogicR3ConfigurationPagesFree(pThis, pThisCC);
5159 lsilogicR3MemRegionsFree(pThisCC);
5160 vboxscsiDestroy(&pThisCC->VBoxSCSI);
5161
5162 return VINF_SUCCESS;
5163}
5164
5165/**
5166 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5167 */
5168static DECLCALLBACK(int) lsilogicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5169{
5170 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5171 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5172 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5173 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5174 int rc = VINF_SUCCESS;
5175
5176 /*
5177 * Initialize enought of the state to make the destructure not trip up.
5178 */
5179 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5180 pThis->fBiosReqPending = false;
5181 RTListInit(&pThisCC->ListMemRegns);
5182 pThis->hMmioReg = NIL_IOMMMIOHANDLE;
5183 pThis->hMmioDiag = NIL_IOMMMIOHANDLE;
5184 pThis->hIoPortsReg = NIL_IOMIOPORTHANDLE;
5185 pThis->hIoPortsBios = NIL_IOMIOPORTHANDLE;
5186 pThisCC->pDevIns = pDevIns;
5187 pThisCC->IBase.pfnQueryInterface = lsilogicR3StatusQueryInterface;
5188 pThisCC->ILeds.pfnQueryStatusLed = lsilogicR3StatusQueryStatusLed;
5189
5190
5191 /*
5192 * Validate and read configuration.
5193 */
5194 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
5195 "ReplyQueueDepth|"
5196 "RequestQueueDepth|"
5197 "ControllerType|"
5198 "NumPorts|"
5199 "Bootable",
5200 "");
5201
5202 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "ReplyQueueDepth",
5203 &pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT);
5204 if (RT_FAILURE(rc))
5205 return PDMDEV_SET_ERROR(pDevIns, rc,
5206 N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
5207 if ( pThis->cReplyQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN
5208 || pThis->cReplyQueueEntries > LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5209 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5210 N_("LsiLogic configuration error: 'ReplyQueueDepth' = %u is out of ranage (%u..%u)"),
5211 pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN,
5212 LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1);
5213 Log(("%s: ReplyQueueDepth=%u\n", __FUNCTION__, pThis->cReplyQueueEntries));
5214
5215 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "RequestQueueDepth",
5216 &pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT);
5217 if (RT_FAILURE(rc))
5218 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
5219 if ( pThis->cRequestQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
5220 || pThis->cRequestQueueEntries > LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5221 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5222 N_("LsiLogic configuration error: 'RequestQueue' = %u is out of ranage (%u..%u)"),
5223 pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN,
5224 LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN - 1);
5225 Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries));
5226
5227 char szCtrlType[64];
5228 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "ControllerType", szCtrlType, sizeof(szCtrlType), LSILOGICSCSI_PCI_SPI_CTRLNAME);
5229 if (RT_FAILURE(rc))
5230 return PDMDEV_SET_ERROR(pDevIns, rc,
5231 N_("LsiLogic configuration error: failed to read ControllerType as string"));
5232 Log(("%s: ControllerType=%s\n", __FUNCTION__, szCtrlType));
5233 rc = lsilogicR3GetCtrlTypeFromString(pThis, szCtrlType);
5234 if (RT_FAILURE(rc))
5235 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to determine controller type from string"));
5236
5237 char szDevTag[20];
5238 RTStrPrintf(szDevTag, sizeof(szDevTag), "LSILOGIC%s-%u",
5239 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "SPI" : "SAS",
5240 iInstance);
5241
5242 rc = pHlp->pfnCFGMQueryU8(pCfg, "NumPorts", &pThis->cPorts);
5243 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5244 {
5245 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5246 pThis->cPorts = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
5247 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5248 pThis->cPorts = LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT;
5249 else
5250 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5251 }
5252 else if (RT_FAILURE(rc))
5253 return PDMDEV_SET_ERROR(pDevIns, rc,
5254 N_("LsiLogic configuration error: failed to read NumPorts as integer"));
5255
5256 bool fBootable;
5257 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Bootable", &fBootable, true);
5258 if (RT_FAILURE(rc))
5259 return PDMDEV_SET_ERROR(pDevIns, rc,
5260 N_("LsiLogic configuration error: failed to read Bootable as boolean"));
5261 Log(("%s: Bootable=%RTbool\n", __FUNCTION__, fBootable));
5262
5263 /* Init static parts. */
5264 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
5265 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
5266
5267 PDMPciDevSetVendorId(pPciDev, LSILOGICSCSI_PCI_VENDOR_ID); /* LsiLogic */
5268 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5269 {
5270 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SPI_DEVICE_ID); /* LSI53C1030 */
5271 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID);
5272 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID);
5273 }
5274 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5275 {
5276 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SAS_DEVICE_ID); /* SAS1068 */
5277 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID);
5278 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID);
5279 }
5280 else
5281 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5282
5283 PDMPciDevSetClassProg(pPciDev, 0x00); /* SCSI */
5284 PDMPciDevSetClassSub(pPciDev, 0x00); /* SCSI */
5285 PDMPciDevSetClassBase(pPciDev, 0x01); /* Mass storage */
5286 PDMPciDevSetInterruptPin(pPciDev, 0x01); /* Interrupt pin A */
5287
5288# ifdef VBOX_WITH_MSI_DEVICES
5289 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
5290 PDMPciDevSetCapabilityList(pPciDev, 0x80);
5291# endif
5292
5293 /*
5294 * Create critical sections protecting the reply post and free queues.
5295 */
5296 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag);
5297 if (RT_FAILURE(rc))
5298 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue"));
5299
5300 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag);
5301 if (RT_FAILURE(rc))
5302 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply post queue"));
5303
5304 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->RequestQueueCritSect, RT_SRC_POS, "%sRQ", szDevTag);
5305 if (RT_FAILURE(rc))
5306 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for request queue"));
5307
5308 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueWriteCritSect, RT_SRC_POS, "%sRFQW", szDevTag);
5309 if (RT_FAILURE(rc))
5310 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue write access"));
5311
5312 /*
5313 * Register the PCI device, it's I/O regions.
5314 */
5315 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
5316 if (RT_FAILURE(rc))
5317 return rc;
5318
5319# ifdef VBOX_WITH_MSI_DEVICES
5320 PDMMSIREG MsiReg;
5321 RT_ZERO(MsiReg);
5322 /* use this code for MSI-X support */
5323# if 0
5324 MsiReg.cMsixVectors = 1;
5325 MsiReg.iMsixCapOffset = 0x80;
5326 MsiReg.iMsixNextOffset = 0x00;
5327 MsiReg.iMsixBar = 3;
5328 Assert(pDevIns->pReg->cMaxMsixVectors >= MsiReg.cMsixVectors); /* fix device registration when enabling this */
5329# else
5330 MsiReg.cMsiVectors = 1;
5331 MsiReg.iMsiCapOffset = 0x80;
5332 MsiReg.iMsiNextOffset = 0x00;
5333# endif
5334 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
5335 if (RT_FAILURE (rc))
5336 {
5337 /* That's OK, we can work without MSI */
5338 PDMPciDevSetCapabilityList(pPciDev, 0x0);
5339 }
5340# endif
5341
5342 /* Region #0: I/O ports. */
5343 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, LSILOGIC_PCI_SPACE_IO_SIZE,
5344 lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/,
5345 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5346 NULL /*paExtDesc*/, &pThis->hIoPortsReg);
5347 AssertRCReturn(rc, rc);
5348
5349 /* Region #1: MMIO.
5350 *
5351 * Non-4-byte read access to LSILOGIC_REG_REPLY_QUEUE may cause real strange behavior
5352 * because the data is part of a physical guest address. But some drivers use 1-byte
5353 * access to scan for SCSI controllers. So, we simplify our code by telling IOM to
5354 * read DWORDs.
5355 *
5356 * Regarding writes, we couldn't find anything specific in the specs about what should
5357 * happen. So far we've ignored unaligned writes and assumed the missing bytes of
5358 * byte and word access to be zero. We suspect that IOMMMIO_FLAGS_WRITE_ONLY_DWORD
5359 * or IOMMMIO_FLAGS_WRITE_DWORD_ZEROED would be the most appropriate here, but since we
5360 * don't have real hw to test one, the old behavior is kept exactly like it used to be.
5361 */
5362 /** @todo Check out unaligned writes and non-dword writes on real LsiLogic
5363 * hardware. */
5364 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 1 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5365 lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/,
5366 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5367 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5368 &pThis->hMmioReg);
5369 AssertRCReturn(rc, rc);
5370
5371 /* Region #2: MMIO - Diag. */
5372 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 2 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5373 lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/,
5374 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5375 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogicDiag" : "LsiLogicSasDiag",
5376 &pThis->hMmioDiag);
5377 AssertRCReturn(rc, rc);
5378
5379 /*
5380 * We need one entry free in the queue.
5381 */
5382 pThis->cReplyQueueEntries++;
5383 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyFreeQueue), VERR_INTERNAL_ERROR_3);
5384 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyPostQueue), VERR_INTERNAL_ERROR_3);
5385
5386 pThis->cRequestQueueEntries++;
5387 AssertLogRelReturn(pThis->cRequestQueueEntries <= RT_ELEMENTS(pThis->aRequestQueue), VERR_INTERNAL_ERROR_3);
5388
5389 /*
5390 * Device states.
5391 */
5392 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5393 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
5394 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5395 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
5396 else
5397 AssertLogRelMsgFailedReturn(("Invalid controller type: %d\n", pThis->enmCtrlType), VERR_INTERNAL_ERROR_4);
5398
5399 /*
5400 * Create event semaphore and worker thread.
5401 */
5402 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pThreadWrk, pThis, lsilogicR3Worker,
5403 lsilogicR3WorkerWakeUp, 0, RTTHREADTYPE_IO, szDevTag);
5404 if (RT_FAILURE(rc))
5405 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5406 N_("LsiLogic: Failed to create worker thread %s"), szDevTag);
5407
5408 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtProcess);
5409 if (RT_FAILURE(rc))
5410 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5411 N_("LsiLogic: Failed to create SUP event semaphore"));
5412
5413 /*
5414 * Allocate device states.
5415 */
5416 pThisCC->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
5417 if (!pThisCC->paDeviceStates)
5418 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate memory for device states"));
5419
5420 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
5421 {
5422 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
5423
5424 /* Initialize static parts of the device. */
5425 pDevice->iLUN = i;
5426 pDevice->pDevIns = pDevIns;
5427 pDevice->Led.u32Magic = PDMLED_MAGIC;
5428 pDevice->IBase.pfnQueryInterface = lsilogicR3DeviceQueryInterface;
5429 pDevice->IMediaPort.pfnQueryDeviceLocation = lsilogicR3QueryDeviceLocation;
5430 pDevice->IMediaExPort.pfnIoReqCompleteNotify = lsilogicR3IoReqCompleteNotify;
5431 pDevice->IMediaExPort.pfnIoReqCopyFromBuf = lsilogicR3IoReqCopyFromBuf;
5432 pDevice->IMediaExPort.pfnIoReqCopyToBuf = lsilogicR3IoReqCopyToBuf;
5433 pDevice->IMediaExPort.pfnIoReqQueryBuf = NULL;
5434 pDevice->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
5435 pDevice->IMediaExPort.pfnIoReqStateChanged = lsilogicR3IoReqStateChanged;
5436 pDevice->IMediaExPort.pfnMediumEjected = lsilogicR3MediumEjected;
5437 pDevice->ILed.pfnQueryStatusLed = lsilogicR3DeviceQueryStatusLed;
5438 RTStrPrintf(pDevice->szName, sizeof(pDevice->szName), "Device%u", i);
5439
5440 /* Attach SCSI driver. */
5441 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, pDevice->szName);
5442 if (RT_SUCCESS(rc))
5443 {
5444 /* Query the media interface. */
5445 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5446 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5447 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5448 VERR_PDM_MISSING_INTERFACE);
5449
5450 /* Get the extended media interface. */
5451 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5452 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5453 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5454 VERR_PDM_MISSING_INTERFACE);
5455
5456 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5457 if (RT_FAILURE(rc))
5458 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5459 N_("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!"),
5460 pDevice->iLUN);
5461 }
5462 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5463 {
5464 pDevice->pDrvBase = NULL;
5465 rc = VINF_SUCCESS;
5466 Log(("LsiLogic: no driver attached to device %s\n", pDevice->szName));
5467 }
5468 else
5469 {
5470 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", pDevice->szName));
5471 return rc;
5472 }
5473 }
5474
5475 /*
5476 * Attach status driver (optional).
5477 */
5478 PPDMIBASE pBase;
5479 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
5480 if (RT_SUCCESS(rc))
5481 {
5482 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5483 pThisCC->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
5484 }
5485 else
5486 AssertMsgReturn(rc == VERR_PDM_NO_ATTACHED_DRIVER,
5487 ("Failed to attach to status driver. rc=%Rrc\n", rc),
5488 PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver")));
5489
5490 /* Initialize the SCSI emulation for the BIOS. */
5491 rc = vboxscsiInitialize(&pThisCC->VBoxSCSI);
5492 if (RT_FAILURE(rc))
5493 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic failed to initialize BIOS SCSI interface"));
5494
5495 /*
5496 * Register I/O port space in ISA region for BIOS access
5497 * if the controller is marked as bootable.
5498 */
5499 if (fBootable)
5500 {
5501 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5502 rc = PDMDevHlpIoPortCreateExAndMap(pDevIns, LSILOGIC_BIOS_IO_PORT, 4 /*cPorts*/, 0 /*fFlags*/,
5503 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5504 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, NULL /*pvUser*/,
5505 "LsiLogic BIOS", NULL /*paExtDesc*/, &pThis->hIoPortsBios);
5506 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5507 rc = PDMDevHlpIoPortCreateExAndMap(pDevIns, LSILOGIC_SAS_BIOS_IO_PORT, 4 /*cPorts*/, 0 /*fFlags*/,
5508 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5509 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, NULL /*pvUser*/,
5510 "LsiLogic SAS BIOS", NULL /*paExtDesc*/, &pThis->hIoPortsBios);
5511 else
5512 AssertMsgFailedReturn(("Invalid controller type %d\n", pThis->enmCtrlType), VERR_INTERNAL_ERROR_3);
5513 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register legacy I/O handlers")));
5514 }
5515
5516 /* Register save state handlers. */
5517 rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5518 NULL, lsilogicR3LiveExec, NULL,
5519 NULL, lsilogicR3SaveExec, NULL,
5520 NULL, lsilogicR3LoadExec, lsilogicR3LoadDone);
5521 if (RT_FAILURE(rc))
5522 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
5523
5524 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
5525
5526 /*
5527 * Register the info item.
5528 */
5529 char szTmp[128];
5530 RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
5531 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp,
5532 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
5533 ? "LsiLogic SPI info."
5534 : "LsiLogic SAS info.", lsilogicR3Info);
5535
5536 /* Perform hard reset. */
5537 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
5538 AssertRC(rc);
5539
5540 return rc;
5541}
5542
5543#else /* !IN_RING3 */
5544
5545/**
5546 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5547 */
5548static DECLCALLBACK(int) lsilogicRZConstruct(PPDMDEVINS pDevIns)
5549{
5550 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5551 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5552
5553 /* Setup callbacks for this context: */
5554 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsReg, lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/);
5555 AssertRCReturn(rc, rc);
5556
5557 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioReg, lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/);
5558 AssertRCReturn(rc, rc);
5559
5560 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioDiag, lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/);
5561 AssertRCReturn(rc, rc);
5562
5563 return VINF_SUCCESS;
5564}
5565
5566#endif /* !IN_RING3 */
5567
5568/**
5569 * The device registration structure - SPI SCSI controller.
5570 */
5571const PDMDEVREG g_DeviceLsiLogicSCSI =
5572{
5573 /* .u32Version = */ PDM_DEVREG_VERSION,
5574 /* .uReserved0 = */ 0,
5575 /* .szName = */ "lsilogicscsi",
5576 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5577 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
5578 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5579 /* .cMaxInstances = */ ~0U,
5580 /* .uSharedVersion = */ 42,
5581 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
5582 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5583 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
5584 /* .cMaxPciDevices = */ 1,
5585 /* .cMaxMsixVectors = */ 0,
5586 /* .pszDescription = */ "LSI Logic 53c1030 SCSI controller.\n",
5587#if defined(IN_RING3)
5588 /* .pszRCMod = */ "VBoxDDRC.rc",
5589 /* .pszR0Mod = */ "VBoxDDR0.r0",
5590 /* .pfnConstruct = */ lsilogicR3Construct,
5591 /* .pfnDestruct = */ lsilogicR3Destruct,
5592 /* .pfnRelocate = */ NULL,
5593 /* .pfnMemSetup = */ NULL,
5594 /* .pfnPowerOn = */ NULL,
5595 /* .pfnReset = */ lsilogicR3Reset,
5596 /* .pfnSuspend = */ lsilogicR3Suspend,
5597 /* .pfnResume = */ lsilogicR3Resume,
5598 /* .pfnAttach = */ lsilogicR3Attach,
5599 /* .pfnDetach = */ lsilogicR3Detach,
5600 /* .pfnQueryInterface = */ NULL,
5601 /* .pfnInitComplete = */ NULL,
5602 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5603 /* .pfnSoftReset = */ NULL,
5604 /* .pfnReserved0 = */ NULL,
5605 /* .pfnReserved1 = */ NULL,
5606 /* .pfnReserved2 = */ NULL,
5607 /* .pfnReserved3 = */ NULL,
5608 /* .pfnReserved4 = */ NULL,
5609 /* .pfnReserved5 = */ NULL,
5610 /* .pfnReserved6 = */ NULL,
5611 /* .pfnReserved7 = */ NULL,
5612#elif defined(IN_RING0)
5613 /* .pfnEarlyConstruct = */ NULL,
5614 /* .pfnConstruct = */ lsilogicRZConstruct,
5615 /* .pfnDestruct = */ NULL,
5616 /* .pfnFinalDestruct = */ NULL,
5617 /* .pfnRequest = */ NULL,
5618 /* .pfnReserved0 = */ NULL,
5619 /* .pfnReserved1 = */ NULL,
5620 /* .pfnReserved2 = */ NULL,
5621 /* .pfnReserved3 = */ NULL,
5622 /* .pfnReserved4 = */ NULL,
5623 /* .pfnReserved5 = */ NULL,
5624 /* .pfnReserved6 = */ NULL,
5625 /* .pfnReserved7 = */ NULL,
5626#elif defined(IN_RC)
5627 /* .pfnConstruct = */ lsilogicRZConstruct,
5628 /* .pfnReserved0 = */ NULL,
5629 /* .pfnReserved1 = */ NULL,
5630 /* .pfnReserved2 = */ NULL,
5631 /* .pfnReserved3 = */ NULL,
5632 /* .pfnReserved4 = */ NULL,
5633 /* .pfnReserved5 = */ NULL,
5634 /* .pfnReserved6 = */ NULL,
5635 /* .pfnReserved7 = */ NULL,
5636#else
5637# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5638#endif
5639 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5640};
5641
5642/**
5643 * The device registration structure - SAS controller.
5644 */
5645const PDMDEVREG g_DeviceLsiLogicSAS =
5646{
5647 /* .u32Version = */ PDM_DEVREG_VERSION,
5648 /* .uReserved0 = */ 0,
5649 /* .szName = */ "lsilogicsas",
5650 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5651 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION
5652 | PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
5653 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5654 /* .cMaxInstances = */ ~0U,
5655 /* .uSharedVersion = */ 42,
5656 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
5657 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5658 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
5659 /* .cMaxPciDevices = */ 1,
5660 /* .cMaxMsixVectors = */ 0,
5661 /* .pszDescription = */ "LSI Logic SAS1068 controller.\n",
5662#if defined(IN_RING3)
5663 /* .pszRCMod = */ "VBoxDDRC.rc",
5664 /* .pszR0Mod = */ "VBoxDDR0.r0",
5665 /* .pfnConstruct = */ lsilogicR3Construct,
5666 /* .pfnDestruct = */ lsilogicR3Destruct,
5667 /* .pfnRelocate = */ NULL,
5668 /* .pfnMemSetup = */ NULL,
5669 /* .pfnPowerOn = */ NULL,
5670 /* .pfnReset = */ lsilogicR3Reset,
5671 /* .pfnSuspend = */ lsilogicR3Suspend,
5672 /* .pfnResume = */ lsilogicR3Resume,
5673 /* .pfnAttach = */ lsilogicR3Attach,
5674 /* .pfnDetach = */ lsilogicR3Detach,
5675 /* .pfnQueryInterface = */ NULL,
5676 /* .pfnInitComplete = */ NULL,
5677 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5678 /* .pfnSoftReset = */ NULL,
5679 /* .pfnReserved0 = */ NULL,
5680 /* .pfnReserved1 = */ NULL,
5681 /* .pfnReserved2 = */ NULL,
5682 /* .pfnReserved3 = */ NULL,
5683 /* .pfnReserved4 = */ NULL,
5684 /* .pfnReserved5 = */ NULL,
5685 /* .pfnReserved6 = */ NULL,
5686 /* .pfnReserved7 = */ NULL,
5687#elif defined(IN_RING0)
5688 /* .pfnEarlyConstruct = */ NULL,
5689 /* .pfnConstruct = */ lsilogicRZConstruct,
5690 /* .pfnDestruct = */ NULL,
5691 /* .pfnFinalDestruct = */ NULL,
5692 /* .pfnRequest = */ NULL,
5693 /* .pfnReserved0 = */ NULL,
5694 /* .pfnReserved1 = */ NULL,
5695 /* .pfnReserved2 = */ NULL,
5696 /* .pfnReserved3 = */ NULL,
5697 /* .pfnReserved4 = */ NULL,
5698 /* .pfnReserved5 = */ NULL,
5699 /* .pfnReserved6 = */ NULL,
5700 /* .pfnReserved7 = */ NULL,
5701#elif defined(IN_RC)
5702 /* .pfnConstruct = */ lsilogicRZConstruct,
5703 /* .pfnReserved0 = */ NULL,
5704 /* .pfnReserved1 = */ NULL,
5705 /* .pfnReserved2 = */ NULL,
5706 /* .pfnReserved3 = */ NULL,
5707 /* .pfnReserved4 = */ NULL,
5708 /* .pfnReserved5 = */ NULL,
5709 /* .pfnReserved6 = */ NULL,
5710 /* .pfnReserved7 = */ NULL,
5711#else
5712# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5713#endif
5714 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5715};
5716
5717#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