VirtualBox

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

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

AMD IOMMU: bugref:9654 LsiLogic: Use PCI interfaces while reading/writing guest physical memory.

  • 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 86483 2020-10-08 06:53:36Z 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 PDMDevHlpPCIPhysReadUser(pDevIns, GCPhys, pvSeg, cbSeg);
1901 GCPhys += cbSeg;
1902 cbCopy -= cbSeg;
1903 }
1904}
1905
1906/**
1907 * Copy from host to guest memory worker.
1908 *
1909 * @copydoc FNLSILOGICR3MEMCOPYCALLBACK
1910 */
1911static DECLCALLBACK(void) lsilogicR3CopyBufferToGuestWorker(PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
1912 PRTSGBUF pSgBuf, size_t cbCopy, size_t *pcbSkip)
1913{
1914 size_t cbSkipped = RT_MIN(cbCopy, *pcbSkip);
1915 cbCopy -= cbSkipped;
1916 GCPhys += cbSkipped;
1917 *pcbSkip -= cbSkipped;
1918
1919 while (cbCopy)
1920 {
1921 size_t cbSeg = cbCopy;
1922 void *pvSeg = RTSgBufGetNextSegment(pSgBuf, &cbSeg);
1923
1924 AssertPtr(pvSeg);
1925 PDMDevHlpPCIPhysWriteUser(pDevIns, GCPhys, pvSeg, cbSeg);
1926 GCPhys += cbSeg;
1927 cbCopy -= cbSeg;
1928 }
1929}
1930
1931/**
1932 * Walks the guest S/G buffer calling the given copy worker for every buffer.
1933 *
1934 * @returns The amout of bytes actually copied.
1935 * @param pDevIns The device instance.
1936 * @param pLsiReq LSI request state.
1937 * @param pfnCopyWorker The copy method to apply for each guest buffer.
1938 * @param pSgBuf The host S/G buffer.
1939 * @param cbSkip How many bytes to skip in advance before starting to
1940 * copy.
1941 * @param cbCopy How many bytes to copy.
1942 */
1943static size_t lsilogicSgBufWalker(PPDMDEVINS pDevIns, PLSILOGICREQ pLsiReq,
1944 PFNLSILOGICR3MEMCOPYCALLBACK pfnCopyWorker,
1945 PRTSGBUF pSgBuf, size_t cbSkip, size_t cbCopy)
1946{
1947 bool fEndOfList = false;
1948 RTGCPHYS GCPhysSgEntryNext = pLsiReq->GCPhysSgStart;
1949 RTGCPHYS GCPhysSegmentStart = pLsiReq->GCPhysSgStart;
1950 uint32_t cChainOffsetNext = pLsiReq->cChainOffset;
1951 size_t cbCopied = 0;
1952
1953 /*
1954 * Add the amount to skip to the host buffer size to avoid a
1955 * few conditionals later on.
1956 */
1957 cbCopy += cbSkip;
1958
1959 /* Go through the list until we reach the end. */
1960 while ( !fEndOfList
1961 && cbCopy)
1962 {
1963 bool fEndOfSegment = false;
1964
1965 while ( !fEndOfSegment
1966 && cbCopy)
1967 {
1968 MptSGEntryUnion SGEntry;
1969
1970 Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSgEntryNext));
1971
1972 /* Read the entry. */
1973 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysSgEntryNext, &SGEntry, sizeof(MptSGEntryUnion));
1974
1975# ifdef LOG_ENABLED
1976 lsilogicDumpSGEntry(&SGEntry);
1977# endif
1978
1979 AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n"));
1980
1981 /* Check if this is a zero element and abort. */
1982 if ( !SGEntry.Simple32.u24Length
1983 && SGEntry.Simple32.fEndOfList
1984 && SGEntry.Simple32.fEndOfBuffer)
1985 return cbCopied - RT_MIN(cbSkip, cbCopied);
1986
1987 size_t cbCopyThis = RT_MIN(SGEntry.Simple32.u24Length, cbCopy);
1988 RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow;
1989
1990 if (SGEntry.Simple32.f64BitAddress)
1991 {
1992 GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32;
1993 GCPhysSgEntryNext += sizeof(MptSGEntrySimple64);
1994 }
1995 else
1996 GCPhysSgEntryNext += sizeof(MptSGEntrySimple32);
1997
1998 pfnCopyWorker(pDevIns, GCPhysAddrDataBuffer, pSgBuf, cbCopyThis, &cbSkip);
1999 cbCopy -= cbCopyThis;
2000 cbCopied += cbCopyThis;
2001
2002 /* Check if we reached the end of the list. */
2003 if (SGEntry.Simple32.fEndOfList)
2004 {
2005 /* We finished. */
2006 fEndOfSegment = true;
2007 fEndOfList = true;
2008 }
2009 else if (SGEntry.Simple32.fLastElement)
2010 fEndOfSegment = true;
2011 } /* while (!fEndOfSegment) */
2012
2013 /* Get next chain element. */
2014 if (cChainOffsetNext)
2015 {
2016 MptSGEntryChain SGEntryChain;
2017
2018 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysSegmentStart + cChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
2019
2020 AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n"));
2021
2022 /* Set the next address now. */
2023 GCPhysSgEntryNext = SGEntryChain.u32SegmentAddressLow;
2024 if (SGEntryChain.f64BitAddress)
2025 GCPhysSgEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32;
2026
2027 GCPhysSegmentStart = GCPhysSgEntryNext;
2028 cChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t);
2029 }
2030 } /* while (!fEndOfList) */
2031
2032 return cbCopied - RT_MIN(cbSkip, cbCopied);
2033}
2034
2035/**
2036 * Copies a data buffer into the S/G buffer set up by the guest.
2037 *
2038 * @returns Amount of bytes copied to the guest.
2039 * @param pDevIns The device instance.
2040 * @param pReq Request structure.
2041 * @param pSgBuf The S/G buffer to copy from.
2042 * @param cbSkip How many bytes to skip in advance before starting to copy.
2043 * @param cbCopy How many bytes to copy.
2044 */
2045static size_t lsilogicR3CopySgBufToGuest(PPDMDEVINS pDevIns, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
2046 size_t cbSkip, size_t cbCopy)
2047{
2048 return lsilogicSgBufWalker(pDevIns, pReq, lsilogicR3CopyBufferToGuestWorker, pSgBuf, cbSkip, cbCopy);
2049}
2050
2051/**
2052 * Copies the guest S/G buffer into a host data buffer.
2053 *
2054 * @returns Amount of bytes copied from the guest.
2055 * @param pDevIns The device instance.
2056 * @param pReq Request structure.
2057 * @param pSgBuf The S/G buffer to copy into.
2058 * @param cbSkip How many bytes to skip in advance before starting to copy.
2059 * @param cbCopy How many bytes to copy.
2060 */
2061static size_t lsilogicR3CopySgBufFromGuest(PPDMDEVINS pDevIns, PLSILOGICREQ pReq, PRTSGBUF pSgBuf,
2062 size_t cbSkip, size_t cbCopy)
2063{
2064 return lsilogicSgBufWalker(pDevIns, pReq, lsilogicR3CopyBufferFromGuestWorker, pSgBuf, cbSkip, cbCopy);
2065}
2066
2067#if 0 /* unused */
2068/**
2069 * Copy a simple memory buffer to the guest memory buffer.
2070 *
2071 * @returns Amount of bytes copied to the guest.
2072 * @param pThis The LsiLogic controller device instance.
2073 * @param pReq Request structure.
2074 * @param pvSrc The buffer to copy from.
2075 * @param cbSrc How many bytes to copy.
2076 * @param cbSkip How many bytes to skip initially.
2077 */
2078static size_t lsilogicR3CopyBufferToGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, const void *pvSrc,
2079 size_t cbSrc, size_t cbSkip)
2080{
2081 RTSGSEG Seg;
2082 RTSGBUF SgBuf;
2083 Seg.pvSeg = (void *)pvSrc;
2084 Seg.cbSeg = cbSrc;
2085 RTSgBufInit(&SgBuf, &Seg, 1);
2086 return lsilogicR3CopySgBufToGuest(pThis, pReq, &SgBuf, cbSkip, cbSrc);
2087}
2088
2089/**
2090 * Copy a guest memry buffe into simple host memory buffer.
2091 *
2092 * @returns Amount of bytes copied to the guest.
2093 * @param pThis The LsiLogic controller device instance.
2094 * @param pReq Request structure.
2095 * @param pvSrc The buffer to copy from.
2096 * @param cbSrc How many bytes to copy.
2097 * @param cbSkip How many bytes to skip initially.
2098 */
2099static size_t lsilogicR3CopyBufferFromGuest(PLSILOGICSCSI pThis, PLSILOGICREQ pReq, void *pvDst,
2100 size_t cbDst, size_t cbSkip)
2101{
2102 RTSGSEG Seg;
2103 RTSGBUF SgBuf;
2104 Seg.pvSeg = (void *)pvDst;
2105 Seg.cbSeg = cbDst;
2106 RTSgBufInit(&SgBuf, &Seg, 1);
2107 return lsilogicR3CopySgBufFromGuest(pThis, pReq, &SgBuf, cbSkip, cbDst);
2108}
2109#endif
2110
2111# ifdef LOG_ENABLED
2112static void lsilogicR3DumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest)
2113{
2114 if (LogIsEnabled())
2115 {
2116 Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID));
2117 Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus));
2118 Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset));
2119 Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function));
2120 Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength));
2121 Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength));
2122 Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags));
2123 Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext));
2124 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++)
2125 Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i]));
2126 Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control));
2127 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++)
2128 Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i]));
2129 Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength));
2130 Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
2131 }
2132}
2133# endif
2134
2135/**
2136 * Handles the completion of th given request.
2137 *
2138 * @returns nothing.
2139 * @param pDevIns The device instance.
2140 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
2141 * @param pThis Pointer to the shared LsiLogic device state.
2142 * @param pReq The request to complete.
2143 * @param rcReq Status code of the request.
2144 */
2145static void lsilogicR3ReqComplete(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC, PLSILOGICREQ pReq, int rcReq)
2146{
2147 PLSILOGICDEVICE pTgtDev = pReq->pTargetDevice;
2148
2149 if (!pReq->fBIOS)
2150 {
2151 RTGCPHYS GCPhysAddrSenseBuffer;
2152
2153 GCPhysAddrSenseBuffer = pReq->GuestRequest.SCSIIO.u32SenseBufferLowAddress;
2154 GCPhysAddrSenseBuffer |= ((uint64_t)pThis->u32SenseBufferHighAddr << 32);
2155
2156 /* Copy the sense buffer over. */
2157 if (pReq->GuestRequest.SCSIIO.u8SenseBufferLength > 0)
2158 PDMDevHlpPCIPhysWriteMeta(pDevIns, GCPhysAddrSenseBuffer, pReq->abSenseBuffer,
2159 RT_UNLIKELY( pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2160 < sizeof(pReq->abSenseBuffer))
2161 ? pReq->GuestRequest.SCSIIO.u8SenseBufferLength
2162 : sizeof(pReq->abSenseBuffer));
2163
2164 if (RT_SUCCESS(rcReq) && RT_LIKELY(pReq->u8ScsiSts == SCSI_STATUS_OK))
2165 {
2166 uint32_t u32MsgCtx = pReq->GuestRequest.SCSIIO.u32MessageContext;
2167
2168 /* Free the request before posting completion. */
2169 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2170 lsilogicR3FinishContextReply(pDevIns, pThis, u32MsgCtx);
2171 }
2172 else
2173 {
2174 MptReplyUnion IOCReply;
2175 RT_ZERO(IOCReply);
2176
2177 /* The SCSI target encountered an error during processing post a reply. */
2178 IOCReply.SCSIIOError.u8TargetID = pReq->GuestRequest.SCSIIO.u8TargetID;
2179 IOCReply.SCSIIOError.u8Bus = pReq->GuestRequest.SCSIIO.u8Bus;
2180 IOCReply.SCSIIOError.u8MessageLength = 8;
2181 IOCReply.SCSIIOError.u8Function = pReq->GuestRequest.SCSIIO.u8Function;
2182 IOCReply.SCSIIOError.u8CDBLength = pReq->GuestRequest.SCSIIO.u8CDBLength;
2183 IOCReply.SCSIIOError.u8SenseBufferLength = pReq->GuestRequest.SCSIIO.u8SenseBufferLength;
2184 IOCReply.SCSIIOError.u8MessageFlags = pReq->GuestRequest.SCSIIO.u8MessageFlags;
2185 IOCReply.SCSIIOError.u32MessageContext = pReq->GuestRequest.SCSIIO.u32MessageContext;
2186 IOCReply.SCSIIOError.u8SCSIStatus = pReq->u8ScsiSts;
2187 IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_AUTOSENSE_VALID;
2188 IOCReply.SCSIIOError.u16IOCStatus = 0;
2189 IOCReply.SCSIIOError.u32IOCLogInfo = 0;
2190 IOCReply.SCSIIOError.u32TransferCount = 0;
2191 IOCReply.SCSIIOError.u32SenseCount = sizeof(pReq->abSenseBuffer);
2192 IOCReply.SCSIIOError.u32ResponseInfo = 0;
2193
2194 /* Free the request before posting completion. */
2195 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2196 lsilogicFinishAddressReply(pDevIns, pThis, &IOCReply, false);
2197 }
2198 }
2199 else
2200 {
2201 uint8_t u8ScsiSts = pReq->u8ScsiSts;
2202 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
2203 int rc = vboxscsiRequestFinished(&pThisCC->VBoxSCSI, u8ScsiSts);
2204 AssertMsgRC(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc));
2205 }
2206
2207 ASMAtomicDecU32(&pTgtDev->cOutstandingRequests);
2208
2209 if (pTgtDev->cOutstandingRequests == 0 && pThis->fSignalIdle)
2210 PDMDevHlpAsyncNotificationCompleted(pDevIns);
2211}
2212
2213/**
2214 * Processes a SCSI I/O request by setting up the request
2215 * and sending it to the underlying SCSI driver.
2216 * Steps needed to complete request are done in the
2217 * callback called by the driver below upon completion of
2218 * the request.
2219 *
2220 * @returns VBox status code.
2221 * @param pDevIns The device instance.
2222 * @param pThis Pointer to the shared LsiLogic device state.
2223 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
2224 * @param GCPhysMessageFrameAddr Guest physical address where the request is located.
2225 * @param pGuestReq The request read fro th guest memory.
2226 */
2227static int lsilogicR3ProcessSCSIIORequest(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC,
2228 RTGCPHYS GCPhysMessageFrameAddr, PMptRequestUnion pGuestReq)
2229{
2230 MptReplyUnion IOCReply;
2231 int rc = VINF_SUCCESS;
2232
2233# ifdef LOG_ENABLED
2234 lsilogicR3DumpSCSIIORequest(&pGuestReq->SCSIIO);
2235# endif
2236
2237 if (RT_LIKELY( (pGuestReq->SCSIIO.u8TargetID < pThis->cDeviceStates)
2238 && (pGuestReq->SCSIIO.u8Bus == 0)))
2239 {
2240 PLSILOGICDEVICE pTgtDev = &pThisCC->paDeviceStates[pGuestReq->SCSIIO.u8TargetID];
2241
2242 if (pTgtDev->pDrvBase)
2243 {
2244 /* Allocate and prepare a new request. */
2245 PDMMEDIAEXIOREQ hIoReq;
2246 PLSILOGICREQ pLsiReq = NULL;
2247 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pLsiReq,
2248 pGuestReq->SCSIIO.u32MessageContext,
2249 PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
2250 if (RT_SUCCESS(rc))
2251 {
2252 pLsiReq->hIoReq = hIoReq;
2253 pLsiReq->pTargetDevice = pTgtDev;
2254 pLsiReq->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr;
2255 pLsiReq->fBIOS = false;
2256 pLsiReq->GCPhysSgStart = GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest);
2257 pLsiReq->cChainOffset = pGuestReq->SCSIIO.u8ChainOffset;
2258 if (pLsiReq->cChainOffset)
2259 pLsiReq->cChainOffset = pLsiReq->cChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest);
2260 memcpy(&pLsiReq->GuestRequest, pGuestReq, sizeof(MptRequestUnion));
2261 RT_BZERO(&pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer));
2262
2263 PDMMEDIAEXIOREQSCSITXDIR enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN;
2264 uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pLsiReq->GuestRequest.SCSIIO.u32Control);
2265
2266 /*
2267 * Keep the direction to unknown if there is a mismatch between the data length
2268 * and the transfer direction bit.
2269 * The Solaris 9 driver is buggy and sets it to none for INQUIRY requests.
2270 */
2271 if ( uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE
2272 && pLsiReq->GuestRequest.SCSIIO.u32DataLength == 0)
2273 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_NONE;
2274 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
2275 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE;
2276 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ)
2277 enmXferDir = PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
2278
2279 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
2280 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pLsiReq->hIoReq, pLsiReq->GuestRequest.SCSIIO.au8LUN[1],
2281 &pLsiReq->GuestRequest.SCSIIO.au8CDB[0], pLsiReq->GuestRequest.SCSIIO.u8CDBLength,
2282 enmXferDir, NULL, pLsiReq->GuestRequest.SCSIIO.u32DataLength,
2283 &pLsiReq->abSenseBuffer[0], sizeof(pLsiReq->abSenseBuffer), NULL,
2284 &pLsiReq->u8ScsiSts, 30 * RT_MS_1SEC);
2285 if (rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
2286 lsilogicR3ReqComplete(pDevIns, pThis, pThisCC, pLsiReq, rc);
2287
2288 return VINF_SUCCESS;
2289 }
2290 else
2291 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
2292 }
2293 else
2294 {
2295 /* Device is not present report SCSI selection timeout. */
2296 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
2297 }
2298 }
2299 else
2300 {
2301 /* Report out of bounds target ID or bus. */
2302 if (pGuestReq->SCSIIO.u8Bus != 0)
2303 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS;
2304 else
2305 IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID;
2306 }
2307
2308 static int g_cLogged = 0;
2309
2310 if (g_cLogged++ < MAX_REL_LOG_ERRORS)
2311 {
2312 LogRel(("LsiLogic#%d: %d/%d (Bus/Target) doesn't exist\n", pDevIns->iInstance,
2313 pGuestReq->SCSIIO.u8TargetID, pGuestReq->SCSIIO.u8Bus));
2314 /* Log the CDB too */
2315 LogRel(("LsiLogic#%d: Guest issued CDB {%#x",
2316 pDevIns->iInstance, pGuestReq->SCSIIO.au8CDB[0]));
2317 for (unsigned i = 1; i < pGuestReq->SCSIIO.u8CDBLength; i++)
2318 LogRel((", %#x", pGuestReq->SCSIIO.au8CDB[i]));
2319 LogRel(("}\n"));
2320 }
2321
2322 /* The rest is equal to both errors. */
2323 IOCReply.SCSIIOError.u8TargetID = pGuestReq->SCSIIO.u8TargetID;
2324 IOCReply.SCSIIOError.u8Bus = pGuestReq->SCSIIO.u8Bus;
2325 IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4;
2326 IOCReply.SCSIIOError.u8Function = pGuestReq->SCSIIO.u8Function;
2327 IOCReply.SCSIIOError.u8CDBLength = pGuestReq->SCSIIO.u8CDBLength;
2328 IOCReply.SCSIIOError.u8SenseBufferLength = pGuestReq->SCSIIO.u8SenseBufferLength;
2329 IOCReply.SCSIIOError.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 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysAddrPageBuffer, pbPageData, RT_MIN(cbBuffer, cbPage));
3268 }
3269 break;
3270 }
3271 default:
3272 AssertMsgFailed(("todo\n"));
3273 }
3274
3275 return VINF_SUCCESS;
3276}
3277
3278/**
3279 * Initializes the configuration pages for the SPI SCSI controller.
3280 *
3281 * @returns nothing
3282 * @param pThis Pointer to the shared LsiLogic device state.
3283 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3284 */
3285static void lsilogicR3InitializeConfigurationPagesSpi(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3286{
3287 PMptConfigurationPagesSpi pPages = &pThisCC->pConfigurationPages->u.SpiPages;
3288
3289 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI, ("Controller is not the SPI SCSI one\n"));
3290 LogFlowFunc(("pThis=%#p\n", pThis));
3291 RT_NOREF(pThis);
3292
3293 /* Clear everything first. */
3294 memset(pPages, 0, sizeof(MptConfigurationPagesSpi));
3295
3296 for (unsigned i = 0; i < RT_ELEMENTS(pPages->aPortPages); i++)
3297 {
3298 /* SCSI-SPI port page 0. */
3299 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3300 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3301 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageNumber = 0;
3302 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort0) / 4;
3303 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fInformationUnitTransfersCapable = true;
3304 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fDTCapable = true;
3305 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fQASCapable = true;
3306 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MinimumSynchronousTransferPeriod = 0;
3307 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u8MaximumSynchronousOffset = 0xff;
3308 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fWide = true;
3309 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.fAIPCapable = true;
3310 pPages->aPortPages[i].SCSISPIPortPage0.u.fields.u2SignalingType = 0x3; /* Single Ended. */
3311
3312 /* SCSI-SPI port page 1. */
3313 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3314 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3315 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageNumber = 1;
3316 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort1) / 4;
3317 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u8SCSIID = 7;
3318 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u16PortResponseIDsBitmask = (1 << 7);
3319 pPages->aPortPages[i].SCSISPIPortPage1.u.fields.u32OnBusTimerValue = 0;
3320
3321 /* SCSI-SPI port page 2. */
3322 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3323 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_PORT;
3324 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageNumber = 2;
3325 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIPort2) / 4;
3326 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u4HostSCSIID = 7;
3327 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.u2InitializeHBA = 0x3;
3328 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.fTerminationDisabled = true;
3329 for (unsigned iDevice = 0; iDevice < RT_ELEMENTS(pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings); iDevice++)
3330 {
3331 pPages->aPortPages[i].SCSISPIPortPage2.u.fields.aDeviceSettings[iDevice].fBootChoice = true;
3332 }
3333 /* Everything else 0 for now. */
3334 }
3335
3336 for (unsigned uBusCurr = 0; uBusCurr < RT_ELEMENTS(pPages->aBuses); uBusCurr++)
3337 {
3338 for (unsigned uDeviceCurr = 0; uDeviceCurr < RT_ELEMENTS(pPages->aBuses[uBusCurr].aDevicePages); uDeviceCurr++)
3339 {
3340 /* SCSI-SPI device page 0. */
3341 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3342 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3343 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageNumber = 0;
3344 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage0.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice0) / 4;
3345 /* Everything else 0 for now. */
3346
3347 /* SCSI-SPI device page 1. */
3348 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3349 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3350 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageNumber = 1;
3351 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage1.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice1) / 4;
3352 /* Everything else 0 for now. */
3353
3354 /* SCSI-SPI device page 2. */
3355 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE
3356 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3357 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageNumber = 2;
3358 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage2.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice2) / 4;
3359 /* Everything else 0 for now. */
3360
3361 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3362 | MPT_CONFIGURATION_PAGE_TYPE_SCSI_SPI_DEVICE;
3363 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageNumber = 3;
3364 pPages->aBuses[uBusCurr].aDevicePages[uDeviceCurr].SCSISPIDevicePage3.u.fields.Header.u8PageLength = sizeof(MptConfigurationPageSCSISPIDevice3) / 4;
3365 /* Everything else 0 for now. */
3366 }
3367 }
3368}
3369
3370/**
3371 * Generates a handle.
3372 *
3373 * @returns the handle.
3374 * @param pThis Pointer to the shared LsiLogic device state.
3375 */
3376DECLINLINE(uint16_t) lsilogicGetHandle(PLSILOGICSCSI pThis)
3377{
3378 uint16_t u16Handle = pThis->u16NextHandle++;
3379 return u16Handle;
3380}
3381
3382/**
3383 * Generates a SAS address (WWID)
3384 *
3385 * @returns nothing.
3386 * @param pSASAddress Pointer to an unitialised SAS address.
3387 * @param iId iId which will go into the address.
3388 *
3389 * @todo Generate better SAS addresses. (Request a block from SUN probably)
3390 */
3391void lsilogicSASAddressGenerate(PSASADDRESS pSASAddress, unsigned iId)
3392{
3393 pSASAddress->u8Address[0] = (0x5 << 5);
3394 pSASAddress->u8Address[1] = 0x01;
3395 pSASAddress->u8Address[2] = 0x02;
3396 pSASAddress->u8Address[3] = 0x03;
3397 pSASAddress->u8Address[4] = 0x04;
3398 pSASAddress->u8Address[5] = 0x05;
3399 pSASAddress->u8Address[6] = 0x06;
3400 pSASAddress->u8Address[7] = iId;
3401}
3402
3403/**
3404 * Initializes the configuration pages for the SAS SCSI controller.
3405 *
3406 * @returns nothing
3407 * @param pThis Pointer to the shared LsiLogic device state.
3408 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3409 */
3410static void lsilogicR3InitializeConfigurationPagesSas(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3411{
3412 PMptConfigurationPagesSas pPages = &pThisCC->pConfigurationPages->u.SasPages;
3413
3414 AssertMsg(pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS, ("Controller is not the SAS SCSI one\n"));
3415
3416 LogFlowFunc(("pThis=%#p\n", pThis));
3417
3418 /* Manufacturing Page 7 - Connector settings. */
3419 pPages->cbManufacturingPage7 = LSILOGICSCSI_MANUFACTURING7_GET_SIZE(pThis->cPorts);
3420 PMptConfigurationPageManufacturing7 pManufacturingPage7 = (PMptConfigurationPageManufacturing7)RTMemAllocZ(pPages->cbManufacturingPage7);
3421 AssertPtr(pManufacturingPage7);
3422 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(pManufacturingPage7,
3423 0, 7,
3424 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3425 /* Set size manually. */
3426 if (pPages->cbManufacturingPage7 / 4 > 255)
3427 pManufacturingPage7->u.fields.Header.u8PageLength = 255;
3428 else
3429 pManufacturingPage7->u.fields.Header.u8PageLength = pPages->cbManufacturingPage7 / 4;
3430 pManufacturingPage7->u.fields.u8NumPhys = pThis->cPorts;
3431 pPages->pManufacturingPage7 = pManufacturingPage7;
3432
3433 /* SAS I/O unit page 0 - Port specific information. */
3434 pPages->cbSASIOUnitPage0 = LSILOGICSCSI_SASIOUNIT0_GET_SIZE(pThis->cPorts);
3435 PMptConfigurationPageSASIOUnit0 pSASPage0 = (PMptConfigurationPageSASIOUnit0)RTMemAllocZ(pPages->cbSASIOUnitPage0);
3436 AssertPtr(pSASPage0);
3437
3438 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage0, pPages->cbSASIOUnitPage0,
3439 0, MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY,
3440 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3441 pSASPage0->u.fields.u8NumPhys = pThis->cPorts;
3442 pPages->pSASIOUnitPage0 = pSASPage0;
3443
3444 /* SAS I/O unit page 1 - Port specific settings. */
3445 pPages->cbSASIOUnitPage1 = LSILOGICSCSI_SASIOUNIT1_GET_SIZE(pThis->cPorts);
3446 PMptConfigurationPageSASIOUnit1 pSASPage1 = (PMptConfigurationPageSASIOUnit1)RTMemAllocZ(pPages->cbSASIOUnitPage1);
3447 AssertPtr(pSASPage1);
3448
3449 MPT_CONFIG_EXTENDED_PAGE_HEADER_INIT(pSASPage1, pPages->cbSASIOUnitPage1,
3450 1, MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE,
3451 MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT);
3452 pSASPage1->u.fields.u8NumPhys = pSASPage0->u.fields.u8NumPhys;
3453 pSASPage1->u.fields.u16ControlFlags = 0;
3454 pSASPage1->u.fields.u16AdditionalControlFlags = 0;
3455 pPages->pSASIOUnitPage1 = pSASPage1;
3456
3457 /* SAS I/O unit page 2 - Port specific information. */
3458 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3459 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3460 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8PageNumber = 2;
3461 pPages->SASIOUnitPage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3462 pPages->SASIOUnitPage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit2) / 4;
3463
3464 /* SAS I/O unit page 3 - Port specific information. */
3465 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3466 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3467 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8PageNumber = 3;
3468 pPages->SASIOUnitPage3.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASIOUNIT;
3469 pPages->SASIOUnitPage3.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASIOUnit3) / 4;
3470
3471 pPages->cPHYs = pThis->cPorts;
3472 pPages->paPHYs = (PMptPHY)RTMemAllocZ(pPages->cPHYs * sizeof(MptPHY));
3473 AssertPtr(pPages->paPHYs);
3474
3475 /* Initialize the PHY configuration */
3476 for (unsigned i = 0; i < pThis->cPorts; i++)
3477 {
3478 PMptPHY pPHYPages = &pPages->paPHYs[i];
3479 uint16_t u16ControllerHandle = lsilogicGetHandle(pThis);
3480
3481 pManufacturingPage7->u.fields.aPHY[i].u8Location = LSILOGICSCSI_MANUFACTURING7_LOCATION_AUTO;
3482
3483 pSASPage0->u.fields.aPHY[i].u8Port = i;
3484 pSASPage0->u.fields.aPHY[i].u8PortFlags = 0;
3485 pSASPage0->u.fields.aPHY[i].u8PhyFlags = 0;
3486 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_FAILED;
3487 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3488 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16ControllerHandle;
3489 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = 0; /* No device attached. */
3490 pSASPage0->u.fields.aPHY[i].u32DiscoveryStatus = 0; /* No errors */
3491
3492 pSASPage1->u.fields.aPHY[i].u8Port = i;
3493 pSASPage1->u.fields.aPHY[i].u8PortFlags = 0;
3494 pSASPage1->u.fields.aPHY[i].u8PhyFlags = 0;
3495 pSASPage1->u.fields.aPHY[i].u8MaxMinLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3496 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3497 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_NO);
3498
3499 /* SAS PHY page 0. */
3500 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3501 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3502 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8PageNumber = 0;
3503 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3504 pPHYPages->SASPHYPage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY0) / 4;
3505 pPHYPages->SASPHYPage0.u.fields.u8AttachedPhyIdentifier = i;
3506 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_NO);
3507 pPHYPages->SASPHYPage0.u.fields.u8ProgrammedLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3508 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3509 pPHYPages->SASPHYPage0.u.fields.u8HwLinkRate = LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MIN_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_15GB)
3510 | LSILOGICSCSI_SASIOUNIT1_LINK_RATE_MAX_SET(LSILOGICSCSI_SASIOUNIT1_LINK_RATE_30GB);
3511
3512 /* SAS PHY page 1. */
3513 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3514 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3515 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8PageNumber = 1;
3516 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASPHYS;
3517 pPHYPages->SASPHYPage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASPHY1) / 4;
3518
3519 /* Settings for present devices. */
3520 if (pThisCC->paDeviceStates[i].pDrvBase)
3521 {
3522 uint16_t u16DeviceHandle = lsilogicGetHandle(pThis);
3523 SASADDRESS SASAddress;
3524 PMptSASDevice pSASDevice = (PMptSASDevice)RTMemAllocZ(sizeof(MptSASDevice));
3525 AssertPtr(pSASDevice);
3526
3527 memset(&SASAddress, 0, sizeof(SASADDRESS));
3528 lsilogicSASAddressGenerate(&SASAddress, i);
3529
3530 pSASPage0->u.fields.aPHY[i].u8NegotiatedLinkRate = LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_SET(LSILOGICSCSI_SASIOUNIT0_NEGOTIATED_RATE_30GB);
3531 pSASPage0->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3532 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3533 pSASPage0->u.fields.aPHY[i].u16AttachedDevHandle = u16DeviceHandle;
3534 pSASPage1->u.fields.aPHY[i].u32ControllerPhyDeviceInfo = LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_SET(LSILOGICSCSI_SASIOUNIT0_DEVICE_TYPE_END)
3535 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3536 pSASPage0->u.fields.aPHY[i].u16ControllerDevHandle = u16DeviceHandle;
3537
3538 pPHYPages->SASPHYPage0.u.fields.u32AttachedDeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END);
3539 pPHYPages->SASPHYPage0.u.fields.SASAddress = SASAddress;
3540 pPHYPages->SASPHYPage0.u.fields.u16OwnerDevHandle = u16DeviceHandle;
3541 pPHYPages->SASPHYPage0.u.fields.u16AttachedDevHandle = u16DeviceHandle;
3542
3543 /* SAS device page 0. */
3544 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3545 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3546 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8PageNumber = 0;
3547 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3548 pSASDevice->SASDevicePage0.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice0) / 4;
3549 pSASDevice->SASDevicePage0.u.fields.SASAddress = SASAddress;
3550 pSASDevice->SASDevicePage0.u.fields.u16ParentDevHandle = u16ControllerHandle;
3551 pSASDevice->SASDevicePage0.u.fields.u8PhyNum = i;
3552 pSASDevice->SASDevicePage0.u.fields.u8AccessStatus = LSILOGICSCSI_SASDEVICE0_STATUS_NO_ERRORS;
3553 pSASDevice->SASDevicePage0.u.fields.u16DevHandle = u16DeviceHandle;
3554 pSASDevice->SASDevicePage0.u.fields.u8TargetID = i;
3555 pSASDevice->SASDevicePage0.u.fields.u8Bus = 0;
3556 pSASDevice->SASDevicePage0.u.fields.u32DeviceInfo = LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_SET(LSILOGICSCSI_SASPHY0_DEV_INFO_DEVICE_TYPE_END)
3557 | LSILOGICSCSI_SASIOUNIT0_DEVICE_SSP_TARGET;
3558 pSASDevice->SASDevicePage0.u.fields.u16Flags = LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_PRESENT
3559 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPED_TO_BUS_AND_TARGET_ID
3560 | LSILOGICSCSI_SASDEVICE0_FLAGS_DEVICE_MAPPING_PERSISTENT;
3561 pSASDevice->SASDevicePage0.u.fields.u8PhysicalPort = i;
3562
3563 /* SAS device page 1. */
3564 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3565 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3566 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8PageNumber = 1;
3567 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3568 pSASDevice->SASDevicePage1.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice1) / 4;
3569 pSASDevice->SASDevicePage1.u.fields.SASAddress = SASAddress;
3570 pSASDevice->SASDevicePage1.u.fields.u16DevHandle = u16DeviceHandle;
3571 pSASDevice->SASDevicePage1.u.fields.u8TargetID = i;
3572 pSASDevice->SASDevicePage1.u.fields.u8Bus = 0;
3573
3574 /* SAS device page 2. */
3575 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageType = MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY
3576 | MPT_CONFIGURATION_PAGE_TYPE_EXTENDED;
3577 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8PageNumber = 2;
3578 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u8ExtPageType = MPT_CONFIGURATION_PAGE_TYPE_EXTENDED_SASDEVICE;
3579 pSASDevice->SASDevicePage2.u.fields.ExtHeader.u16ExtPageLength = sizeof(MptConfigurationPageSASDevice2) / 4;
3580 pSASDevice->SASDevicePage2.u.fields.SASAddress = SASAddress;
3581
3582 /* Link into device list. */
3583 if (!pPages->cDevices)
3584 {
3585 pPages->pSASDeviceHead = pSASDevice;
3586 pPages->pSASDeviceTail = pSASDevice;
3587 pPages->cDevices = 1;
3588 }
3589 else
3590 {
3591 pSASDevice->pPrev = pPages->pSASDeviceTail;
3592 pPages->pSASDeviceTail->pNext = pSASDevice;
3593 pPages->pSASDeviceTail = pSASDevice;
3594 pPages->cDevices++;
3595 }
3596 }
3597 }
3598}
3599
3600/**
3601 * Initializes the configuration pages.
3602 *
3603 * @returns nothing
3604 * @param pDevIns The device instance.
3605 * @param pThis Pointer to the shared LsiLogic device state.
3606 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3607 */
3608static void lsilogicR3InitializeConfigurationPages(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3609{
3610 /* Initialize the common pages. */
3611 PMptConfigurationPagesSupported pPages = (PMptConfigurationPagesSupported)RTMemAllocZ(sizeof(MptConfigurationPagesSupported));
3612 /** @todo r=bird: Missing alloc failure check. Why do we allocate this
3613 * structure? It's fixed size... */
3614
3615 pThisCC->pConfigurationPages = pPages;
3616
3617 LogFlowFunc(("pThis=%#p\n", pThis));
3618
3619 /* Clear everything first. */
3620 memset(pPages, 0, sizeof(MptConfigurationPagesSupported));
3621
3622 /* Manufacturing Page 0. */
3623 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage0,
3624 MptConfigurationPageManufacturing0, 0,
3625 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3626 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipName, "VBox MPT Fusion", 16);
3627 strncpy((char *)pPages->ManufacturingPage0.u.fields.abChipRevision, "1.0", 8);
3628 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardName, "VBox MPT Fusion", 16);
3629 strncpy((char *)pPages->ManufacturingPage0.u.fields.abBoardAssembly, "SUN", 8);
3630 memcpy(pPages->ManufacturingPage0.u.fields.abBoardTracerNumber, "CAFECAFECAFECAFE", 16);
3631
3632 /* Manufacturing Page 1 - I don't know what this contains so we leave it 0 for now. */
3633 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage1,
3634 MptConfigurationPageManufacturing1, 1,
3635 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3636
3637 /* Manufacturing Page 2. */
3638 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage2,
3639 MptConfigurationPageManufacturing2, 2,
3640 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3641
3642 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3643 {
3644 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3645 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3646 }
3647 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3648 {
3649 pPages->ManufacturingPage2.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3650 pPages->ManufacturingPage2.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3651 }
3652
3653 /* Manufacturing Page 3. */
3654 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage3,
3655 MptConfigurationPageManufacturing3, 3,
3656 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3657
3658 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3659 {
3660 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3661 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3662 }
3663 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3664 {
3665 pPages->ManufacturingPage3.u.fields.u16PCIDeviceID = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3666 pPages->ManufacturingPage3.u.fields.u8PCIRevisionID = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3667 }
3668
3669 /* Manufacturing Page 4 - I don't know what this contains so we leave it 0 for now. */
3670 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage4,
3671 MptConfigurationPageManufacturing4, 4,
3672 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3673
3674 /* Manufacturing Page 5 - WWID settings. */
3675 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage5,
3676 MptConfigurationPageManufacturing5, 5,
3677 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT_READONLY);
3678
3679 /* Manufacturing Page 6 - Product specific settings. */
3680 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage6,
3681 MptConfigurationPageManufacturing6, 6,
3682 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3683
3684 /* Manufacturing Page 8 - Product specific settings. */
3685 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage8,
3686 MptConfigurationPageManufacturing8, 8,
3687 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3688
3689 /* Manufacturing Page 9 - Product specific settings. */
3690 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage9,
3691 MptConfigurationPageManufacturing9, 9,
3692 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3693
3694 /* Manufacturing Page 10 - Product specific settings. */
3695 MPT_CONFIG_PAGE_HEADER_INIT_MANUFACTURING(&pPages->ManufacturingPage10,
3696 MptConfigurationPageManufacturing10, 10,
3697 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3698
3699 /* I/O Unit page 0. */
3700 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage0,
3701 MptConfigurationPageIOUnit0, 0,
3702 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3703 pPages->IOUnitPage0.u.fields.u64UniqueIdentifier = 0xcafe;
3704
3705 /* I/O Unit page 1. */
3706 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage1,
3707 MptConfigurationPageIOUnit1, 1,
3708 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3709 pPages->IOUnitPage1.u.fields.fSingleFunction = true;
3710 pPages->IOUnitPage1.u.fields.fAllPathsMapped = false;
3711 pPages->IOUnitPage1.u.fields.fIntegratedRAIDDisabled = true;
3712 pPages->IOUnitPage1.u.fields.f32BitAccessForced = false;
3713
3714 /* I/O Unit page 2. */
3715 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage2,
3716 MptConfigurationPageIOUnit2, 2,
3717 MPT_CONFIGURATION_PAGE_ATTRIBUTE_PERSISTENT);
3718 pPages->IOUnitPage2.u.fields.fPauseOnError = false;
3719 pPages->IOUnitPage2.u.fields.fVerboseModeEnabled = false;
3720 pPages->IOUnitPage2.u.fields.fDisableColorVideo = false;
3721 pPages->IOUnitPage2.u.fields.fNotHookInt40h = false;
3722 pPages->IOUnitPage2.u.fields.u32BIOSVersion = 0xcafecafe;
3723 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEnabled = true;
3724 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].fAdapterEmbedded = true;
3725 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIBusNumber = 0;
3726 pPages->IOUnitPage2.u.fields.aAdapterOrder[0].u8PCIDevFn = pDevIns->apPciDevs[0]->uDevFn;
3727
3728 /* I/O Unit page 3. */
3729 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage3,
3730 MptConfigurationPageIOUnit3, 3,
3731 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3732 pPages->IOUnitPage3.u.fields.u8GPIOCount = 0;
3733
3734 /* I/O Unit page 4. */
3735 MPT_CONFIG_PAGE_HEADER_INIT_IO_UNIT(&pPages->IOUnitPage4,
3736 MptConfigurationPageIOUnit4, 4,
3737 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3738
3739 /* IOC page 0. */
3740 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage0,
3741 MptConfigurationPageIOC0, 0,
3742 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3743 pPages->IOCPage0.u.fields.u32TotalNVStore = 0;
3744 pPages->IOCPage0.u.fields.u32FreeNVStore = 0;
3745
3746 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3747 {
3748 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3749 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SPI_DEVICE_ID;
3750 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SPI_REVISION_ID;
3751 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SPI_CLASS_CODE;
3752 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID;
3753 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID;
3754 }
3755 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3756 {
3757 pPages->IOCPage0.u.fields.u16VendorId = LSILOGICSCSI_PCI_VENDOR_ID;
3758 pPages->IOCPage0.u.fields.u16DeviceId = LSILOGICSCSI_PCI_SAS_DEVICE_ID;
3759 pPages->IOCPage0.u.fields.u8RevisionId = LSILOGICSCSI_PCI_SAS_REVISION_ID;
3760 pPages->IOCPage0.u.fields.u32ClassCode = LSILOGICSCSI_PCI_SAS_CLASS_CODE;
3761 pPages->IOCPage0.u.fields.u16SubsystemVendorId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID;
3762 pPages->IOCPage0.u.fields.u16SubsystemId = LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID;
3763 }
3764
3765 /* IOC page 1. */
3766 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage1,
3767 MptConfigurationPageIOC1, 1,
3768 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3769 pPages->IOCPage1.u.fields.fReplyCoalescingEnabled = false;
3770 pPages->IOCPage1.u.fields.u32CoalescingTimeout = 0;
3771 pPages->IOCPage1.u.fields.u8CoalescingDepth = 0;
3772
3773 /* IOC page 2. */
3774 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage2,
3775 MptConfigurationPageIOC2, 2,
3776 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3777 /* Everything else here is 0. */
3778
3779 /* IOC page 3. */
3780 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage3,
3781 MptConfigurationPageIOC3, 3,
3782 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3783 /* Everything else here is 0. */
3784
3785 /* IOC page 4. */
3786 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage4,
3787 MptConfigurationPageIOC4, 4,
3788 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3789 /* Everything else here is 0. */
3790
3791 /* IOC page 6. */
3792 MPT_CONFIG_PAGE_HEADER_INIT_IOC(&pPages->IOCPage6,
3793 MptConfigurationPageIOC6, 6,
3794 MPT_CONFIGURATION_PAGE_ATTRIBUTE_READONLY);
3795 /* Everything else here is 0. */
3796
3797 /* BIOS page 1. */
3798 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage1,
3799 MptConfigurationPageBIOS1, 1,
3800 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3801
3802 /* BIOS page 2. */
3803 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage2,
3804 MptConfigurationPageBIOS2, 2,
3805 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3806
3807 /* BIOS page 4. */
3808 MPT_CONFIG_PAGE_HEADER_INIT_BIOS(&pPages->BIOSPage4,
3809 MptConfigurationPageBIOS4, 4,
3810 MPT_CONFIGURATION_PAGE_ATTRIBUTE_CHANGEABLE);
3811
3812 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3813 lsilogicR3InitializeConfigurationPagesSpi(pThis, pThisCC);
3814 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3815 lsilogicR3InitializeConfigurationPagesSas(pThis, pThisCC);
3816 else
3817 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
3818}
3819
3820/**
3821 * Sets the emulated controller type from a given string.
3822 *
3823 * @returns VBox status code.
3824 *
3825 * @param pThis Pointer to the shared LsiLogic device state.
3826 * @param pcszCtrlType The string to use.
3827 */
3828static int lsilogicR3GetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType)
3829{
3830 int rc = VERR_INVALID_PARAMETER;
3831
3832 if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME))
3833 {
3834 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SPI;
3835 rc = VINF_SUCCESS;
3836 }
3837 else if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SAS_CTRLNAME))
3838 {
3839 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SAS;
3840 rc = VINF_SUCCESS;
3841 }
3842
3843 return rc;
3844}
3845
3846/**
3847 * @callback_method_impl{FNIOMIOPORTIN, Legacy ISA port.}
3848 */
3849static DECLCALLBACK(VBOXSTRICTRC)
3850lsilogicR3IsaIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3851{
3852 RT_NOREF(pvUser, cb);
3853 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3854
3855 ASSERT_GUEST(cb == 1);
3856
3857 int rc = vboxscsiReadRegister(&pThisCC->VBoxSCSI, offPort, pu32);
3858 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register read status: %Rrc\n", rc));
3859
3860 Log2(("%s: pu32=%p:{%.*Rhxs} offPort=%d rc=%Rrc\n", __FUNCTION__, pu32, 1, pu32, offPort, rc));
3861
3862 return rc;
3863}
3864
3865/**
3866 * Prepares a request from the BIOS.
3867 *
3868 * @returns VBox status code.
3869 * @param pThis Pointer to the shared LsiLogic device state.
3870 * @param pThisCC Pointer to the ring-3 LsiLogic device state.
3871 */
3872static int lsilogicR3PrepareBiosScsiRequest(PLSILOGICSCSI pThis, PLSILOGICSCSICC pThisCC)
3873{
3874 int rc;
3875 uint32_t uTargetDevice;
3876 uint32_t uLun;
3877 uint8_t *pbCdb;
3878 size_t cbCdb;
3879 size_t cbBuf;
3880
3881 rc = vboxscsiSetupRequest(&pThisCC->VBoxSCSI, &uLun, &pbCdb, &cbCdb, &cbBuf, &uTargetDevice);
3882 AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc);
3883
3884 if ( uTargetDevice < pThis->cDeviceStates
3885 && pThisCC->paDeviceStates[uTargetDevice].pDrvBase)
3886 {
3887 PLSILOGICDEVICE pTgtDev = &pThisCC->paDeviceStates[uTargetDevice];
3888 PDMMEDIAEXIOREQ hIoReq;
3889 PLSILOGICREQ pReq;
3890
3891 rc = pTgtDev->pDrvMediaEx->pfnIoReqAlloc(pTgtDev->pDrvMediaEx, &hIoReq, (void **)&pReq,
3892 0, PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR);
3893 AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc);
3894
3895 pReq->fBIOS = true;
3896 pReq->hIoReq = hIoReq;
3897 pReq->pTargetDevice = pTgtDev;
3898
3899 ASMAtomicIncU32(&pTgtDev->cOutstandingRequests);
3900
3901 rc = pTgtDev->pDrvMediaEx->pfnIoReqSendScsiCmd(pTgtDev->pDrvMediaEx, pReq->hIoReq, uLun,
3902 pbCdb, cbCdb, PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, NULL,
3903 cbBuf, NULL, 0, NULL, &pReq->u8ScsiSts, 30 * RT_MS_1SEC);
3904 if (rc == VINF_SUCCESS || rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3905 {
3906 uint8_t u8ScsiSts = pReq->u8ScsiSts;
3907 pTgtDev->pDrvMediaEx->pfnIoReqFree(pTgtDev->pDrvMediaEx, pReq->hIoReq);
3908 rc = vboxscsiRequestFinished(&pThisCC->VBoxSCSI, u8ScsiSts);
3909 }
3910 else if (rc == VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
3911 rc = VINF_SUCCESS;
3912
3913 return rc;
3914 }
3915
3916 /* Device is not present. */
3917 AssertMsg(pbCdb[0] == SCSI_INQUIRY,
3918 ("Device is not present but command is not inquiry\n"));
3919
3920 SCSIINQUIRYDATA ScsiInquiryData;
3921
3922 memset(&ScsiInquiryData, 0, sizeof(SCSIINQUIRYDATA));
3923 ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
3924 ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
3925
3926 memcpy(pThisCC->VBoxSCSI.pbBuf, &ScsiInquiryData, 5);
3927
3928 rc = vboxscsiRequestFinished(&pThisCC->VBoxSCSI, SCSI_STATUS_OK);
3929 AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc);
3930
3931 return rc;
3932}
3933
3934/**
3935 * @callback_method_impl{FNIOMIOPORTNEWOUT, Legacy ISA port.}
3936 */
3937static DECLCALLBACK(VBOXSTRICTRC)
3938lsilogicR3IsaIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3939{
3940 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3941 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3942 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, offPort));
3943 RT_NOREF(pvUser, cb);
3944
3945 ASSERT_GUEST(cb == 1);
3946
3947 /*
3948 * If there is already a request form the BIOS pending ignore this write
3949 * because it should not happen.
3950 */
3951 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
3952 return VINF_SUCCESS;
3953
3954 int rc = vboxscsiWriteRegister(&pThisCC->VBoxSCSI, offPort, (uint8_t)u32);
3955 if (rc == VERR_MORE_DATA)
3956 {
3957 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3958 /* Notify the worker thread that there are pending requests. */
3959 LogFlowFunc(("Signal event semaphore\n"));
3960 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
3961 AssertRC(rc);
3962 }
3963 else
3964 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register write status: %Rrc\n", rc));
3965
3966 return VINF_SUCCESS;
3967}
3968
3969/**
3970 * @callback_method_impl{FNIOMIOPORTNEWOUTSTRING,
3971 * Port I/O Handler for primary port range OUT string operations.}
3972 */
3973static DECLCALLBACK(VBOXSTRICTRC) lsilogicR3IsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort,
3974 uint8_t const *pbSrc, uint32_t *pcTransfers, unsigned cb)
3975{
3976 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
3977 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
3978 Log2(("#%d %s: pvUser=%#p cb=%d offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, offPort));
3979 RT_NOREF(pvUser);
3980
3981 int rc = vboxscsiWriteString(pDevIns, &pThisCC->VBoxSCSI, offPort, pbSrc, pcTransfers, cb);
3982 if (rc == VERR_MORE_DATA)
3983 {
3984 ASMAtomicXchgBool(&pThis->fBiosReqPending, true);
3985 /* Notify the worker thread that there are pending requests. */
3986 LogFlowFunc(("Signal event semaphore\n"));
3987 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
3988 AssertRC(rc);
3989 }
3990 else
3991 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register write status: %Rrc\n", rc));
3992
3993 return VINF_SUCCESS;
3994}
3995
3996/**
3997 * @callback_method_impl{FNIOMIOPORTINSTRING,
3998 * Port I/O Handler for primary port range IN string operations.}
3999 */
4000static DECLCALLBACK(VBOXSTRICTRC) lsilogicR3IsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort,
4001 uint8_t *pbDst, uint32_t *pcTransfers, unsigned cb)
4002{
4003 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4004 LogFlowFunc(("#%d %s: pvUser=%#p cb=%d offPort=%#x\n", pDevIns->iInstance, __FUNCTION__, pvUser, cb, offPort));
4005 RT_NOREF(pvUser);
4006
4007 int rc = vboxscsiReadString(pDevIns, &pThisCC->VBoxSCSI, offPort, pbDst, pcTransfers, cb);
4008 AssertMsg(rc == VINF_SUCCESS, ("Unexpected BIOS register read status: %Rrc\n", rc));
4009 return rc;
4010}
4011
4012/**
4013 * @callback_method_impl{PFNDBGFHANDLERDEV}
4014 */
4015static DECLCALLBACK(void) lsilogicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4016{
4017 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4018 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4019
4020 /*
4021 * Parse args.
4022 */
4023 bool const fVerbose = pszArgs && strstr(pszArgs, "verbose") != NULL;
4024
4025 /*
4026 * Show info.
4027 */
4028 pHlp->pfnPrintf(pHlp,
4029 "%s#%d: port=%04x mmio=%RGp max-devices=%u GC=%RTbool R0=%RTbool\n",
4030 pDevIns->pReg->szName, pDevIns->iInstance,
4031 PDMDevHlpIoPortGetMappingAddress(pDevIns, pThis->hIoPortsReg),
4032 PDMDevHlpMmioGetMappingAddress(pDevIns, pThis->hMmioReg),
4033 pThis->cDeviceStates, pDevIns->fRCEnabled, pDevIns->fR0Enabled);
4034
4035 /*
4036 * Show general state.
4037 */
4038 pHlp->pfnPrintf(pHlp, "enmState=%u\n", pThis->enmState);
4039 pHlp->pfnPrintf(pHlp, "enmWhoInit=%u\n", pThis->enmWhoInit);
4040 pHlp->pfnPrintf(pHlp, "enmDoorbellState=%d\n", pThis->enmDoorbellState);
4041 pHlp->pfnPrintf(pHlp, "fDiagnosticEnabled=%RTbool\n", pThis->fDiagnosticEnabled);
4042 pHlp->pfnPrintf(pHlp, "fNotificationSent=%RTbool\n", pThis->fNotificationSent);
4043 pHlp->pfnPrintf(pHlp, "fEventNotificationEnabled=%RTbool\n", pThis->fEventNotificationEnabled);
4044 pHlp->pfnPrintf(pHlp, "uInterruptMask=%#x\n", pThis->uInterruptMask);
4045 pHlp->pfnPrintf(pHlp, "uInterruptStatus=%#x\n", pThis->uInterruptStatus);
4046 pHlp->pfnPrintf(pHlp, "u16IOCFaultCode=%#06x\n", pThis->u16IOCFaultCode);
4047 pHlp->pfnPrintf(pHlp, "u32HostMFAHighAddr=%#x\n", pThis->u32HostMFAHighAddr);
4048 pHlp->pfnPrintf(pHlp, "u32SenseBufferHighAddr=%#x\n", pThis->u32SenseBufferHighAddr);
4049 pHlp->pfnPrintf(pHlp, "cMaxDevices=%u\n", pThis->cMaxDevices);
4050 pHlp->pfnPrintf(pHlp, "cMaxBuses=%u\n", pThis->cMaxBuses);
4051 pHlp->pfnPrintf(pHlp, "cbReplyFrame=%u\n", pThis->cbReplyFrame);
4052 pHlp->pfnPrintf(pHlp, "cReplyQueueEntries=%u\n", pThis->cReplyQueueEntries);
4053 pHlp->pfnPrintf(pHlp, "cRequestQueueEntries=%u\n", pThis->cRequestQueueEntries);
4054 pHlp->pfnPrintf(pHlp, "cPorts=%u\n", pThis->cPorts);
4055
4056 /*
4057 * Show queue status.
4058 */
4059 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextEntryFreeWrite=%u\n", pThis->uReplyFreeQueueNextEntryFreeWrite);
4060 pHlp->pfnPrintf(pHlp, "uReplyFreeQueueNextAddressRead=%u\n", pThis->uReplyFreeQueueNextAddressRead);
4061 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextEntryFreeWrite=%u\n", pThis->uReplyPostQueueNextEntryFreeWrite);
4062 pHlp->pfnPrintf(pHlp, "uReplyPostQueueNextAddressRead=%u\n", pThis->uReplyPostQueueNextAddressRead);
4063 pHlp->pfnPrintf(pHlp, "uRequestQueueNextEntryFreeWrite=%u\n", pThis->uRequestQueueNextEntryFreeWrite);
4064 pHlp->pfnPrintf(pHlp, "uRequestQueueNextAddressRead=%u\n", pThis->uRequestQueueNextAddressRead);
4065
4066 /*
4067 * Show queue content if verbose
4068 */
4069 if (fVerbose)
4070 {
4071 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4072 pHlp->pfnPrintf(pHlp, "RFQ[%u]=%#x\n", i, pThis->aReplyFreeQueue[i]);
4073
4074 pHlp->pfnPrintf(pHlp, "\n");
4075
4076 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4077 pHlp->pfnPrintf(pHlp, "RPQ[%u]=%#x\n", i, pThis->aReplyPostQueue[i]);
4078
4079 pHlp->pfnPrintf(pHlp, "\n");
4080
4081 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4082 pHlp->pfnPrintf(pHlp, "ReqQ[%u]=%#x\n", i, pThis->aRequestQueue[i]);
4083 }
4084
4085 /*
4086 * Print the device status.
4087 */
4088 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4089 {
4090 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4091
4092 pHlp->pfnPrintf(pHlp, "\n");
4093
4094 pHlp->pfnPrintf(pHlp, "Device[%u]: device-attached=%RTbool cOutstandingRequests=%u\n",
4095 i, pDevice->pDrvBase != NULL, pDevice->cOutstandingRequests);
4096 }
4097}
4098
4099
4100/**
4101 * @callback_method_impl{FNPDMTHREADDEV}
4102 */
4103static DECLCALLBACK(int) lsilogicR3Worker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4104{
4105 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4106 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4107 int rc = VINF_SUCCESS;
4108
4109 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
4110 return VINF_SUCCESS;
4111
4112 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
4113 {
4114 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, true);
4115 bool fNotificationSent = ASMAtomicXchgBool(&pThis->fNotificationSent, false);
4116 if (!fNotificationSent)
4117 {
4118 Assert(ASMAtomicReadBool(&pThis->fWrkThreadSleeping));
4119 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtProcess, RT_INDEFINITE_WAIT);
4120 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
4121 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
4122 break;
4123 LogFlowFunc(("Woken up with rc=%Rrc\n", rc));
4124 ASMAtomicWriteBool(&pThis->fNotificationSent, false);
4125 }
4126
4127 ASMAtomicWriteBool(&pThis->fWrkThreadSleeping, false);
4128
4129 /* Check whether there is a BIOS request pending and process it first. */
4130 if (ASMAtomicReadBool(&pThis->fBiosReqPending))
4131 {
4132 rc = lsilogicR3PrepareBiosScsiRequest(pThis, pThisCC);
4133 AssertRC(rc);
4134 ASMAtomicXchgBool(&pThis->fBiosReqPending, false);
4135 }
4136
4137 /* Only process request which arrived before we received the notification. */
4138 uint32_t uRequestQueueNextEntryWrite = ASMAtomicReadU32(&pThis->uRequestQueueNextEntryFreeWrite);
4139
4140 /* Go through the messages now and process them. */
4141 while ( RT_LIKELY(pThis->enmState == LSILOGICSTATE_OPERATIONAL)
4142 && (pThis->uRequestQueueNextAddressRead != uRequestQueueNextEntryWrite))
4143 {
4144 MptRequestUnion GuestRequest;
4145 uint32_t u32RequestMessageFrameDesc = pThis->aRequestQueue[pThis->uRequestQueueNextAddressRead];
4146 RTGCPHYS GCPhysMessageFrameAddr = LSILOGIC_RTGCPHYS_FROM_U32(pThis->u32HostMFAHighAddr,
4147 (u32RequestMessageFrameDesc & ~0x07));
4148
4149 /* Read the message header from the guest first. */
4150 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, sizeof(MptMessageHdr));
4151
4152 /* Determine the size of the request. */
4153 uint32_t cbRequest = 0;
4154 switch (GuestRequest.Header.u8Function)
4155 {
4156 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
4157 cbRequest = sizeof(MptSCSIIORequest);
4158 break;
4159 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
4160 cbRequest = sizeof(MptSCSITaskManagementRequest);
4161 break;
4162 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
4163 cbRequest = sizeof(MptIOCInitRequest);
4164 break;
4165 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
4166 cbRequest = sizeof(MptIOCFactsRequest);
4167 break;
4168 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
4169 cbRequest = sizeof(MptConfigurationRequest);
4170 break;
4171 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
4172 cbRequest = sizeof(MptPortFactsRequest);
4173 break;
4174 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
4175 cbRequest = sizeof(MptPortEnableRequest);
4176 break;
4177 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
4178 cbRequest = sizeof(MptEventNotificationRequest);
4179 break;
4180 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
4181 AssertMsgFailed(("todo\n"));
4182 //cbRequest = sizeof(MptEventAckRequest);
4183 break;
4184 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
4185 cbRequest = sizeof(MptFWDownloadRequest);
4186 break;
4187 case MPT_MESSAGE_HDR_FUNCTION_FW_UPLOAD:
4188 cbRequest = sizeof(MptFWUploadRequest);
4189 break;
4190 default:
4191 AssertMsgFailed(("Unknown function issued %u\n", GuestRequest.Header.u8Function));
4192 lsilogicSetIOCFaultCode(pThis, LSILOGIC_IOCSTATUS_INVALID_FUNCTION);
4193 }
4194
4195 if (cbRequest != 0)
4196 {
4197 /* Read the complete message frame from guest memory now. */
4198 PDMDevHlpPCIPhysReadMeta(pDevIns, GCPhysMessageFrameAddr, &GuestRequest, cbRequest);
4199
4200 /* Handle SCSI I/O requests now. */
4201 if (GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST)
4202 {
4203 rc = lsilogicR3ProcessSCSIIORequest(pDevIns, pThis, pThisCC, GCPhysMessageFrameAddr, &GuestRequest);
4204 AssertRC(rc);
4205 }
4206 else
4207 {
4208 MptReplyUnion Reply;
4209 rc = lsilogicR3ProcessMessageRequest(pDevIns, pThis, pThisCC, &GuestRequest.Header, &Reply);
4210 AssertRC(rc);
4211 }
4212
4213 pThis->uRequestQueueNextAddressRead++;
4214 pThis->uRequestQueueNextAddressRead %= pThis->cRequestQueueEntries;
4215 }
4216 } /* While request frames available. */
4217 } /* While running */
4218
4219 return VINF_SUCCESS;
4220}
4221
4222
4223/**
4224 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
4225 */
4226static DECLCALLBACK(int) lsilogicR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
4227{
4228 RT_NOREF(pThread);
4229 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4230 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
4231}
4232
4233
4234/**
4235 * Kicks the controller to process pending tasks after the VM was resumed
4236 * or loaded from a saved state.
4237 *
4238 * @returns nothing.
4239 * @param pDevIns The device instance.
4240 * @param pThis Pointer to the shared LsiLogic device state.
4241 */
4242static void lsilogicR3Kick(PPDMDEVINS pDevIns, PLSILOGICSCSI pThis)
4243{
4244 if (pThis->fNotificationSent)
4245 {
4246 /* Notify the worker thread that there are pending requests. */
4247 LogFlowFunc(("Signal event semaphore\n"));
4248 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEvtProcess);
4249 AssertRC(rc);
4250 }
4251}
4252
4253
4254/*
4255 * Saved state.
4256 */
4257
4258/**
4259 * @callback_method_impl{FNSSMDEVLIVEEXEC}
4260 */
4261static DECLCALLBACK(int) lsilogicR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4262{
4263 RT_NOREF(uPass);
4264 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4265 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4266 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4267
4268 pHlp->pfnSSMPutU32(pSSM, pThis->enmCtrlType);
4269 pHlp->pfnSSMPutU32(pSSM, pThis->cDeviceStates);
4270 pHlp->pfnSSMPutU32(pSSM, pThis->cPorts);
4271
4272 /* Save the device config. */
4273 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4274 pHlp->pfnSSMPutBool(pSSM, pThisCC->paDeviceStates[i].pDrvBase != NULL);
4275
4276 return VINF_SSM_DONT_CALL_AGAIN;
4277}
4278
4279/**
4280 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4281 */
4282static DECLCALLBACK(int) lsilogicR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4283{
4284 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4285 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4286 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4287
4288 /* Every device first. */
4289 lsilogicR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
4290 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4291 {
4292 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4293
4294 AssertMsg(!pDevice->cOutstandingRequests,
4295 ("There are still outstanding requests on this device\n"));
4296 pHlp->pfnSSMPutU32(pSSM, pDevice->cOutstandingRequests);
4297
4298 /* Query all suspended requests and store them in the request queue. */
4299 if (pDevice->pDrvMediaEx)
4300 {
4301 uint32_t cReqsRedo = pDevice->pDrvMediaEx->pfnIoReqGetSuspendedCount(pDevice->pDrvMediaEx);
4302 if (cReqsRedo)
4303 {
4304 PDMMEDIAEXIOREQ hIoReq;
4305 PLSILOGICREQ pReq;
4306 int rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedStart(pDevice->pDrvMediaEx, &hIoReq,
4307 (void **)&pReq);
4308 AssertRCBreak(rc);
4309
4310 for (;;)
4311 {
4312 if (!pReq->fBIOS)
4313 {
4314 /* Write only the lower 32bit part of the address. */
4315 ASMAtomicWriteU32(&pThis->aRequestQueue[pThis->uRequestQueueNextEntryFreeWrite],
4316 pReq->GCPhysMessageFrameAddr & UINT32_C(0xffffffff));
4317
4318 pThis->uRequestQueueNextEntryFreeWrite++;
4319 pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries;
4320 }
4321 else
4322 {
4323 AssertMsg(!pReq->pRedoNext, ("Only one BIOS task can be active!\n"));
4324 vboxscsiSetRequestRedo(&pThisCC->VBoxSCSI);
4325 }
4326
4327 cReqsRedo--;
4328 if (!cReqsRedo)
4329 break;
4330
4331 rc = pDevice->pDrvMediaEx->pfnIoReqQuerySuspendedNext(pDevice->pDrvMediaEx, hIoReq,
4332 &hIoReq, (void **)&pReq);
4333 AssertRCBreak(rc);
4334 }
4335 }
4336 }
4337 }
4338
4339 /* Now the main device state. */
4340 pHlp->pfnSSMPutU32(pSSM, pThis->enmState);
4341 pHlp->pfnSSMPutU32(pSSM, pThis->enmWhoInit);
4342 pHlp->pfnSSMPutU32(pSSM, pThis->enmDoorbellState);
4343 pHlp->pfnSSMPutBool(pSSM, pThis->fDiagnosticEnabled);
4344 pHlp->pfnSSMPutBool(pSSM, pThis->fNotificationSent);
4345 pHlp->pfnSSMPutBool(pSSM, pThis->fEventNotificationEnabled);
4346 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptMask);
4347 pHlp->pfnSSMPutU32(pSSM, pThis->uInterruptStatus);
4348 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4349 pHlp->pfnSSMPutU32(pSSM, pThis->aMessage[i]);
4350 pHlp->pfnSSMPutU32(pSSM, pThis->iMessage);
4351 pHlp->pfnSSMPutU32(pSSM, pThis->cMessage);
4352 pHlp->pfnSSMPutMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4353 pHlp->pfnSSMPutU32(pSSM, pThis->uNextReplyEntryRead);
4354 pHlp->pfnSSMPutU32(pSSM, pThis->cReplySize);
4355 pHlp->pfnSSMPutU16(pSSM, pThis->u16IOCFaultCode);
4356 pHlp->pfnSSMPutU32(pSSM, pThis->u32HostMFAHighAddr);
4357 pHlp->pfnSSMPutU32(pSSM, pThis->u32SenseBufferHighAddr);
4358 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxDevices);
4359 pHlp->pfnSSMPutU8(pSSM, pThis->cMaxBuses);
4360 pHlp->pfnSSMPutU16(pSSM, pThis->cbReplyFrame);
4361 pHlp->pfnSSMPutU32(pSSM, pThis->iDiagnosticAccess);
4362 pHlp->pfnSSMPutU32(pSSM, pThis->cReplyQueueEntries);
4363 pHlp->pfnSSMPutU32(pSSM, pThis->cRequestQueueEntries);
4364 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextEntryFreeWrite);
4365 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyFreeQueueNextAddressRead);
4366 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextEntryFreeWrite);
4367 pHlp->pfnSSMPutU32(pSSM, pThis->uReplyPostQueueNextAddressRead);
4368 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextEntryFreeWrite);
4369 pHlp->pfnSSMPutU32(pSSM, pThis->uRequestQueueNextAddressRead);
4370
4371 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4372 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyFreeQueue[i]);
4373 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4374 pHlp->pfnSSMPutU32(pSSM, pThis->aReplyPostQueue[i]);
4375 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4376 pHlp->pfnSSMPutU32(pSSM, pThis->aRequestQueue[i]);
4377
4378 pHlp->pfnSSMPutU16(pSSM, pThis->u16NextHandle);
4379
4380 /* Save diagnostic memory register and data regions. */
4381 pHlp->pfnSSMPutU32(pSSM, pThis->u32DiagMemAddr);
4382 pHlp->pfnSSMPutU32(pSSM, lsilogicR3MemRegionsCount(pThisCC));
4383
4384 PLSILOGICMEMREGN pIt;
4385 RTListForEach(&pThisCC->ListMemRegns, pIt, LSILOGICMEMREGN, NodeList)
4386 {
4387 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrStart);
4388 pHlp->pfnSSMPutU32(pSSM, pIt->u32AddrEnd);
4389 pHlp->pfnSSMPutMem(pSSM, &pIt->au32Data[0], (pIt->u32AddrEnd - pIt->u32AddrStart + 1) * sizeof(uint32_t));
4390 }
4391
4392 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
4393
4394 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4395 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4396 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4397 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4398 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4399 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4400 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4401 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4402 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4403 pHlp->pfnSSMPutMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4404 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4405 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4406 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4407 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4408 pHlp->pfnSSMPutMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4409 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4410 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4411 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4412 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4413 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4414 pHlp->pfnSSMPutMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4415 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4416 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4417 pHlp->pfnSSMPutMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4418
4419 /* Device dependent pages */
4420 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4421 {
4422 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4423
4424 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4425 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4426 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4427
4428 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4429 {
4430 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4431 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4432 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4433 pHlp->pfnSSMPutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4434 }
4435 }
4436 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4437 {
4438 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4439
4440 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbManufacturingPage7);
4441 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage0);
4442 pHlp->pfnSSMPutU32(pSSM, pSasPages->cbSASIOUnitPage1);
4443
4444 pHlp->pfnSSMPutMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4445 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4446 pHlp->pfnSSMPutMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4447
4448 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4449 pHlp->pfnSSMPutMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4450
4451 pHlp->pfnSSMPutU32(pSSM, pSasPages->cPHYs);
4452 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4453 {
4454 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4455 pHlp->pfnSSMPutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4456 }
4457
4458 /* The number of devices first. */
4459 pHlp->pfnSSMPutU32(pSSM, pSasPages->cDevices);
4460
4461 for (PMptSASDevice pCurr = pSasPages->pSASDeviceHead; pCurr; pCurr = pCurr->pNext)
4462 {
4463 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4464 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4465 pHlp->pfnSSMPutMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4466 }
4467 }
4468 else
4469 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4470
4471 vboxscsiR3SaveExec(pHlp, &pThisCC->VBoxSCSI, pSSM);
4472 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
4473}
4474
4475/**
4476 * @callback_method_impl{FNSSMDEVLOADDONE}
4477 */
4478static DECLCALLBACK(int) lsilogicR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4479{
4480 RT_NOREF(pSSM);
4481 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4482
4483 lsilogicR3Kick(pDevIns, pThis);
4484 return VINF_SUCCESS;
4485}
4486
4487/**
4488 * @callback_method_impl{FNSSMDEVLOADEXEC}
4489 */
4490static DECLCALLBACK(int) lsilogicR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4491{
4492 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4493 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4494 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4495 int rc;
4496
4497 if ( uVersion != LSILOGIC_SAVED_STATE_VERSION
4498 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM
4499 && uVersion != LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL
4500 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_SAS
4501 && uVersion != LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4502 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4503
4504 /* device config */
4505 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4506 {
4507 LSILOGICCTRLTYPE enmCtrlType;
4508 uint32_t cDeviceStates, cPorts;
4509
4510 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, enmCtrlType, LSILOGICCTRLTYPE);
4511 pHlp->pfnSSMGetU32(pSSM, &cDeviceStates);
4512 rc = pHlp->pfnSSMGetU32(pSSM, &cPorts);
4513 AssertRCReturn(rc, rc);
4514
4515 if (enmCtrlType != pThis->enmCtrlType)
4516 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
4517 pThis->enmCtrlType, enmCtrlType);
4518 if (cDeviceStates != pThis->cDeviceStates)
4519 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
4520 pThis->cDeviceStates, cDeviceStates);
4521 if (cPorts != pThis->cPorts)
4522 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"),
4523 pThis->cPorts, cPorts);
4524 }
4525 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4526 {
4527 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4528 {
4529 bool fPresent;
4530 rc = pHlp->pfnSSMGetBool(pSSM, &fPresent);
4531 AssertRCReturn(rc, rc);
4532 if (fPresent != (pThisCC->paDeviceStates[i].pDrvBase != NULL))
4533 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
4534 i, pThisCC->paDeviceStates[i].pDrvBase != NULL, fPresent);
4535 }
4536 }
4537 if (uPass != SSM_PASS_FINAL)
4538 return VINF_SUCCESS;
4539
4540 /* Every device first. */
4541 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4542 {
4543 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
4544
4545 AssertMsg(!pDevice->cOutstandingRequests,
4546 ("There are still outstanding requests on this device\n"));
4547 pHlp->pfnSSMGetU32V(pSSM, &pDevice->cOutstandingRequests);
4548 }
4549 /* Now the main device state. */
4550 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmState, LSILOGICSTATE);
4551 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmWhoInit, LSILOGICWHOINIT);
4552 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_BOOL_DOORBELL)
4553 {
4554 /*
4555 * The doorbell status flag distinguishes only between
4556 * doorbell not in use or a Function handshake is currently in progress.
4557 */
4558 bool fDoorbellInProgress = false;
4559 rc = pHlp->pfnSSMGetBool(pSSM, &fDoorbellInProgress);
4560 AssertRCReturn(rc, rc);
4561 if (fDoorbellInProgress)
4562 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_FN_HANDSHAKE;
4563 else
4564 pThis->enmDoorbellState = LSILOGICDOORBELLSTATE_NOT_IN_USE;
4565 }
4566 else
4567 PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->enmDoorbellState, LSILOGICDOORBELLSTATE);
4568 pHlp->pfnSSMGetBool(pSSM, &pThis->fDiagnosticEnabled);
4569 pHlp->pfnSSMGetBool(pSSM, &pThis->fNotificationSent);
4570 pHlp->pfnSSMGetBool(pSSM, &pThis->fEventNotificationEnabled);
4571 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptMask);
4572 pHlp->pfnSSMGetU32V(pSSM, &pThis->uInterruptStatus);
4573 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aMessage); i++)
4574 pHlp->pfnSSMGetU32(pSSM, &pThis->aMessage[i]);
4575 pHlp->pfnSSMGetU32(pSSM, &pThis->iMessage);
4576 pHlp->pfnSSMGetU32(pSSM, &pThis->cMessage);
4577 pHlp->pfnSSMGetMem(pSSM, &pThis->ReplyBuffer, sizeof(pThis->ReplyBuffer));
4578 pHlp->pfnSSMGetU32(pSSM, &pThis->uNextReplyEntryRead);
4579 pHlp->pfnSSMGetU32(pSSM, &pThis->cReplySize);
4580 pHlp->pfnSSMGetU16(pSSM, &pThis->u16IOCFaultCode);
4581 pHlp->pfnSSMGetU32(pSSM, &pThis->u32HostMFAHighAddr);
4582 pHlp->pfnSSMGetU32(pSSM, &pThis->u32SenseBufferHighAddr);
4583 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxDevices);
4584 pHlp->pfnSSMGetU8(pSSM, &pThis->cMaxBuses);
4585 pHlp->pfnSSMGetU16(pSSM, &pThis->cbReplyFrame);
4586 pHlp->pfnSSMGetU32(pSSM, &pThis->iDiagnosticAccess);
4587
4588 uint32_t cReplyQueueEntries, cRequestQueueEntries;
4589 pHlp->pfnSSMGetU32(pSSM, &cReplyQueueEntries);
4590 rc = pHlp->pfnSSMGetU32(pSSM, &cRequestQueueEntries);
4591 AssertRCReturn(rc, rc);
4592
4593 if ( cReplyQueueEntries != pThis->cReplyQueueEntries
4594 || cRequestQueueEntries != pThis->cRequestQueueEntries)
4595 {
4596 LogRel(("Changing queue sizes: cReplyQueueEntries=%u cRequestQueuEntries=%u\n", cReplyQueueEntries, cRequestQueueEntries));
4597 if ( cReplyQueueEntries > RT_ELEMENTS(pThis->aReplyFreeQueue)
4598 || cReplyQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
4599 || cRequestQueueEntries > RT_ELEMENTS(pThis->aRequestQueue)
4600 || cRequestQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN)
4601 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Out of bounds: cReplyQueueEntries=%u cRequestQueueEntries=%u"),
4602 cReplyQueueEntries, cRequestQueueEntries);
4603 pThis->cReplyQueueEntries = cReplyQueueEntries;
4604 pThis->cRequestQueueEntries = cRequestQueueEntries;
4605 }
4606
4607 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextEntryFreeWrite);
4608 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyFreeQueueNextAddressRead);
4609 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextEntryFreeWrite);
4610 pHlp->pfnSSMGetU32V(pSSM, &pThis->uReplyPostQueueNextAddressRead);
4611 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextEntryFreeWrite);
4612 pHlp->pfnSSMGetU32V(pSSM, &pThis->uRequestQueueNextAddressRead);
4613
4614 PMptConfigurationPagesSupported pPages = pThisCC->pConfigurationPages;
4615
4616 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4617 {
4618 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4619 MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2;
4620
4621 if (pThis->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI)
4622 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller"));
4623
4624 pHlp->pfnSSMGetMem(pSSM, &ConfigPagesV2, sizeof(MptConfigurationPagesSupported_SSM_V2));
4625
4626 pPages->ManufacturingPage0 = ConfigPagesV2.ManufacturingPage0;
4627 pPages->ManufacturingPage1 = ConfigPagesV2.ManufacturingPage1;
4628 pPages->ManufacturingPage2 = ConfigPagesV2.ManufacturingPage2;
4629 pPages->ManufacturingPage3 = ConfigPagesV2.ManufacturingPage3;
4630 pPages->ManufacturingPage4 = ConfigPagesV2.ManufacturingPage4;
4631 pPages->IOUnitPage0 = ConfigPagesV2.IOUnitPage0;
4632 pPages->IOUnitPage1 = ConfigPagesV2.IOUnitPage1;
4633 pPages->IOUnitPage2 = ConfigPagesV2.IOUnitPage2;
4634 pPages->IOUnitPage3 = ConfigPagesV2.IOUnitPage3;
4635 pPages->IOCPage0 = ConfigPagesV2.IOCPage0;
4636 pPages->IOCPage1 = ConfigPagesV2.IOCPage1;
4637 pPages->IOCPage2 = ConfigPagesV2.IOCPage2;
4638 pPages->IOCPage3 = ConfigPagesV2.IOCPage3;
4639 pPages->IOCPage4 = ConfigPagesV2.IOCPage4;
4640 pPages->IOCPage6 = ConfigPagesV2.IOCPage6;
4641
4642 pSpiPages->aPortPages[0].SCSISPIPortPage0 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage0;
4643 pSpiPages->aPortPages[0].SCSISPIPortPage1 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage1;
4644 pSpiPages->aPortPages[0].SCSISPIPortPage2 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage2;
4645
4646 for (unsigned i = 0; i < RT_ELEMENTS(pPages->u.SpiPages.aBuses[0].aDevicePages); i++)
4647 {
4648 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
4649 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
4650 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
4651 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
4652 }
4653 }
4654 else
4655 {
4656 /* Queue content */
4657 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4658 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyFreeQueue[i]);
4659 for (unsigned i = 0; i < pThis->cReplyQueueEntries; i++)
4660 pHlp->pfnSSMGetU32V(pSSM, &pThis->aReplyPostQueue[i]);
4661 for (unsigned i = 0; i < pThis->cRequestQueueEntries; i++)
4662 pHlp->pfnSSMGetU32V(pSSM, &pThis->aRequestQueue[i]);
4663
4664 pHlp->pfnSSMGetU16(pSSM, &pThis->u16NextHandle);
4665
4666 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_DIAG_MEM)
4667 {
4668
4669 /* Save diagnostic memory register and data regions. */
4670 pHlp->pfnSSMGetU32(pSSM, &pThis->u32DiagMemAddr);
4671 uint32_t cMemRegions = 0;
4672 rc = pHlp->pfnSSMGetU32(pSSM, &cMemRegions);
4673 AssertLogRelRCReturn(rc, rc);
4674
4675 while (cMemRegions)
4676 {
4677 uint32_t u32AddrStart = 0;
4678 pHlp->pfnSSMGetU32(pSSM, &u32AddrStart);
4679 uint32_t u32AddrEnd = 0;
4680 rc = pHlp->pfnSSMGetU32(pSSM, &u32AddrEnd);
4681 AssertLogRelRCReturn(rc, rc);
4682
4683 uint32_t cRegion = u32AddrEnd - u32AddrStart + 1;
4684 PLSILOGICMEMREGN pRegion = (PLSILOGICMEMREGN)RTMemAllocZ(RT_UOFFSETOF_DYN(LSILOGICMEMREGN, au32Data[cRegion]));
4685 if (pRegion)
4686 {
4687 pRegion->u32AddrStart = u32AddrStart;
4688 pRegion->u32AddrEnd = u32AddrEnd;
4689 pHlp->pfnSSMGetMem(pSSM, &pRegion->au32Data[0], cRegion * sizeof(uint32_t));
4690 lsilogicR3MemRegionInsert(pThisCC, pRegion);
4691 pThisCC->cbMemRegns += cRegion * sizeof(uint32_t);
4692 }
4693 else
4694 {
4695 /* Leave a log message but continue. */
4696 LogRel(("LsiLogic: Out of memory while restoring the state, might not work as expected\n"));
4697 pHlp->pfnSSMSkip(pSSM, cRegion * sizeof(uint32_t));
4698 }
4699 cMemRegions--;
4700 }
4701 }
4702
4703 /* Configuration pages */
4704 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4705 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4706 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4707 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4708 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4709 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4710 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4711 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4712 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4713 pHlp->pfnSSMGetMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4714 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4715 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4716 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4717 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4718 pHlp->pfnSSMGetMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4719 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4720 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4721 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4722 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4723 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4724 pHlp->pfnSSMGetMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4725 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4726 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4727 pHlp->pfnSSMGetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4728
4729 /* Device dependent pages */
4730 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4731 {
4732 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4733
4734 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4735 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4736 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4737
4738 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4739 {
4740 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4741 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4742 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4743 pHlp->pfnSSMGetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4744 }
4745 }
4746 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4747 {
4748 uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7;
4749 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4750
4751 pHlp->pfnSSMGetU32(pSSM, &cbManufacturingPage7);
4752 pHlp->pfnSSMGetU32(pSSM, &cbPage0);
4753 rc = pHlp->pfnSSMGetU32(pSSM, &cbPage1);
4754 AssertRCReturn(rc, rc);
4755
4756 if ( (cbPage0 != pSasPages->cbSASIOUnitPage0)
4757 || (cbPage1 != pSasPages->cbSASIOUnitPage1)
4758 || (cbManufacturingPage7 != pSasPages->cbManufacturingPage7))
4759 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4760
4761 AssertPtr(pSasPages->pManufacturingPage7);
4762 AssertPtr(pSasPages->pSASIOUnitPage0);
4763 AssertPtr(pSasPages->pSASIOUnitPage1);
4764
4765 pHlp->pfnSSMGetMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4766 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4767 pHlp->pfnSSMGetMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4768
4769 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4770 pHlp->pfnSSMGetMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4771
4772 rc = pHlp->pfnSSMGetU32(pSSM, &cPHYs);
4773 AssertRCReturn(rc, rc);
4774 if (cPHYs != pSasPages->cPHYs)
4775 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4776
4777 AssertPtr(pSasPages->paPHYs);
4778 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4779 {
4780 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4781 pHlp->pfnSSMGetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4782 }
4783
4784 /* The number of devices first. */
4785 rc = pHlp->pfnSSMGetU32(pSSM, &pSasPages->cDevices);
4786 AssertRCReturn(rc, rc);
4787
4788 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4789
4790 for (unsigned i = 0; i < pSasPages->cDevices; i++)
4791 {
4792 AssertReturn(pCurr, VERR_SSM_LOAD_CONFIG_MISMATCH);
4793
4794 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4795 pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4796 rc = pHlp->pfnSSMGetMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4797 AssertRCReturn(rc, rc);
4798
4799 pCurr = pCurr->pNext;
4800 }
4801
4802 Assert(!pCurr);
4803 }
4804 else
4805 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4806 }
4807
4808 rc = vboxscsiR3LoadExec(pHlp, &pThisCC->VBoxSCSI, pSSM);
4809 if (RT_FAILURE(rc))
4810 {
4811 LogRel(("LsiLogic: Failed to restore BIOS state: %Rrc.\n", rc));
4812 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: Failed to restore BIOS state\n"));
4813 }
4814
4815 uint32_t u32;
4816 rc = pHlp->pfnSSMGetU32(pSSM, &u32);
4817 if (RT_FAILURE(rc))
4818 return rc;
4819 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4820
4821 return VINF_SUCCESS;
4822}
4823
4824
4825/*
4826 * The device level IBASE and LED interfaces.
4827 */
4828
4829/**
4830 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed, For a SCSI device.}
4831 *
4832 * @remarks Called by the scsi driver, proxying the main calls.
4833 */
4834static DECLCALLBACK(int) lsilogicR3DeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4835{
4836 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, ILed);
4837 if (iLUN == 0)
4838 {
4839 *ppLed = &pDevice->Led;
4840 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4841 return VINF_SUCCESS;
4842 }
4843 return VERR_PDM_LUN_NOT_FOUND;
4844}
4845
4846
4847/**
4848 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4849 */
4850static DECLCALLBACK(void *) lsilogicR3DeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4851{
4852 PLSILOGICDEVICE pDevice = RT_FROM_MEMBER(pInterface, LSILOGICDEVICE, IBase);
4853
4854 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
4855 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pDevice->IMediaPort);
4856 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pDevice->IMediaExPort);
4857 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
4858 return NULL;
4859}
4860
4861
4862/*
4863 * The controller level IBASE and LED interfaces.
4864 */
4865
4866/**
4867 * Gets the pointer to the status LED of a unit.
4868 *
4869 * @returns VBox status code.
4870 * @param pInterface Pointer to the interface structure containing the called function pointer.
4871 * @param iLUN The unit which status LED we desire.
4872 * @param ppLed Where to store the LED pointer.
4873 */
4874static DECLCALLBACK(int) lsilogicR3StatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4875{
4876 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, ILeds);
4877 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PLSILOGICSCSI);
4878 if (iLUN < pThis->cDeviceStates)
4879 {
4880 *ppLed = &pThisCC->paDeviceStates[iLUN].Led;
4881 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4882 return VINF_SUCCESS;
4883 }
4884 return VERR_PDM_LUN_NOT_FOUND;
4885}
4886
4887/**
4888 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4889 */
4890static DECLCALLBACK(void *) lsilogicR3StatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4891{
4892 PLSILOGICSCSICC pThisCC = RT_FROM_MEMBER(pInterface, LSILOGICSCSICC, IBase);
4893 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4894 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds);
4895 return NULL;
4896}
4897
4898
4899/*
4900 * The PDM device interface and some helpers.
4901 */
4902
4903/**
4904 * Checks if all asynchronous I/O is finished.
4905 *
4906 * Used by lsilogicR3Reset, lsilogicR3Suspend and lsilogicR3PowerOff.
4907 *
4908 * @returns true if quiesced, false if busy.
4909 * @param pDevIns The device instance.
4910 */
4911static bool lsilogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
4912{
4913 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4914 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4915
4916 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4917 {
4918 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
4919 if (pThisDevice->pDrvBase)
4920 {
4921 if (pThisDevice->cOutstandingRequests != 0)
4922 return false;
4923 }
4924 }
4925
4926 return true;
4927}
4928
4929/**
4930 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
4931 * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff.}
4932 */
4933static DECLCALLBACK(bool) lsilogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
4934{
4935 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4936 return false;
4937
4938 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4939 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4940 return true;
4941}
4942
4943/**
4944 * Common worker for ahciR3Suspend and ahciR3PowerOff.
4945 */
4946static void lsilogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
4947{
4948 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4949 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
4950
4951 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
4952 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
4953 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncSuspendOrPowerOffDone);
4954 else
4955 {
4956 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
4957
4958 AssertMsg(!pThis->fNotificationSent, ("The PDM Queue should be empty at this point\n"));
4959 }
4960
4961 for (uint32_t i = 0; i < pThis->cDeviceStates; i++)
4962 {
4963 PLSILOGICDEVICE pThisDevice = &pThisCC->paDeviceStates[i];
4964 if (pThisDevice->pDrvMediaEx)
4965 pThisDevice->pDrvMediaEx->pfnNotifySuspend(pThisDevice->pDrvMediaEx);
4966 }
4967}
4968
4969/**
4970 * @interface_method_impl{PDMDEVREG,pfnSuspend}
4971 */
4972static DECLCALLBACK(void) lsilogicR3Suspend(PPDMDEVINS pDevIns)
4973{
4974 Log(("lsilogicR3Suspend\n"));
4975 lsilogicR3SuspendOrPowerOff(pDevIns);
4976}
4977
4978/**
4979 * @interface_method_impl{PDMDEVREG,pfnResume}
4980 */
4981static DECLCALLBACK(void) lsilogicR3Resume(PPDMDEVINS pDevIns)
4982{
4983 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4984
4985 Log(("lsilogicR3Resume\n"));
4986
4987 lsilogicR3Kick(pDevIns, pThis);
4988}
4989
4990/**
4991 * @interface_method_impl{PDMDEVREG,pfnDetach}
4992 *
4993 * One harddisk at one port has been unplugged.
4994 * The VM is suspended at this point.
4995 */
4996static DECLCALLBACK(void) lsilogicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4997{
4998 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
4999 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5000 Log(("%s: iLUN=%#x\n", __FUNCTION__, iLUN));
5001 RT_NOREF(fFlags);
5002
5003 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG, ("LsiLogic: Device does not support hotplugging\n"));
5004
5005 if (iLUN >= pThis->cDeviceStates)
5006 return;
5007
5008 /*
5009 * Zero some important members.
5010 */
5011 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
5012 pDevice->pDrvBase = NULL;
5013 pDevice->pDrvMedia = NULL;
5014 pDevice->pDrvMediaEx = NULL;
5015}
5016
5017/**
5018 * @interface_method_impl{PDMDEVREG,pfnAttach}
5019 */
5020static DECLCALLBACK(int) lsilogicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
5021{
5022 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5023 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5024 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[iLUN];
5025 int rc;
5026
5027 if (iLUN >= pThis->cDeviceStates)
5028 return VERR_PDM_LUN_NOT_FOUND;
5029
5030 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
5031 ("LsiLogic: Device does not support hotplugging\n"),
5032 VERR_INVALID_PARAMETER);
5033
5034 /* the usual paranoia */
5035 AssertRelease(!pDevice->pDrvBase);
5036 AssertRelease(!pDevice->pDrvMedia);
5037 AssertRelease(!pDevice->pDrvMediaEx);
5038 Assert(pDevice->iLUN == iLUN);
5039
5040 /*
5041 * Try attach the block device and get the interfaces,
5042 * required as well as optional.
5043 */
5044 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
5045 if (RT_SUCCESS(rc))
5046 {
5047 /* Query the media interface. */
5048 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5049 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5050 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5051 VERR_PDM_MISSING_INTERFACE);
5052
5053 /* Get the extended media interface. */
5054 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5055 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5056 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5057 VERR_PDM_MISSING_INTERFACE);
5058
5059 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5060 AssertMsgRCReturn(rc, ("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!", pDevice->iLUN),
5061 rc);
5062 }
5063 else
5064 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
5065
5066 if (RT_FAILURE(rc))
5067 {
5068 pDevice->pDrvBase = NULL;
5069 pDevice->pDrvMedia = NULL;
5070 pDevice->pDrvMediaEx = NULL;
5071 }
5072 return rc;
5073}
5074
5075/**
5076 * Common reset worker.
5077 *
5078 * @param pDevIns The device instance data.
5079 */
5080static void lsilogicR3ResetCommon(PPDMDEVINS pDevIns)
5081{
5082 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5083 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5084 int rc;
5085
5086 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
5087 AssertRC(rc);
5088
5089 vboxscsiHwReset(&pThisCC->VBoxSCSI);
5090}
5091
5092/**
5093 * @callback_method_impl{FNPDMDEVASYNCNOTIFY,
5094 * Callback employed by lsilogicR3Reset.}
5095 */
5096static DECLCALLBACK(bool) lsilogicR3IsAsyncResetDone(PPDMDEVINS pDevIns)
5097{
5098 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5099
5100 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5101 return false;
5102 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5103
5104 lsilogicR3ResetCommon(pDevIns);
5105 return true;
5106}
5107
5108/**
5109 * @interface_method_impl{PDMDEVREG,pfnReset}
5110 */
5111static DECLCALLBACK(void) lsilogicR3Reset(PPDMDEVINS pDevIns)
5112{
5113 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5114
5115 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
5116 if (!lsilogicR3AllAsyncIOIsFinished(pDevIns))
5117 PDMDevHlpSetAsyncNotification(pDevIns, lsilogicR3IsAsyncResetDone);
5118 else
5119 {
5120 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
5121 lsilogicR3ResetCommon(pDevIns);
5122 }
5123}
5124
5125/**
5126 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
5127 */
5128static DECLCALLBACK(void) lsilogicR3PowerOff(PPDMDEVINS pDevIns)
5129{
5130 Log(("lsilogicR3PowerOff\n"));
5131 lsilogicR3SuspendOrPowerOff(pDevIns);
5132}
5133
5134/**
5135 * @interface_method_impl{PDMDEVREG,pfnDestruct}
5136 */
5137static DECLCALLBACK(int) lsilogicR3Destruct(PPDMDEVINS pDevIns)
5138{
5139 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
5140 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5141 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5142
5143 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueCritSect);
5144 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyPostQueueCritSect);
5145 PDMDevHlpCritSectDelete(pDevIns, &pThis->RequestQueueCritSect);
5146 PDMDevHlpCritSectDelete(pDevIns, &pThis->ReplyFreeQueueWriteCritSect);
5147
5148 RTMemFree(pThisCC->paDeviceStates);
5149 pThisCC->paDeviceStates = NULL;
5150
5151 if (pThis->hEvtProcess != NIL_SUPSEMEVENT)
5152 {
5153 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtProcess);
5154 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5155 }
5156
5157 lsilogicR3ConfigurationPagesFree(pThis, pThisCC);
5158 lsilogicR3MemRegionsFree(pThisCC);
5159 vboxscsiDestroy(&pThisCC->VBoxSCSI);
5160
5161 return VINF_SUCCESS;
5162}
5163
5164/**
5165 * @interface_method_impl{PDMDEVREG,pfnConstruct}
5166 */
5167static DECLCALLBACK(int) lsilogicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
5168{
5169 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5170 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5171 PLSILOGICSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PLSILOGICSCSICC);
5172 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5173 int rc = VINF_SUCCESS;
5174
5175 /*
5176 * Initialize enought of the state to make the destructure not trip up.
5177 */
5178 pThis->hEvtProcess = NIL_SUPSEMEVENT;
5179 pThis->fBiosReqPending = false;
5180 RTListInit(&pThisCC->ListMemRegns);
5181 pThis->hMmioReg = NIL_IOMMMIOHANDLE;
5182 pThis->hMmioDiag = NIL_IOMMMIOHANDLE;
5183 pThis->hIoPortsReg = NIL_IOMIOPORTHANDLE;
5184 pThis->hIoPortsBios = NIL_IOMIOPORTHANDLE;
5185 pThisCC->pDevIns = pDevIns;
5186 pThisCC->IBase.pfnQueryInterface = lsilogicR3StatusQueryInterface;
5187 pThisCC->ILeds.pfnQueryStatusLed = lsilogicR3StatusQueryStatusLed;
5188
5189
5190 /*
5191 * Validate and read configuration.
5192 */
5193 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
5194 "ReplyQueueDepth|"
5195 "RequestQueueDepth|"
5196 "ControllerType|"
5197 "NumPorts|"
5198 "Bootable",
5199 "");
5200
5201 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "ReplyQueueDepth",
5202 &pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT);
5203 if (RT_FAILURE(rc))
5204 return PDMDEV_SET_ERROR(pDevIns, rc,
5205 N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
5206 if ( pThis->cReplyQueueEntries < LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN
5207 || pThis->cReplyQueueEntries > LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5208 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5209 N_("LsiLogic configuration error: 'ReplyQueueDepth' = %u is out of ranage (%u..%u)"),
5210 pThis->cReplyQueueEntries, LSILOGICSCSI_REPLY_QUEUE_DEPTH_MIN,
5211 LSILOGICSCSI_REPLY_QUEUE_DEPTH_MAX - 1);
5212 Log(("%s: ReplyQueueDepth=%u\n", __FUNCTION__, pThis->cReplyQueueEntries));
5213
5214 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "RequestQueueDepth",
5215 &pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT);
5216 if (RT_FAILURE(rc))
5217 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
5218 if ( pThis->cRequestQueueEntries < LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN
5219 || pThis->cRequestQueueEntries > LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MAX - 1 /* see +1 later in the function */)
5220 return PDMDevHlpVMSetError(pDevIns, VERR_OUT_OF_RANGE, RT_SRC_POS,
5221 N_("LsiLogic configuration error: 'RequestQueue' = %u is out of ranage (%u..%u)"),
5222 pThis->cRequestQueueEntries, LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN,
5223 LSILOGICSCSI_REQUEST_QUEUE_DEPTH_MIN - 1);
5224 Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries));
5225
5226 char szCtrlType[64];
5227 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "ControllerType", szCtrlType, sizeof(szCtrlType), LSILOGICSCSI_PCI_SPI_CTRLNAME);
5228 if (RT_FAILURE(rc))
5229 return PDMDEV_SET_ERROR(pDevIns, rc,
5230 N_("LsiLogic configuration error: failed to read ControllerType as string"));
5231 Log(("%s: ControllerType=%s\n", __FUNCTION__, szCtrlType));
5232 rc = lsilogicR3GetCtrlTypeFromString(pThis, szCtrlType);
5233 if (RT_FAILURE(rc))
5234 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic configuration error: failed to determine controller type from string"));
5235
5236 char szDevTag[20];
5237 RTStrPrintf(szDevTag, sizeof(szDevTag), "LSILOGIC%s-%u",
5238 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "SPI" : "SAS",
5239 iInstance);
5240
5241 rc = pHlp->pfnCFGMQueryU8(pCfg, "NumPorts", &pThis->cPorts);
5242 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
5243 {
5244 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5245 pThis->cPorts = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
5246 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5247 pThis->cPorts = LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT;
5248 else
5249 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5250 }
5251 else if (RT_FAILURE(rc))
5252 return PDMDEV_SET_ERROR(pDevIns, rc,
5253 N_("LsiLogic configuration error: failed to read NumPorts as integer"));
5254
5255 bool fBootable;
5256 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Bootable", &fBootable, true);
5257 if (RT_FAILURE(rc))
5258 return PDMDEV_SET_ERROR(pDevIns, rc,
5259 N_("LsiLogic configuration error: failed to read Bootable as boolean"));
5260 Log(("%s: Bootable=%RTbool\n", __FUNCTION__, fBootable));
5261
5262 /* Init static parts. */
5263 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
5264 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
5265
5266 PDMPciDevSetVendorId(pPciDev, LSILOGICSCSI_PCI_VENDOR_ID); /* LsiLogic */
5267 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5268 {
5269 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SPI_DEVICE_ID); /* LSI53C1030 */
5270 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID);
5271 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID);
5272 }
5273 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5274 {
5275 PDMPciDevSetDeviceId(pPciDev, LSILOGICSCSI_PCI_SAS_DEVICE_ID); /* SAS1068 */
5276 PDMPciDevSetSubSystemVendorId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID);
5277 PDMPciDevSetSubSystemId(pPciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID);
5278 }
5279 else
5280 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5281
5282 PDMPciDevSetClassProg(pPciDev, 0x00); /* SCSI */
5283 PDMPciDevSetClassSub(pPciDev, 0x00); /* SCSI */
5284 PDMPciDevSetClassBase(pPciDev, 0x01); /* Mass storage */
5285 PDMPciDevSetInterruptPin(pPciDev, 0x01); /* Interrupt pin A */
5286
5287# ifdef VBOX_WITH_MSI_DEVICES
5288 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
5289 PDMPciDevSetCapabilityList(pPciDev, 0x80);
5290# endif
5291
5292 /*
5293 * Create critical sections protecting the reply post and free queues.
5294 */
5295 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag);
5296 if (RT_FAILURE(rc))
5297 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue"));
5298
5299 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag);
5300 if (RT_FAILURE(rc))
5301 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply post queue"));
5302
5303 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->RequestQueueCritSect, RT_SRC_POS, "%sRQ", szDevTag);
5304 if (RT_FAILURE(rc))
5305 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for request queue"));
5306
5307 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueWriteCritSect, RT_SRC_POS, "%sRFQW", szDevTag);
5308 if (RT_FAILURE(rc))
5309 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic: cannot create critical section for reply free queue write access"));
5310
5311 /*
5312 * Register the PCI device, it's I/O regions.
5313 */
5314 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
5315 if (RT_FAILURE(rc))
5316 return rc;
5317
5318# ifdef VBOX_WITH_MSI_DEVICES
5319 PDMMSIREG MsiReg;
5320 RT_ZERO(MsiReg);
5321 /* use this code for MSI-X support */
5322# if 0
5323 MsiReg.cMsixVectors = 1;
5324 MsiReg.iMsixCapOffset = 0x80;
5325 MsiReg.iMsixNextOffset = 0x00;
5326 MsiReg.iMsixBar = 3;
5327 Assert(pDevIns->pReg->cMaxMsixVectors >= MsiReg.cMsixVectors); /* fix device registration when enabling this */
5328# else
5329 MsiReg.cMsiVectors = 1;
5330 MsiReg.iMsiCapOffset = 0x80;
5331 MsiReg.iMsiNextOffset = 0x00;
5332# endif
5333 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
5334 if (RT_FAILURE (rc))
5335 {
5336 /* That's OK, we can work without MSI */
5337 PDMPciDevSetCapabilityList(pPciDev, 0x0);
5338 }
5339# endif
5340
5341 /* Region #0: I/O ports. */
5342 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, LSILOGIC_PCI_SPACE_IO_SIZE,
5343 lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/,
5344 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5345 NULL /*paExtDesc*/, &pThis->hIoPortsReg);
5346 AssertRCReturn(rc, rc);
5347
5348 /* Region #1: MMIO.
5349 *
5350 * Non-4-byte read access to LSILOGIC_REG_REPLY_QUEUE may cause real strange behavior
5351 * because the data is part of a physical guest address. But some drivers use 1-byte
5352 * access to scan for SCSI controllers. So, we simplify our code by telling IOM to
5353 * read DWORDs.
5354 *
5355 * Regarding writes, we couldn't find anything specific in the specs about what should
5356 * happen. So far we've ignored unaligned writes and assumed the missing bytes of
5357 * byte and word access to be zero. We suspect that IOMMMIO_FLAGS_WRITE_ONLY_DWORD
5358 * or IOMMMIO_FLAGS_WRITE_DWORD_ZEROED would be the most appropriate here, but since we
5359 * don't have real hw to test one, the old behavior is kept exactly like it used to be.
5360 */
5361 /** @todo Check out unaligned writes and non-dword writes on real LsiLogic
5362 * hardware. */
5363 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 1 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5364 lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/,
5365 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5366 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogic" : "LsiLogicSas",
5367 &pThis->hMmioReg);
5368 AssertRCReturn(rc, rc);
5369
5370 /* Region #2: MMIO - Diag. */
5371 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 2 /*iPciRegion*/, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM,
5372 lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/,
5373 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
5374 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI ? "LsiLogicDiag" : "LsiLogicSasDiag",
5375 &pThis->hMmioDiag);
5376 AssertRCReturn(rc, rc);
5377
5378 /*
5379 * We need one entry free in the queue.
5380 */
5381 pThis->cReplyQueueEntries++;
5382 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyFreeQueue), VERR_INTERNAL_ERROR_3);
5383 AssertLogRelReturn(pThis->cReplyQueueEntries <= RT_ELEMENTS(pThis->aReplyPostQueue), VERR_INTERNAL_ERROR_3);
5384
5385 pThis->cRequestQueueEntries++;
5386 AssertLogRelReturn(pThis->cRequestQueueEntries <= RT_ELEMENTS(pThis->aRequestQueue), VERR_INTERNAL_ERROR_3);
5387
5388 /*
5389 * Device states.
5390 */
5391 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5392 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
5393 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5394 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
5395 else
5396 AssertLogRelMsgFailedReturn(("Invalid controller type: %d\n", pThis->enmCtrlType), VERR_INTERNAL_ERROR_4);
5397
5398 /*
5399 * Create event semaphore and worker thread.
5400 */
5401 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pThreadWrk, pThis, lsilogicR3Worker,
5402 lsilogicR3WorkerWakeUp, 0, RTTHREADTYPE_IO, szDevTag);
5403 if (RT_FAILURE(rc))
5404 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5405 N_("LsiLogic: Failed to create worker thread %s"), szDevTag);
5406
5407 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtProcess);
5408 if (RT_FAILURE(rc))
5409 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5410 N_("LsiLogic: Failed to create SUP event semaphore"));
5411
5412 /*
5413 * Allocate device states.
5414 */
5415 pThisCC->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
5416 if (!pThisCC->paDeviceStates)
5417 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate memory for device states"));
5418
5419 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
5420 {
5421 PLSILOGICDEVICE pDevice = &pThisCC->paDeviceStates[i];
5422
5423 /* Initialize static parts of the device. */
5424 pDevice->iLUN = i;
5425 pDevice->pDevIns = pDevIns;
5426 pDevice->Led.u32Magic = PDMLED_MAGIC;
5427 pDevice->IBase.pfnQueryInterface = lsilogicR3DeviceQueryInterface;
5428 pDevice->IMediaPort.pfnQueryDeviceLocation = lsilogicR3QueryDeviceLocation;
5429 pDevice->IMediaExPort.pfnIoReqCompleteNotify = lsilogicR3IoReqCompleteNotify;
5430 pDevice->IMediaExPort.pfnIoReqCopyFromBuf = lsilogicR3IoReqCopyFromBuf;
5431 pDevice->IMediaExPort.pfnIoReqCopyToBuf = lsilogicR3IoReqCopyToBuf;
5432 pDevice->IMediaExPort.pfnIoReqQueryBuf = NULL;
5433 pDevice->IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
5434 pDevice->IMediaExPort.pfnIoReqStateChanged = lsilogicR3IoReqStateChanged;
5435 pDevice->IMediaExPort.pfnMediumEjected = lsilogicR3MediumEjected;
5436 pDevice->ILed.pfnQueryStatusLed = lsilogicR3DeviceQueryStatusLed;
5437 RTStrPrintf(pDevice->szName, sizeof(pDevice->szName), "Device%u", i);
5438
5439 /* Attach SCSI driver. */
5440 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, pDevice->szName);
5441 if (RT_SUCCESS(rc))
5442 {
5443 /* Query the media interface. */
5444 pDevice->pDrvMedia = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIA);
5445 AssertMsgReturn(VALID_PTR(pDevice->pDrvMedia),
5446 ("LsiLogic configuration error: LUN#%d misses the basic media interface!\n", pDevice->iLUN),
5447 VERR_PDM_MISSING_INTERFACE);
5448
5449 /* Get the extended media interface. */
5450 pDevice->pDrvMediaEx = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMIMEDIAEX);
5451 AssertMsgReturn(VALID_PTR(pDevice->pDrvMediaEx),
5452 ("LsiLogic configuration error: LUN#%d misses the extended media interface!\n", pDevice->iLUN),
5453 VERR_PDM_MISSING_INTERFACE);
5454
5455 rc = pDevice->pDrvMediaEx->pfnIoReqAllocSizeSet(pDevice->pDrvMediaEx, sizeof(LSILOGICREQ));
5456 if (RT_FAILURE(rc))
5457 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
5458 N_("LsiLogic configuration error: LUN#%u: Failed to set I/O request size!"),
5459 pDevice->iLUN);
5460 }
5461 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5462 {
5463 pDevice->pDrvBase = NULL;
5464 rc = VINF_SUCCESS;
5465 Log(("LsiLogic: no driver attached to device %s\n", pDevice->szName));
5466 }
5467 else
5468 {
5469 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", pDevice->szName));
5470 return rc;
5471 }
5472 }
5473
5474 /*
5475 * Attach status driver (optional).
5476 */
5477 PPDMIBASE pBase;
5478 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
5479 if (RT_SUCCESS(rc))
5480 {
5481 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5482 pThisCC->pMediaNotify = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIANOTIFY);
5483 }
5484 else
5485 AssertMsgReturn(rc == VERR_PDM_NO_ATTACHED_DRIVER,
5486 ("Failed to attach to status driver. rc=%Rrc\n", rc),
5487 PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver")));
5488
5489 /* Initialize the SCSI emulation for the BIOS. */
5490 rc = vboxscsiInitialize(&pThisCC->VBoxSCSI);
5491 if (RT_FAILURE(rc))
5492 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic failed to initialize BIOS SCSI interface"));
5493
5494 /*
5495 * Register I/O port space in ISA region for BIOS access
5496 * if the controller is marked as bootable.
5497 */
5498 if (fBootable)
5499 {
5500 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5501 rc = PDMDevHlpIoPortCreateExAndMap(pDevIns, LSILOGIC_BIOS_IO_PORT, 4 /*cPorts*/, 0 /*fFlags*/,
5502 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5503 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, NULL /*pvUser*/,
5504 "LsiLogic BIOS", NULL /*paExtDesc*/, &pThis->hIoPortsBios);
5505 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5506 rc = PDMDevHlpIoPortCreateExAndMap(pDevIns, LSILOGIC_SAS_BIOS_IO_PORT, 4 /*cPorts*/, 0 /*fFlags*/,
5507 lsilogicR3IsaIOPortWrite, lsilogicR3IsaIOPortRead,
5508 lsilogicR3IsaIOPortWriteStr, lsilogicR3IsaIOPortReadStr, NULL /*pvUser*/,
5509 "LsiLogic SAS BIOS", NULL /*paExtDesc*/, &pThis->hIoPortsBios);
5510 else
5511 AssertMsgFailedReturn(("Invalid controller type %d\n", pThis->enmCtrlType), VERR_INTERNAL_ERROR_3);
5512 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register legacy I/O handlers")));
5513 }
5514
5515 /* Register save state handlers. */
5516 rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5517 NULL, lsilogicR3LiveExec, NULL,
5518 NULL, lsilogicR3SaveExec, NULL,
5519 NULL, lsilogicR3LoadExec, lsilogicR3LoadDone);
5520 if (RT_FAILURE(rc))
5521 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
5522
5523 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
5524
5525 /*
5526 * Register the info item.
5527 */
5528 char szTmp[128];
5529 RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
5530 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp,
5531 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
5532 ? "LsiLogic SPI info."
5533 : "LsiLogic SAS info.", lsilogicR3Info);
5534
5535 /* Perform hard reset. */
5536 rc = lsilogicR3HardReset(pDevIns, pThis, pThisCC);
5537 AssertRC(rc);
5538
5539 return rc;
5540}
5541
5542#else /* !IN_RING3 */
5543
5544/**
5545 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5546 */
5547static DECLCALLBACK(int) lsilogicRZConstruct(PPDMDEVINS pDevIns)
5548{
5549 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5550 PLSILOGICSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PLSILOGICSCSI);
5551
5552 /* Setup callbacks for this context: */
5553 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsReg, lsilogicIOPortWrite, lsilogicIOPortRead, NULL /*pvUser*/);
5554 AssertRCReturn(rc, rc);
5555
5556 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioReg, lsilogicMMIOWrite, lsilogicMMIORead, NULL /*pvUser*/);
5557 AssertRCReturn(rc, rc);
5558
5559 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioDiag, lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL /*pvUser*/);
5560 AssertRCReturn(rc, rc);
5561
5562 return VINF_SUCCESS;
5563}
5564
5565#endif /* !IN_RING3 */
5566
5567/**
5568 * The device registration structure - SPI SCSI controller.
5569 */
5570const PDMDEVREG g_DeviceLsiLogicSCSI =
5571{
5572 /* .u32Version = */ PDM_DEVREG_VERSION,
5573 /* .uReserved0 = */ 0,
5574 /* .szName = */ "lsilogicscsi",
5575 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5576 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
5577 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5578 /* .cMaxInstances = */ ~0U,
5579 /* .uSharedVersion = */ 42,
5580 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
5581 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5582 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
5583 /* .cMaxPciDevices = */ 1,
5584 /* .cMaxMsixVectors = */ 0,
5585 /* .pszDescription = */ "LSI Logic 53c1030 SCSI controller.\n",
5586#if defined(IN_RING3)
5587 /* .pszRCMod = */ "VBoxDDRC.rc",
5588 /* .pszR0Mod = */ "VBoxDDR0.r0",
5589 /* .pfnConstruct = */ lsilogicR3Construct,
5590 /* .pfnDestruct = */ lsilogicR3Destruct,
5591 /* .pfnRelocate = */ NULL,
5592 /* .pfnMemSetup = */ NULL,
5593 /* .pfnPowerOn = */ NULL,
5594 /* .pfnReset = */ lsilogicR3Reset,
5595 /* .pfnSuspend = */ lsilogicR3Suspend,
5596 /* .pfnResume = */ lsilogicR3Resume,
5597 /* .pfnAttach = */ lsilogicR3Attach,
5598 /* .pfnDetach = */ lsilogicR3Detach,
5599 /* .pfnQueryInterface = */ NULL,
5600 /* .pfnInitComplete = */ NULL,
5601 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5602 /* .pfnSoftReset = */ NULL,
5603 /* .pfnReserved0 = */ NULL,
5604 /* .pfnReserved1 = */ NULL,
5605 /* .pfnReserved2 = */ NULL,
5606 /* .pfnReserved3 = */ NULL,
5607 /* .pfnReserved4 = */ NULL,
5608 /* .pfnReserved5 = */ NULL,
5609 /* .pfnReserved6 = */ NULL,
5610 /* .pfnReserved7 = */ NULL,
5611#elif defined(IN_RING0)
5612 /* .pfnEarlyConstruct = */ NULL,
5613 /* .pfnConstruct = */ lsilogicRZConstruct,
5614 /* .pfnDestruct = */ NULL,
5615 /* .pfnFinalDestruct = */ NULL,
5616 /* .pfnRequest = */ NULL,
5617 /* .pfnReserved0 = */ NULL,
5618 /* .pfnReserved1 = */ NULL,
5619 /* .pfnReserved2 = */ NULL,
5620 /* .pfnReserved3 = */ NULL,
5621 /* .pfnReserved4 = */ NULL,
5622 /* .pfnReserved5 = */ NULL,
5623 /* .pfnReserved6 = */ NULL,
5624 /* .pfnReserved7 = */ NULL,
5625#elif defined(IN_RC)
5626 /* .pfnConstruct = */ lsilogicRZConstruct,
5627 /* .pfnReserved0 = */ NULL,
5628 /* .pfnReserved1 = */ NULL,
5629 /* .pfnReserved2 = */ NULL,
5630 /* .pfnReserved3 = */ NULL,
5631 /* .pfnReserved4 = */ NULL,
5632 /* .pfnReserved5 = */ NULL,
5633 /* .pfnReserved6 = */ NULL,
5634 /* .pfnReserved7 = */ NULL,
5635#else
5636# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5637#endif
5638 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5639};
5640
5641/**
5642 * The device registration structure - SAS controller.
5643 */
5644const PDMDEVREG g_DeviceLsiLogicSAS =
5645{
5646 /* .u32Version = */ PDM_DEVREG_VERSION,
5647 /* .uReserved0 = */ 0,
5648 /* .szName = */ "lsilogicsas",
5649 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5650 | PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION
5651 | PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
5652 /* .fClass = */ PDM_DEVREG_CLASS_STORAGE,
5653 /* .cMaxInstances = */ ~0U,
5654 /* .uSharedVersion = */ 42,
5655 /* .cbInstanceShared = */ sizeof(LSILOGICSCSI),
5656 /* .cbInstanceCC = */ sizeof(LSILOGICSCSICC),
5657 /* .cbInstanceRC = */ sizeof(LSILOGICSCSIRC),
5658 /* .cMaxPciDevices = */ 1,
5659 /* .cMaxMsixVectors = */ 0,
5660 /* .pszDescription = */ "LSI Logic SAS1068 controller.\n",
5661#if defined(IN_RING3)
5662 /* .pszRCMod = */ "VBoxDDRC.rc",
5663 /* .pszR0Mod = */ "VBoxDDR0.r0",
5664 /* .pfnConstruct = */ lsilogicR3Construct,
5665 /* .pfnDestruct = */ lsilogicR3Destruct,
5666 /* .pfnRelocate = */ NULL,
5667 /* .pfnMemSetup = */ NULL,
5668 /* .pfnPowerOn = */ NULL,
5669 /* .pfnReset = */ lsilogicR3Reset,
5670 /* .pfnSuspend = */ lsilogicR3Suspend,
5671 /* .pfnResume = */ lsilogicR3Resume,
5672 /* .pfnAttach = */ lsilogicR3Attach,
5673 /* .pfnDetach = */ lsilogicR3Detach,
5674 /* .pfnQueryInterface = */ NULL,
5675 /* .pfnInitComplete = */ NULL,
5676 /* .pfnPowerOff = */ lsilogicR3PowerOff,
5677 /* .pfnSoftReset = */ NULL,
5678 /* .pfnReserved0 = */ NULL,
5679 /* .pfnReserved1 = */ NULL,
5680 /* .pfnReserved2 = */ NULL,
5681 /* .pfnReserved3 = */ NULL,
5682 /* .pfnReserved4 = */ NULL,
5683 /* .pfnReserved5 = */ NULL,
5684 /* .pfnReserved6 = */ NULL,
5685 /* .pfnReserved7 = */ NULL,
5686#elif defined(IN_RING0)
5687 /* .pfnEarlyConstruct = */ NULL,
5688 /* .pfnConstruct = */ lsilogicRZConstruct,
5689 /* .pfnDestruct = */ NULL,
5690 /* .pfnFinalDestruct = */ NULL,
5691 /* .pfnRequest = */ NULL,
5692 /* .pfnReserved0 = */ NULL,
5693 /* .pfnReserved1 = */ NULL,
5694 /* .pfnReserved2 = */ NULL,
5695 /* .pfnReserved3 = */ NULL,
5696 /* .pfnReserved4 = */ NULL,
5697 /* .pfnReserved5 = */ NULL,
5698 /* .pfnReserved6 = */ NULL,
5699 /* .pfnReserved7 = */ NULL,
5700#elif defined(IN_RC)
5701 /* .pfnConstruct = */ lsilogicRZConstruct,
5702 /* .pfnReserved0 = */ NULL,
5703 /* .pfnReserved1 = */ NULL,
5704 /* .pfnReserved2 = */ NULL,
5705 /* .pfnReserved3 = */ NULL,
5706 /* .pfnReserved4 = */ NULL,
5707 /* .pfnReserved5 = */ NULL,
5708 /* .pfnReserved6 = */ NULL,
5709 /* .pfnReserved7 = */ NULL,
5710#else
5711# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5712#endif
5713 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5714};
5715
5716#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