VirtualBox

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

Last change on this file since 33000 was 32983, checked in by vboxsync, 14 years ago

LsiLogic: Suspend the VM on a recoverable error without changing the saved state format

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

© 2023 Oracle
ContactPrivacy policyTerms of Use