VirtualBox

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

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

Storage: Convert from PDMDATASEG to RTSGSEG to avoid casting between those two in VBoxHDD and more async I/O updates

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