VirtualBox

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

Last change on this file since 45025 was 45025, checked in by vboxsync, 12 years ago

Update PDMDEVREG initialization comment so they refer to pfnMemSetup instead of pfnIOCtl.

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