VirtualBox

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

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

Changed PDMDevHlpMMIORegister to take flags and drop pfnFill. Added PDMDevHlpMMIORegisterEx for the one user of pfnFill.

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

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