VirtualBox

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

Last change on this file since 84358 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette