VirtualBox

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

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

scm whitespace cleanup

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

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