VirtualBox

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

Last change on this file since 37596 was 37466, checked in by vboxsync, 13 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 225.8 KB
Line 
1/* $Id: DevLsiLogicSCSI.cpp 37466 2011-06-15 12:44:16Z 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/vmm/pdmdev.h>
21#include <VBox/vmm/pdmqueue.h>
22#include <VBox/vmm/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 "VBoxDD.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];
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-%u",
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 char szTaggedText[64];
5121 RTStrPrintf(szTaggedText, sizeof(szTaggedText), "%s-Task", szDevTag);
5122 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 2, 0,
5123 lsilogicNotifyQueueConsumer, true,
5124 szTaggedText,
5125 &pThis->pNotificationQueueR3);
5126 if (RT_FAILURE(rc))
5127 return rc;
5128 pThis->pNotificationQueueR0 = PDMQueueR0Ptr(pThis->pNotificationQueueR3);
5129 pThis->pNotificationQueueRC = PDMQueueRCPtr(pThis->pNotificationQueueR3);
5130
5131 /*
5132 * We need one entry free in the queue.
5133 */
5134 pThis->cReplyQueueEntries++;
5135 pThis->cRequestQueueEntries++;
5136
5137 /*
5138 * Allocate memory for the queues.
5139 */
5140 rc = lsilogicQueuesAlloc(pThis);
5141 if (RT_FAILURE(rc))
5142 return rc;
5143
5144 /*
5145 * Create critical sections protecting the reply post and free queues.
5146 */
5147 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS, "%sRFQ", szDevTag);
5148 if (RT_FAILURE(rc))
5149 return PDMDEV_SET_ERROR(pDevIns, rc,
5150 N_("LsiLogic: cannot create critical section for reply free queue"));
5151
5152 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS, "%sRPQ", szDevTag);
5153 if (RT_FAILURE(rc))
5154 return PDMDEV_SET_ERROR(pDevIns, rc,
5155 N_("LsiLogic: cannot create critical section for reply post queue"));
5156
5157 /*
5158 * Allocate task cache.
5159 */
5160 rc = RTMemCacheCreate(&pThis->hTaskCache, sizeof(LSILOGICTASKSTATE), 0, UINT32_MAX,
5161 lsilogicTaskStateCtor, lsilogicTaskStateDtor, NULL, 0);
5162 if (RT_FAILURE(rc))
5163 return PDMDEV_SET_ERROR(pDevIns, rc,
5164 N_("Cannot create task cache"));
5165
5166 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5167 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
5168 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5169 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
5170 else
5171 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
5172
5173 /*
5174 * Allocate device states.
5175 */
5176 pThis->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
5177 if (!pThis->paDeviceStates)
5178 return PDMDEV_SET_ERROR(pDevIns, rc,
5179 N_("Failed to allocate memory for device states"));
5180
5181 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
5182 {
5183 char szName[24];
5184 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
5185
5186 /* Initialize static parts of the device. */
5187 pDevice->iLUN = i;
5188 pDevice->pLsiLogicR3 = pThis;
5189 pDevice->Led.u32Magic = PDMLED_MAGIC;
5190 pDevice->IBase.pfnQueryInterface = lsilogicDeviceQueryInterface;
5191 pDevice->ISCSIPort.pfnSCSIRequestCompleted = lsilogicDeviceSCSIRequestCompleted;
5192 pDevice->ISCSIPort.pfnQueryDeviceLocation = lsilogicQueryDeviceLocation;
5193 pDevice->ILed.pfnQueryStatusLed = lsilogicDeviceQueryStatusLed;
5194
5195 RTStrPrintf(szName, sizeof(szName), "Device%d", i);
5196
5197 /* Attach SCSI driver. */
5198 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, szName);
5199 if (RT_SUCCESS(rc))
5200 {
5201 /* Get SCSI connector interface. */
5202 pDevice->pDrvSCSIConnector = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMISCSICONNECTOR);
5203 AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
5204 }
5205 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
5206 {
5207 pDevice->pDrvBase = NULL;
5208 rc = VINF_SUCCESS;
5209 Log(("LsiLogic: no driver attached to device %s\n", szName));
5210 }
5211 else
5212 {
5213 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", szName));
5214 return rc;
5215 }
5216 }
5217
5218 /*
5219 * Attach status driver (optional).
5220 */
5221 PPDMIBASE pBase;
5222 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
5223 if (RT_SUCCESS(rc))
5224 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5225 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
5226 {
5227 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5228 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver"));
5229 }
5230
5231 /* Initialize the SCSI emulation for the BIOS. */
5232 rc = vboxscsiInitialize(&pThis->VBoxSCSI);
5233 AssertRC(rc);
5234
5235 /*
5236 * Register I/O port space in ISA region for BIOS access
5237 * if the controller is marked as bootable.
5238 */
5239 if (fBootable)
5240 {
5241 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
5242 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_ISA_IO_PORT, 3, NULL,
5243 lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead,
5244 lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr,
5245 "LsiLogic BIOS");
5246 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5247 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_SAS_ISA_IO_PORT, 3, NULL,
5248 lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead,
5249 lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr,
5250 "LsiLogic SAS BIOS");
5251 else
5252 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
5253
5254 if (RT_FAILURE(rc))
5255 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register legacy I/O handlers"));
5256 }
5257
5258 /* Register save state handlers. */
5259 rc = PDMDevHlpSSMRegisterEx(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
5260 NULL, lsilogicLiveExec, NULL,
5261 NULL, lsilogicSaveExec, NULL,
5262 NULL, lsilogicLoadExec, lsilogicLoadDone);
5263 if (RT_FAILURE(rc))
5264 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
5265
5266 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
5267
5268 /*
5269 * Register the info item.
5270 */
5271 char szTmp[128];
5272 RTStrPrintf(szTmp, sizeof(szTmp), "%s%d", pDevIns->pReg->szName, pDevIns->iInstance);
5273 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp,
5274 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
5275 ? "LsiLogic SPI info."
5276 : "LsiLogic SAS info.", lsilogicInfo);
5277
5278 /* Perform hard reset. */
5279 rc = lsilogicHardReset(pThis);
5280 AssertRC(rc);
5281
5282 return rc;
5283}
5284
5285/**
5286 * The device registration structure - SPI SCSI controller.
5287 */
5288const PDMDEVREG g_DeviceLsiLogicSCSI =
5289{
5290 /* u32Version */
5291 PDM_DEVREG_VERSION,
5292 /* szName */
5293 "lsilogicscsi",
5294 /* szRCMod */
5295 "VBoxDDGC.gc",
5296 /* szR0Mod */
5297 "VBoxDDR0.r0",
5298 /* pszDescription */
5299 "LSI Logic 53c1030 SCSI controller.\n",
5300 /* fFlags */
5301 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
5302 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
5303 /* fClass */
5304 PDM_DEVREG_CLASS_STORAGE,
5305 /* cMaxInstances */
5306 ~0,
5307 /* cbInstance */
5308 sizeof(LSILOGICSCSI),
5309 /* pfnConstruct */
5310 lsilogicConstruct,
5311 /* pfnDestruct */
5312 lsilogicDestruct,
5313 /* pfnRelocate */
5314 lsilogicRelocate,
5315 /* pfnIOCtl */
5316 NULL,
5317 /* pfnPowerOn */
5318 NULL,
5319 /* pfnReset */
5320 lsilogicReset,
5321 /* pfnSuspend */
5322 lsilogicSuspend,
5323 /* pfnResume */
5324 lsilogicResume,
5325 /* pfnAttach */
5326 lsilogicAttach,
5327 /* pfnDetach */
5328 lsilogicDetach,
5329 /* pfnQueryInterface. */
5330 NULL,
5331 /* pfnInitComplete */
5332 NULL,
5333 /* pfnPowerOff */
5334 lsilogicPowerOff,
5335 /* pfnSoftReset */
5336 NULL,
5337 /* u32VersionEnd */
5338 PDM_DEVREG_VERSION
5339};
5340
5341/**
5342 * The device registration structure - SAS controller.
5343 */
5344const PDMDEVREG g_DeviceLsiLogicSAS =
5345{
5346 /* u32Version */
5347 PDM_DEVREG_VERSION,
5348 /* szName */
5349 "lsilogicsas",
5350 /* szRCMod */
5351 "VBoxDDGC.gc",
5352 /* szR0Mod */
5353 "VBoxDDR0.r0",
5354 /* pszDescription */
5355 "LSI Logic SAS1068 controller.\n",
5356 /* fFlags */
5357 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
5358 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
5359 /* fClass */
5360 PDM_DEVREG_CLASS_STORAGE,
5361 /* cMaxInstances */
5362 ~0,
5363 /* cbInstance */
5364 sizeof(LSILOGICSCSI),
5365 /* pfnConstruct */
5366 lsilogicConstruct,
5367 /* pfnDestruct */
5368 lsilogicDestruct,
5369 /* pfnRelocate */
5370 lsilogicRelocate,
5371 /* pfnIOCtl */
5372 NULL,
5373 /* pfnPowerOn */
5374 NULL,
5375 /* pfnReset */
5376 lsilogicReset,
5377 /* pfnSuspend */
5378 lsilogicSuspend,
5379 /* pfnResume */
5380 lsilogicResume,
5381 /* pfnAttach */
5382 lsilogicAttach,
5383 /* pfnDetach */
5384 lsilogicDetach,
5385 /* pfnQueryInterface. */
5386 NULL,
5387 /* pfnInitComplete */
5388 NULL,
5389 /* pfnPowerOff */
5390 lsilogicPowerOff,
5391 /* pfnSoftReset */
5392 NULL,
5393 /* u32VersionEnd */
5394 PDM_DEVREG_VERSION
5395};
5396
5397#endif /* IN_RING3 */
5398#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