VirtualBox

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

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

DevLsiLogicSCSI: also register 4 ports for the LSILOGICCTRLTYPE_SCSI_SAS controller

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 225.2 KB
Line 
1/* $Id: DevLsiLogicSCSI.cpp 43665 2012-10-17 11:35:08Z vboxsync $ */
2/** @file
3 * VBox storage devices: LsiLogic LSI53c1030 SCSI controller.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18//#define DEBUG
19#define LOG_GROUP LOG_GROUP_DEV_LSILOGICSCSI
20#include <VBox/vmm/pdmdev.h>
21#include <VBox/vmm/pdmqueue.h>
22#include <VBox/vmm/pdmcritsect.h>
23#include <VBox/scsi.h>
24#include <iprt/assert.h>
25#include <iprt/asm.h>
26#include <iprt/string.h>
27#ifdef IN_RING3
28# include <iprt/memcache.h>
29# include <iprt/mem.h>
30# include <iprt/param.h>
31# include <iprt/uuid.h>
32# include <iprt/time.h>
33#endif
34
35#include "DevLsiLogicSCSI.h"
36#include "VBoxSCSI.h"
37
38#include "VBoxDD.h"
39
40/** The current saved state version. */
41#define LSILOGIC_SAVED_STATE_VERSION 3
42/** The saved state version used by VirtualBox before SAS support was added. */
43#define LSILOGIC_SAVED_STATE_VERSION_PRE_SAS 2
44/** The saved state version used by VirtualBox 3.0 and earlier. It does not
45 * include the device config part. */
46#define LSILOGIC_SAVED_STATE_VERSION_VBOX_30 1
47
48/** Maximum number of entries in the release log. */
49#define MAX_REL_LOG_ERRORS 1024
50
51/**
52 * Reply data.
53 */
54typedef struct LSILOGICSCSIREPLY
55{
56 /** Lower 32 bits of the reply address in memory. */
57 uint32_t u32HostMFALowAddress;
58 /** Full address of the reply in guest memory. */
59 RTGCPHYS GCPhysReplyAddress;
60 /** Size of the reply. */
61 uint32_t cbReply;
62 /** Different views to the reply depending on the request type. */
63 MptReplyUnion Reply;
64} LSILOGICSCSIREPLY, *PLSILOGICSCSIREPLY;
65
66/**
67 * State of a device attached to the buslogic host adapter.
68 *
69 * @implements PDMIBASE
70 * @implements PDMISCSIPORT
71 * @implements PDMILEDPORTS
72 */
73typedef struct LSILOGICDEVICE
74{
75 /** Pointer to the owning lsilogic device instance. - R3 pointer */
76 R3PTRTYPE(struct LSILOGICSCSI *) pLsiLogicR3;
77
78 /** LUN of the device. */
79 RTUINT iLUN;
80 /** Number of outstanding tasks on the port. */
81 volatile uint32_t cOutstandingRequests;
82
83#if HC_ARCH_BITS == 64
84 uint32_t Alignment0;
85#endif
86
87 /** Our base interface. */
88 PDMIBASE IBase;
89 /** SCSI port interface. */
90 PDMISCSIPORT ISCSIPort;
91 /** Led interface. */
92 PDMILEDPORTS ILed;
93 /** Pointer to the attached driver's base interface. */
94 R3PTRTYPE(PPDMIBASE) pDrvBase;
95 /** Pointer to the underlying SCSI connector interface. */
96 R3PTRTYPE(PPDMISCSICONNECTOR) pDrvSCSIConnector;
97 /** The status LED state for this device. */
98 PDMLED Led;
99
100} LSILOGICDEVICE, *PLSILOGICDEVICE;
101
102/** Pointer to a task state. */
103typedef struct LSILOGICTASKSTATE *PLSILOGICTASKSTATE;
104
105/**
106 * Device instance data for the emulated
107 * SCSI controller.
108 */
109typedef struct LSILOGICSCSI
110{
111 /** PCI device structure. */
112 PCIDEVICE PciDev;
113 /** Pointer to the device instance. - R3 ptr. */
114 PPDMDEVINSR3 pDevInsR3;
115 /** Pointer to the device instance. - R0 ptr. */
116 PPDMDEVINSR0 pDevInsR0;
117 /** Pointer to the device instance. - RC ptr. */
118 PPDMDEVINSRC pDevInsRC;
119
120 /** Flag whether the GC part of the device is enabled. */
121 bool fGCEnabled;
122 /** Flag whether the R0 part of the device is enabled. */
123 bool fR0Enabled;
124
125 /** The state the controller is currently in. */
126 LSILOGICSTATE enmState;
127 /** Who needs to init the driver to get into operational state. */
128 LSILOGICWHOINIT enmWhoInit;
129 /** Flag whether we are in doorbell function. */
130 bool fDoorbellInProgress;
131 /** Flag whether diagnostic access is enabled. */
132 bool fDiagnosticEnabled;
133
134 /** Flag whether a notification was send to R3. */
135 bool fNotificationSend;
136
137 /** Flag whether the guest enabled event notification from the IOC. */
138 bool fEventNotificationEnabled;
139
140#if HC_ARCH_BITS == 64
141 uint32_t Alignment0;
142#endif
143
144 /** Queue to send tasks to R3. - R3 ptr */
145 R3PTRTYPE(PPDMQUEUE) pNotificationQueueR3;
146 /** Queue to send tasks to R3. - R0 ptr */
147 R0PTRTYPE(PPDMQUEUE) pNotificationQueueR0;
148 /** Queue to send tasks to R3. - RC ptr */
149 RCPTRTYPE(PPDMQUEUE) pNotificationQueueRC;
150
151#if HC_ARCH_BITS == 64
152 uint32_t Alignment1;
153#endif
154
155 /** Number of device states allocated. */
156 uint32_t cDeviceStates;
157
158#if HC_ARCH_BITS == 64
159 uint32_t Alignment2;
160#endif
161
162 /** States for attached devices. */
163 R3PTRTYPE(PLSILOGICDEVICE) paDeviceStates;
164
165 /** MMIO address the device is mapped to. */
166 RTGCPHYS GCPhysMMIOBase;
167 /** I/O port address the device is mapped to. */
168 RTIOPORT IOPortBase;
169
170 /** Interrupt mask. */
171 volatile uint32_t uInterruptMask;
172 /** Interrupt status register. */
173 volatile uint32_t uInterruptStatus;
174
175 /** Buffer for messages which are passed
176 * through the doorbell using the
177 * handshake method. */
178 uint32_t aMessage[sizeof(MptConfigurationRequest)];
179 /** Actual position in the buffer. */
180 uint32_t iMessage;
181 /** Size of the message which is given in the doorbell message in dwords. */
182 uint32_t cMessage;
183
184 /** Reply buffer. */
185 MptReplyUnion ReplyBuffer;
186 /** Next entry to read. */
187 uint32_t uNextReplyEntryRead;
188 /** Size of the reply in the buffer in 16bit words. */
189 uint32_t cReplySize;
190
191 /** The fault code of the I/O controller if we are in the fault state. */
192 uint16_t u16IOCFaultCode;
193
194 /** Upper 32 bits of the message frame address to locate requests in guest memory. */
195 uint32_t u32HostMFAHighAddr;
196 /** Upper 32 bits of the sense buffer address. */
197 uint32_t u32SenseBufferHighAddr;
198 /** Maximum number of devices the driver reported he can handle. */
199 uint8_t cMaxDevices;
200 /** Maximum number of buses the driver reported he can handle. */
201 uint8_t cMaxBuses;
202 /** Current size of reply message frames in the guest. */
203 uint16_t cbReplyFrame;
204
205 /** Next key to write in the sequence to get access
206 * to diagnostic memory. */
207 uint32_t iDiagnosticAccess;
208
209 /** Number entries allocated for the reply queue. */
210 uint32_t cReplyQueueEntries;
211 /** Number entries allocated for the outstanding request queue. */
212 uint32_t cRequestQueueEntries;
213
214 uint32_t Alignment3;
215
216 /** Critical section protecting the reply post queue. */
217 PDMCRITSECT ReplyPostQueueCritSect;
218 /** Critical section protecting the reply free queue. */
219 PDMCRITSECT ReplyFreeQueueCritSect;
220
221 /** Pointer to the start of the reply free queue - R3. */
222 R3PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR3;
223 /** Pointer to the start of the reply post queue - R3. */
224 R3PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR3;
225 /** Pointer to the start of the request queue - R3. */
226 R3PTRTYPE(volatile uint32_t *) pRequestQueueBaseR3;
227
228 /** Pointer to the start of the reply queue - R0. */
229 R0PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR0;
230 /** Pointer to the start of the reply queue - R0. */
231 R0PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR0;
232 /** Pointer to the start of the request queue - R0. */
233 R0PTRTYPE(volatile uint32_t *) pRequestQueueBaseR0;
234
235 /** Pointer to the start of the reply queue - RC. */
236 RCPTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseRC;
237 /** Pointer to the start of the reply queue - RC. */
238 RCPTRTYPE(volatile uint32_t *) pReplyPostQueueBaseRC;
239 /** Pointer to the start of the request queue - RC. */
240 RCPTRTYPE(volatile uint32_t *) pRequestQueueBaseRC;
241
242 /** Next free entry in the reply queue the guest can write a address to. */
243 volatile uint32_t uReplyFreeQueueNextEntryFreeWrite;
244 /** Next valid entry the controller can read a valid address for reply frames from. */
245 volatile uint32_t uReplyFreeQueueNextAddressRead;
246
247 /** Next free entry in the reply queue the guest can write a address to. */
248 volatile uint32_t uReplyPostQueueNextEntryFreeWrite;
249 /** Next valid entry the controller can read a valid address for reply frames from. */
250 volatile uint32_t uReplyPostQueueNextAddressRead;
251
252 /** Next free entry the guest can write a address to a request frame to. */
253 volatile uint32_t uRequestQueueNextEntryFreeWrite;
254 /** Next valid entry the controller can read a valid address for request frames from. */
255 volatile uint32_t uRequestQueueNextAddressRead;
256
257 /** Emulated controller type */
258 LSILOGICCTRLTYPE enmCtrlType;
259 /** Handle counter */
260 uint16_t u16NextHandle;
261
262 uint16_t u16Alignment4;
263 uint32_t u32Alignment5;
264
265 /** Number of ports this controller has. */
266 uint8_t cPorts;
267
268#if HC_ARCH_BITS == 64
269 uint32_t Alignment6;
270#endif
271
272 /** BIOS emulation. */
273 VBOXSCSI VBoxSCSI;
274 /** Cache for allocated tasks. */
275 R3PTRTYPE(RTMEMCACHE) hTaskCache;
276 /** Status LUN: The base interface. */
277 PDMIBASE IBase;
278 /** Status LUN: Leds interface. */
279 PDMILEDPORTS ILeds;
280 /** Status LUN: Partner of ILeds. */
281 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
282 /** Pointer to the configuration page area. */
283 R3PTRTYPE(PMptConfigurationPagesSupported) pConfigurationPages;
284
285#if HC_ARCH_BITS == 64
286 uint32_t Alignment7;
287#endif
288
289 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
290 * a port is entering the idle state. */
291 bool volatile fSignalIdle;
292 /** Flag whether we have tasks which need to be processed again- */
293 bool volatile fRedo;
294 /** List of tasks which can be redone. */
295 R3PTRTYPE(volatile PLSILOGICTASKSTATE) pTasksRedoHead;
296
297} LSILOGISCSI, *PLSILOGICSCSI;
298
299/**
300 * Scatter gather list entry data.
301 */
302typedef struct LSILOGICTASKSTATESGENTRY
303{
304 /** Flag whether the buffer in the list is from the guest or an
305 * allocated temporary buffer because the segments in the guest
306 * are not sector aligned.
307 */
308 bool fGuestMemory;
309 /** Flag whether the buffer contains data or is the destination for the transfer. */
310 bool fBufferContainsData;
311 /** Pointer to the start of the buffer. */
312 void *pvBuf;
313 /** Size of the buffer. */
314 uint32_t cbBuf;
315 /** Flag dependent data. */
316 union
317 {
318 /** Data to handle direct mappings of guest buffers. */
319 PGMPAGEMAPLOCK PageLock;
320 /** The segment in the guest which is not sector aligned. */
321 RTGCPHYS GCPhysAddrBufferUnaligned;
322 } u;
323} LSILOGICTASKSTATESGENTRY, *PLSILOGICTASKSTATESGENTRY;
324
325/**
326 * Task state object which holds all necessary data while
327 * processing the request from the guest.
328 */
329typedef struct LSILOGICTASKSTATE
330{
331 /** Next in the redo list. */
332 PLSILOGICTASKSTATE pRedoNext;
333 /** Target device. */
334 PLSILOGICDEVICE pTargetDevice;
335 /** The message request from the guest. */
336 MptRequestUnion GuestRequest;
337 /** Reply message if the request produces one. */
338 MptReplyUnion IOCReply;
339 /** SCSI request structure for the SCSI driver. */
340 PDMSCSIREQUEST PDMScsiRequest;
341 /** Address of the message request frame in guests memory.
342 * Used to read the S/G entries in the second step. */
343 RTGCPHYS GCPhysMessageFrameAddr;
344 /** Number of scatter gather list entries. */
345 uint32_t cSGListEntries;
346 /** How many entries would fit into the sg list. */
347 uint32_t cSGListSize;
348 /** How many times the list was too big. */
349 uint32_t cSGListTooBig;
350 /** Pointer to the first entry of the scatter gather list. */
351 PRTSGSEG pSGListHead;
352 /** How many entries would fit into the sg info list. */
353 uint32_t cSGInfoSize;
354 /** Number of entries for the information entries. */
355 uint32_t cSGInfoEntries;
356 /** How many times the list was too big. */
357 uint32_t cSGInfoTooBig;
358 /** Pointer to the first mapping information entry. */
359 PLSILOGICTASKSTATESGENTRY paSGEntries;
360 /** Size of the temporary buffer for unaligned guest segments. */
361 uint32_t cbBufferUnaligned;
362 /** Pointer to the temporary buffer. */
363 void *pvBufferUnaligned;
364 /** Pointer to the sense buffer. */
365 uint8_t abSenseBuffer[18];
366 /** Flag whether the request was issued from the BIOS. */
367 bool fBIOS;
368} LSILOGICTASKSTATE;
369
370#ifndef VBOX_DEVICE_STRUCT_TESTCASE
371
372RT_C_DECLS_BEGIN
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_R3_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_R3_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_R3_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_R3_MMIO_WRITE)
1307 rc = VINF_IOM_R3_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_R3_MMIO_READ)
1322 rc = VINF_IOM_R3_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, rcCompletion);
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_BIOS_IO_PORT
3672 : Port - LSILOGIC_SAS_BIOS_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, SCSI_STATUS_OK);
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_BIOS_IO_PORT
3761 : Port - LSILOGIC_SAS_BIOS_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_BIOS_IO_PORT
3788 : Port - LSILOGIC_SAS_BIOS_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_BIOS_IO_PORT
3815 : Port - LSILOGIC_SAS_BIOS_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, NIL_RTR0PTR /*pvUser*/,
3852 "lsilogicMMIOWrite", "lsilogicMMIORead");
3853 if (RT_FAILURE(rc))
3854 return rc;
3855 }
3856
3857 if (pThis->fGCEnabled)
3858 {
3859 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
3860 "lsilogicMMIOWrite", "lsilogicMMIORead");
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, NIL_RTR0PTR /*pvUser*/,
3879 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead");
3880 if (RT_FAILURE(rc))
3881 return rc;
3882 }
3883
3884 if (pThis->fGCEnabled)
3885 {
3886 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
3887 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead");
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_BIOS_IO_PORT, 4, NULL,
5233 lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead,
5234 lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr,
5235 "LsiLogic BIOS");
5236 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
5237 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_SAS_BIOS_IO_PORT, 4, 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 ~0U,
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 PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION,
5350 /* fClass */
5351 PDM_DEVREG_CLASS_STORAGE,
5352 /* cMaxInstances */
5353 ~0U,
5354 /* cbInstance */
5355 sizeof(LSILOGICSCSI),
5356 /* pfnConstruct */
5357 lsilogicConstruct,
5358 /* pfnDestruct */
5359 lsilogicDestruct,
5360 /* pfnRelocate */
5361 lsilogicRelocate,
5362 /* pfnIOCtl */
5363 NULL,
5364 /* pfnPowerOn */
5365 NULL,
5366 /* pfnReset */
5367 lsilogicReset,
5368 /* pfnSuspend */
5369 lsilogicSuspend,
5370 /* pfnResume */
5371 lsilogicResume,
5372 /* pfnAttach */
5373 lsilogicAttach,
5374 /* pfnDetach */
5375 lsilogicDetach,
5376 /* pfnQueryInterface. */
5377 NULL,
5378 /* pfnInitComplete */
5379 NULL,
5380 /* pfnPowerOff */
5381 lsilogicPowerOff,
5382 /* pfnSoftReset */
5383 NULL,
5384 /* u32VersionEnd */
5385 PDM_DEVREG_VERSION
5386};
5387
5388#endif /* IN_RING3 */
5389#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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