VirtualBox

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

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

warning

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