VirtualBox

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

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

LsiLogic: Fix memory leak

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

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