VirtualBox

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

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

Storage: Introduce interface to query the location of a medium (device + instance + LUN) in a VM to generate IDs which are constant for saved states

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