VirtualBox

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

Last change on this file since 30382 was 30128, checked in by vboxsync, 15 years ago

LsiLogic: Don't reset the interrupt mask during a unit reset. Fixes older Linux guests (SLES 9 for example) which were hanging in an interrupt loop during initialization of the controller

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