VirtualBox

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

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

DevLsiLogicSCSI.cpp: not about why 2 items are used (insert while consuming because the flag is cleared (early) in the consumer).

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