VirtualBox

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

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

LsiLogic: The request queue should have the same size as the reply queue or we risk overwriting completed requests by others causing timeouts in the guest

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 206.9 KB
Line 
1/* $Id: DevLsiLogicSCSI.cpp 29588 2010-05-17 22:32:29Z vboxsync $ */
2/** @file
3 * VBox storage devices: LsiLogic LSI53c1030 SCSI controller.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18//#define DEBUG
19#define LOG_GROUP LOG_GROUP_DEV_LSILOGICSCSI
20#include <VBox/pdmdev.h>
21#include <VBox/pdmqueue.h>
22#include <VBox/pdmcritsect.h>
23#include <VBox/scsi.h>
24#include <iprt/assert.h>
25#include <iprt/asm.h>
26#include <iprt/string.h>
27#ifdef IN_RING3
28# include <iprt/memcache.h>
29# include <iprt/mem.h>
30# include <iprt/param.h>
31# include <iprt/uuid.h>
32#endif
33
34#include "DevLsiLogicSCSI.h"
35#include "VBoxSCSI.h"
36
37#include "../Builtins.h"
38
39/** The current saved state version. */
40#define LSILOGIC_SAVED_STATE_VERSION 3
41/** The saved state version used by VirtualBox before SAS support was added. */
42#define LSILOGIC_SAVED_STATE_VERSION_PRE_SAS 2
43/** The saved state version used by VirtualBox 3.0 and earlier. It does not
44 * include the device config part. */
45#define LSILOGIC_SAVED_STATE_VERSION_VBOX_30 1
46
47/**
48 * Reply data.
49 */
50typedef struct LSILOGICSCSIREPLY
51{
52 /** Lower 32 bits of the reply address in memory. */
53 uint32_t u32HostMFALowAddress;
54 /** Full address of the reply in guest memory. */
55 RTGCPHYS GCPhysReplyAddress;
56 /** Size of the reply. */
57 uint32_t cbReply;
58 /** Different views to the reply depending on the request type. */
59 MptReplyUnion Reply;
60} LSILOGICSCSIREPLY, *PLSILOGICSCSIREPLY;
61
62/**
63 * State of a device attached to the buslogic host adapter.
64 *
65 * @implements PDMIBASE
66 * @implements PDMISCSIPORT
67 * @implements PDMILEDPORTS
68 */
69typedef struct LSILOGICDEVICE
70{
71 /** Pointer to the owning lsilogic device instance. - R3 pointer */
72 R3PTRTYPE(struct LSILOGICSCSI *) pLsiLogicR3;
73
74 /** LUN of the device. */
75 RTUINT iLUN;
76 /** Number of outstanding tasks on the port. */
77 volatile uint32_t cOutstandingRequests;
78
79#if HC_ARCH_BITS == 64
80 uint32_t Alignment0;
81#endif
82
83 /** Our base interace. */
84 PDMIBASE IBase;
85 /** SCSI port interface. */
86 PDMISCSIPORT ISCSIPort;
87 /** Led interface. */
88 PDMILEDPORTS ILed;
89 /** Pointer to the attached driver's base interface. */
90 R3PTRTYPE(PPDMIBASE) pDrvBase;
91 /** Pointer to the underlying SCSI connector interface. */
92 R3PTRTYPE(PPDMISCSICONNECTOR) pDrvSCSIConnector;
93 /** The status LED state for this device. */
94 PDMLED Led;
95
96} LSILOGICDEVICE, *PLSILOGICDEVICE;
97
98/**
99 * Device instance data for the emulated
100 * SCSI controller.
101 */
102typedef struct LSILOGICSCSI
103{
104 /** PCI device structure. */
105 PCIDEVICE PciDev;
106 /** Pointer to the device instance. - R3 ptr. */
107 PPDMDEVINSR3 pDevInsR3;
108 /** Pointer to the device instance. - R0 ptr. */
109 PPDMDEVINSR0 pDevInsR0;
110 /** Pointer to the device instance. - RC ptr. */
111 PPDMDEVINSRC pDevInsRC;
112
113 /** Flag whether the GC part of the device is enabled. */
114 bool fGCEnabled;
115 /** Flag whether the R0 part of the device is enabled. */
116 bool fR0Enabled;
117
118 /** The state the controller is currently in. */
119 LSILOGICSTATE enmState;
120 /** Who needs to init the driver to get into operational state. */
121 LSILOGICWHOINIT enmWhoInit;
122 /** Flag whether we are in doorbell function. */
123 bool fDoorbellInProgress;
124 /** Flag whether diagnostic access is enabled. */
125 bool fDiagnosticEnabled;
126
127 /** Flag whether a notification was send to R3. */
128 bool fNotificationSend;
129
130 /** Flag whether the guest enabled event notification from the IOC. */
131 bool fEventNotificationEnabled;
132
133#if HC_ARCH_BITS == 64
134 uint32_t Alignment0;
135#endif
136
137 /** Queue to send tasks to R3. - R3 ptr */
138 R3PTRTYPE(PPDMQUEUE) pNotificationQueueR3;
139 /** Queue to send tasks to R3. - R0 ptr */
140 R0PTRTYPE(PPDMQUEUE) pNotificationQueueR0;
141 /** Queue to send tasks to R3. - RC ptr */
142 RCPTRTYPE(PPDMQUEUE) pNotificationQueueRC;
143
144#if HC_ARCH_BITS == 64
145 uint32_t Alignment1;
146#endif
147
148 /** Number of device states allocated. */
149 uint32_t cDeviceStates;
150
151#if HC_ARCH_BITS == 64
152 uint32_t Alignment2;
153#endif
154
155 /** States for attached devices. */
156 R3PTRTYPE(PLSILOGICDEVICE) paDeviceStates;
157
158 /** MMIO address the device is mapped to. */
159 RTGCPHYS GCPhysMMIOBase;
160 /** I/O port address the device is mapped to. */
161 RTIOPORT IOPortBase;
162
163 /** Interrupt mask. */
164 volatile uint32_t uInterruptMask;
165 /** Interrupt status register. */
166 volatile uint32_t uInterruptStatus;
167
168 /** Buffer for messages which are passed
169 * through the doorbell using the
170 * handshake method. */
171 uint32_t aMessage[sizeof(MptConfigurationRequest)];
172 /** Actual position in the buffer. */
173 uint32_t iMessage;
174 /** Size of the message which is given in the doorbell message in dwords. */
175 uint32_t cMessage;
176
177 /** Reply buffer. */
178 MptReplyUnion ReplyBuffer;
179 /** Next entry to read. */
180 uint32_t uNextReplyEntryRead;
181 /** Size of the reply in the buffer in 16bit words. */
182 uint32_t cReplySize;
183
184 /** The fault code of the I/O controller if we are in the fault state. */
185 uint16_t u16IOCFaultCode;
186
187 /** Upper 32 bits of the message frame address to locate requests in guest memory. */
188 uint32_t u32HostMFAHighAddr;
189 /** Upper 32 bits of the sense buffer address. */
190 uint32_t u32SenseBufferHighAddr;
191 /** Maximum number of devices the driver reported he can handle. */
192 uint8_t cMaxDevices;
193 /** Maximum number of buses the driver reported he can handle. */
194 uint8_t cMaxBuses;
195 /** Current size of reply message frames in the guest. */
196 uint16_t cbReplyFrame;
197
198 /** Next key to write in the sequence to get access
199 * to diagnostic memory. */
200 uint32_t iDiagnosticAccess;
201
202 /** Number entries allocated for the reply queue. */
203 uint32_t cReplyQueueEntries;
204 /** Number entries allocated for the outstanding request queue. */
205 uint32_t cRequestQueueEntries;
206
207 uint32_t Alignment3;
208
209 /** Critical section protecting the reply post queue. */
210 PDMCRITSECT ReplyPostQueueCritSect;
211 /** Critical section protecting the reply free queue. */
212 PDMCRITSECT ReplyFreeQueueCritSect;
213
214 /** Pointer to the start of the reply free queue - R3. */
215 R3PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR3;
216 /** Pointer to the start of the reply post queue - R3. */
217 R3PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR3;
218 /** Pointer to the start of the request queue - R3. */
219 R3PTRTYPE(volatile uint32_t *) pRequestQueueBaseR3;
220
221 /** Pointer to the start of the reply queue - R0. */
222 R0PTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseR0;
223 /** Pointer to the start of the reply queue - R0. */
224 R0PTRTYPE(volatile uint32_t *) pReplyPostQueueBaseR0;
225 /** Pointer to the start of the request queue - R0. */
226 R0PTRTYPE(volatile uint32_t *) pRequestQueueBaseR0;
227
228 /** Pointer to the start of the reply queue - RC. */
229 RCPTRTYPE(volatile uint32_t *) pReplyFreeQueueBaseRC;
230 /** Pointer to the start of the reply queue - RC. */
231 RCPTRTYPE(volatile uint32_t *) pReplyPostQueueBaseRC;
232 /** Pointer to the start of the request queue - RC. */
233 RCPTRTYPE(volatile uint32_t *) pRequestQueueBaseRC;
234
235 /** Next free entry in the reply queue the guest can write a address to. */
236 volatile uint32_t uReplyFreeQueueNextEntryFreeWrite;
237 /** Next valid entry the controller can read a valid address for reply frames from. */
238 volatile uint32_t uReplyFreeQueueNextAddressRead;
239
240 /** Next free entry in the reply queue the guest can write a address to. */
241 volatile uint32_t uReplyPostQueueNextEntryFreeWrite;
242 /** Next valid entry the controller can read a valid address for reply frames from. */
243 volatile uint32_t uReplyPostQueueNextAddressRead;
244
245 /** Next free entry the guest can write a address to a request frame to. */
246 volatile uint32_t uRequestQueueNextEntryFreeWrite;
247 /** Next valid entry the controller can read a valid address for request frames from. */
248 volatile uint32_t uRequestQueueNextAddressRead;
249
250 /** Emulated controller type */
251 LSILOGICCTRLTYPE enmCtrlType;
252 /** Handle counter */
253 uint16_t u16NextHandle;
254
255 uint16_t u16Alignment4;
256 uint32_t u32Alignment5;
257
258 /** Number of ports this controller has. */
259 uint8_t cPorts;
260
261#if HC_ARCH_BITS == 64
262 uint32_t Alignment6;
263#endif
264
265 /** BIOS emulation. */
266 VBOXSCSI VBoxSCSI;
267 /** Cache for allocated tasks. */
268 R3PTRTYPE(RTMEMCACHE) hTaskCache;
269 /** Status LUN: The base interface. */
270 PDMIBASE IBase;
271 /** Status LUN: Leds interface. */
272 PDMILEDPORTS ILeds;
273 /** Status LUN: Partner of ILeds. */
274 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
275
276 R3PTRTYPE(PMptConfigurationPagesSupported) pConfigurationPages;
277} LSILOGISCSI, *PLSILOGICSCSI;
278
279/**
280 * Scatter gather list entry data.
281 */
282typedef struct LSILOGICTASKSTATESGENTRY
283{
284 /** Flag whether the buffer in the list is from the guest or an
285 * allocated temporary buffer because the segments in the guest
286 * are not sector aligned.
287 */
288 bool fGuestMemory;
289 /** Flag whether the buffer contains data or is the destination for the transfer. */
290 bool fBufferContainsData;
291 /** Pointer to the start of the buffer. */
292 void *pvBuf;
293 /** Size of the buffer. */
294 uint32_t cbBuf;
295 /** Flag dependent data. */
296 union
297 {
298 /** Data to handle direct mappings of guest buffers. */
299 PGMPAGEMAPLOCK PageLock;
300 /** The segment in the guest which is not sector aligned. */
301 RTGCPHYS GCPhysAddrBufferUnaligned;
302 } u;
303} LSILOGICTASKSTATESGENTRY, *PLSILOGICTASKSTATESGENTRY;
304
305/**
306 * Task state object which holds all neccessary data while
307 * processing the request from the guest.
308 */
309typedef struct LSILOGICTASKSTATE
310{
311 /** Target device. */
312 PLSILOGICDEVICE pTargetDevice;
313 /** The message request from the guest. */
314 MptRequestUnion GuestRequest;
315 /** Reply message if the request produces one. */
316 MptReplyUnion IOCReply;
317 /** SCSI request structure for the SCSI driver. */
318 PDMSCSIREQUEST PDMScsiRequest;
319 /** Address of the message request frame in guests memory.
320 * Used to read the S/G entries in the second step. */
321 RTGCPHYS GCPhysMessageFrameAddr;
322 /** Number of scatter gather list entries. */
323 uint32_t cSGListEntries;
324 /** How many entries would fit into the sg list. */
325 uint32_t cSGListSize;
326 /** How many times the list was too big. */
327 uint32_t cSGListTooBig;
328 /** Pointer to the first entry of the scatter gather list. */
329 PRTSGSEG pSGListHead;
330 /** How many entries would fit into the sg info list. */
331 uint32_t cSGInfoSize;
332 /** Number of entries for the information entries. */
333 uint32_t cSGInfoEntries;
334 /** How many times the list was too big. */
335 uint32_t cSGInfoTooBig;
336 /** Pointer to the first mapping information entry. */
337 PLSILOGICTASKSTATESGENTRY paSGEntries;
338 /** Size of the temporary buffer for unaligned guest segments. */
339 uint32_t cbBufferUnaligned;
340 /** Pointer to the temporary buffer. */
341 void *pvBufferUnaligned;
342 /** Pointer to the sense buffer. */
343 uint8_t abSenseBuffer[18];
344 /** Flag whether the request was issued from the BIOS. */
345 bool fBIOS;
346} LSILOGICTASKSTATE, *PLSILOGICTASKSTATE;
347
348#ifndef VBOX_DEVICE_STRUCT_TESTCASE
349
350RT_C_DECLS_BEGIN
351PDMBOTHCBDECL(int) lsilogicIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
352 RTIOPORT Port, uint32_t u32, unsigned cb);
353PDMBOTHCBDECL(int) lsilogicIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
354 RTIOPORT Port, uint32_t *pu32, unsigned cb);
355PDMBOTHCBDECL(int) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
356 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
357PDMBOTHCBDECL(int) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser,
358 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
359PDMBOTHCBDECL(int) lsilogicDiagnosticWrite(PPDMDEVINS pDevIns, void *pvUser,
360 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
361PDMBOTHCBDECL(int) lsilogicDiagnosticRead(PPDMDEVINS pDevIns, void *pvUser,
362 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
363#ifdef IN_RING3
364static void lsilogicInitializeConfigurationPages(PLSILOGICSCSI pLsiLogic);
365static void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis);
366static int lsilogicProcessConfigurationRequest(PLSILOGICSCSI pLsiLogic, PMptConfigurationRequest pConfigurationReq,
367 PMptConfigurationReply pReply);
368#endif
369RT_C_DECLS_END
370
371#define PDMIBASE_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, IBase)) )
372#define PDMISCSIPORT_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ISCSIPort)) )
373#define PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface) ( (PLSILOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICDEVICE, ILed)) )
374#define LSILOGIC_RTGCPHYS_FROM_U32(Hi, Lo) ( (RTGCPHYS)RT_MAKE_U64(Lo, Hi) )
375#define PDMIBASE_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, IBase)) )
376#define PDMILEDPORTS_2_PLSILOGICSCSI(pInterface) ( (PLSILOGICSCSI)((uintptr_t)(pInterface) - RT_OFFSETOF(LSILOGICSCSI, ILeds)) )
377
378/** Key sequence the guest has to write to enable access
379 * to diagnostic memory. */
380static const uint8_t g_lsilogicDiagnosticAccess[] = {0x04, 0x0b, 0x02, 0x07, 0x0d};
381
382/**
383 * Updates the status of the interrupt pin of the device.
384 *
385 * @returns nothing.
386 * @param pThis Pointer to the device instance data.
387 */
388static void lsilogicUpdateInterrupt(PLSILOGICSCSI pThis)
389{
390 uint32_t uIntSts;
391
392 LogFlowFunc(("Updating interrupts\n"));
393
394 /* Mask out doorbell status so that it does not affect interrupt updating. */
395 uIntSts = (ASMAtomicReadU32(&pThis->uInterruptStatus) & ~LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS);
396 /* Check maskable interrupts. */
397 uIntSts &= ~(pThis->uInterruptMask & ~LSILOGIC_REG_HOST_INTR_MASK_IRQ_ROUTING);
398
399 if (uIntSts)
400 {
401 LogFlowFunc(("Setting interrupt\n"));
402 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1);
403 }
404 else
405 {
406 LogFlowFunc(("Clearing interrupt\n"));
407 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0);
408 }
409}
410
411/**
412 * Sets a given interrupt status bit in the status register and
413 * updates the interupt status.
414 *
415 * @returns nothing.
416 * @param pLsiLogic Pointer to the device instance.
417 * @param uStatus The status bit to set.
418 */
419DECLINLINE(void) lsilogicSetInterrupt(PLSILOGICSCSI pLsiLogic, uint32_t uStatus)
420{
421 ASMAtomicOrU32(&pLsiLogic->uInterruptStatus, uStatus);
422 lsilogicUpdateInterrupt(pLsiLogic);
423}
424
425/**
426 * Clears a given interrupt status bit in the status register and
427 * updates the interupt status.
428 *
429 * @returns nothing.
430 * @param pLsiLogic Pointer to the device instance.
431 * @param uStatus The status bit to set.
432 */
433DECLINLINE(void) lsilogicClearInterrupt(PLSILOGICSCSI pLsiLogic, uint32_t uStatus)
434{
435 ASMAtomicAndU32(&pLsiLogic->uInterruptStatus, ~uStatus);
436 lsilogicUpdateInterrupt(pLsiLogic);
437}
438
439/**
440 * Sets the I/O controller into fault state and sets the fault code.
441 *
442 * @returns nothing
443 * @param pLsiLogic Pointer to the controller device instance.
444 * @param uIOCFaultCode Fault code to set.
445 */
446DECLINLINE(void) lsilogicSetIOCFaultCode(PLSILOGICSCSI pLsiLogic, uint16_t uIOCFaultCode)
447{
448 if (pLsiLogic->enmState != LSILOGICSTATE_FAULT)
449 {
450 Log(("%s: Setting I/O controller into FAULT state: uIOCFaultCode=%u\n", __FUNCTION__, uIOCFaultCode));
451 pLsiLogic->enmState = LSILOGICSTATE_FAULT;
452 pLsiLogic->u16IOCFaultCode = uIOCFaultCode;
453 }
454 else
455 {
456 Log(("%s: We are already in FAULT state\n"));
457 }
458}
459
460#ifdef IN_RING3
461/**
462 * Performs a hard reset on the controller.
463 *
464 * @returns VBox status code.
465 * @param pThis Pointer to the device instance to initialize.
466 */
467static int lsilogicHardReset(PLSILOGICSCSI pThis)
468{
469 pThis->enmState = LSILOGICSTATE_RESET;
470
471 /* The interrupts are masked out. */
472 pThis->uInterruptMask |= LSILOGIC_REG_HOST_INTR_MASK_DOORBELL |
473 LSILOGIC_REG_HOST_INTR_MASK_REPLY;
474 /* Reset interrupt states. */
475 pThis->uInterruptStatus = 0;
476 lsilogicUpdateInterrupt(pThis);
477
478 /* Reset the queues. */
479 pThis->uReplyFreeQueueNextEntryFreeWrite = 0;
480 pThis->uReplyFreeQueueNextAddressRead = 0;
481 pThis->uReplyPostQueueNextEntryFreeWrite = 0;
482 pThis->uReplyPostQueueNextAddressRead = 0;
483 pThis->uRequestQueueNextEntryFreeWrite = 0;
484 pThis->uRequestQueueNextAddressRead = 0;
485
486 /* Disable diagnostic access. */
487 pThis->iDiagnosticAccess = 0;
488
489 /* Set default values. */
490 pThis->cMaxDevices = pThis->cDeviceStates;
491 pThis->cMaxBuses = 1;
492 pThis->cbReplyFrame = 128; /* @todo Figure out where it is needed. */
493 pThis->u16NextHandle = 1;
494 /** @todo: Put stuff to reset here. */
495
496 lsilogicConfigurationPagesFree(pThis);
497 lsilogicInitializeConfigurationPages(pThis);
498
499 /* Mark that we finished performing the reset. */
500 pThis->enmState = LSILOGICSTATE_READY;
501 return VINF_SUCCESS;
502}
503
504/**
505 * Frees the configuration pages if allocated.
506 *
507 * @returns nothing.
508 * @param pThis The LsiLogic controller instance
509 */
510static void lsilogicConfigurationPagesFree(PLSILOGICSCSI pThis)
511{
512
513 if (pThis->pConfigurationPages)
514 {
515 /* Destroy device list if we emulate a SAS controller. */
516 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
517 {
518 PMptConfigurationPagesSas pSasPages = &pThis->pConfigurationPages->u.SasPages;
519 PMptSASDevice pSASDeviceCurr = pSasPages->pSASDeviceHead;
520
521 while (pSASDeviceCurr)
522 {
523 PMptSASDevice pFree = pSASDeviceCurr;
524
525 pSASDeviceCurr = pSASDeviceCurr->pNext;
526 RTMemFree(pFree);
527 }
528 if (pSasPages->paPHYs)
529 RTMemFree(pSasPages->paPHYs);
530 if (pSasPages->pManufacturingPage7)
531 RTMemFree(pSasPages->pManufacturingPage7);
532 if (pSasPages->pSASIOUnitPage0)
533 RTMemFree(pSasPages->pSASIOUnitPage0);
534 if (pSasPages->pSASIOUnitPage1)
535 RTMemFree(pSasPages->pSASIOUnitPage1);
536 }
537
538 RTMemFree(pThis->pConfigurationPages);
539 }
540}
541
542/**
543 * Finishes a context reply.
544 *
545 * @returns nothing
546 * @param pLsiLogic Pointer to the device instance
547 * @param u32MessageContext The message context ID to post.
548 */
549static void lsilogicFinishContextReply(PLSILOGICSCSI pLsiLogic, uint32_t u32MessageContext)
550{
551 int rc;
552
553 LogFlowFunc(("pLsiLogic=%#p u32MessageContext=%#x\n", pLsiLogic, u32MessageContext));
554
555 AssertMsg(!pLsiLogic->fDoorbellInProgress, ("We are in a doorbell function\n"));
556
557 /* Write message context ID into reply post queue. */
558 rc = PDMCritSectEnter(&pLsiLogic->ReplyPostQueueCritSect, VINF_SUCCESS);
559 AssertRC(rc);
560
561#if 0
562 /* Check for a entry in the queue. */
563 if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
564 {
565 /* Set error code. */
566 lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
567 PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect);
568 return;
569 }
570#endif
571
572 /* We have a context reply. */
573 ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite], u32MessageContext);
574 ASMAtomicIncU32(&pLsiLogic->uReplyPostQueueNextEntryFreeWrite);
575 pLsiLogic->uReplyPostQueueNextEntryFreeWrite %= pLsiLogic->cReplyQueueEntries;
576
577 PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect);
578
579 /* Set interrupt. */
580 lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
581}
582
583static void lsilogicTaskStateClear(PLSILOGICTASKSTATE pTaskState)
584{
585 RTMemFree(pTaskState->pSGListHead);
586 RTMemFree(pTaskState->paSGEntries);
587 if (pTaskState->pvBufferUnaligned)
588 RTMemPageFree(pTaskState->pvBufferUnaligned, pTaskState->cbBufferUnaligned);
589 pTaskState->cSGListSize = 0;
590 pTaskState->cSGInfoSize = 0;
591 pTaskState->cSGInfoEntries = 0;
592 pTaskState->cSGListTooBig = 0;
593 pTaskState->pSGListHead = NULL;
594 pTaskState->paSGEntries = NULL;
595 pTaskState->pvBufferUnaligned = NULL;
596 pTaskState->cbBufferUnaligned = 0;
597}
598
599static int lsilogicTaskStateCtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
600{
601 memset(pvObj, 0, sizeof(LSILOGICTASKSTATE));
602 return VINF_SUCCESS;
603}
604
605static void lsilogicTaskStateDtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
606{
607 PLSILOGICTASKSTATE pTaskState = (PLSILOGICTASKSTATE)pvObj;
608 lsilogicTaskStateClear(pTaskState);
609}
610
611#endif /* IN_RING3 */
612
613/**
614 * Takes neccessary steps to finish a reply frame.
615 *
616 * @returns nothing
617 * @param pLsiLogic Pointer to the device instance
618 * @param pReply Pointer to the reply message.
619 * @param fForceReplyFifo Flag whether the use of the reply post fifo is forced.
620 */
621static void lsilogicFinishAddressReply(PLSILOGICSCSI pLsiLogic, PMptReplyUnion pReply, bool fForceReplyFifo)
622{
623 /*
624 * If we are in a doorbell function we set the reply size now and
625 * set the system doorbell status interrupt to notify the guest that
626 * we are ready to send the reply.
627 */
628 if (pLsiLogic->fDoorbellInProgress && !fForceReplyFifo)
629 {
630 /* Set size of the reply in 16bit words. The size in the reply is in 32bit dwords. */
631 pLsiLogic->cReplySize = pReply->Header.u8MessageLength * 2;
632 Log(("%s: cReplySize=%u\n", __FUNCTION__, pLsiLogic->cReplySize));
633 pLsiLogic->uNextReplyEntryRead = 0;
634 lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
635 }
636 else
637 {
638 /*
639 * The reply queues are only used if the request was fetched from the request queue.
640 * Requests from the request queue are always transferred to R3. So it is not possible
641 * that this case happens in R0 or GC.
642 */
643#ifdef IN_RING3
644 int rc;
645 /* Grab a free reply message from the queue. */
646 rc = PDMCritSectEnter(&pLsiLogic->ReplyFreeQueueCritSect, VINF_SUCCESS);
647 AssertRC(rc);
648
649#if 0
650 /* Check for a free reply frame. */
651 if (RT_UNLIKELY(pLsiLogic->uReplyFreeQueueNextAddressRead != pLsiLogic->uReplyFreeQueueNextEntryFreeWrite))
652 {
653 /* Set error code. */
654 lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
655 PDMCritSectLeave(&pLsiLogic->ReplyFreeQueueCritSect);
656 return;
657 }
658#endif
659
660 uint32_t u32ReplyFrameAddressLow = pLsiLogic->CTX_SUFF(pReplyFreeQueueBase)[pLsiLogic->uReplyFreeQueueNextAddressRead];
661
662 pLsiLogic->uReplyFreeQueueNextAddressRead++;
663 pLsiLogic->uReplyFreeQueueNextAddressRead %= pLsiLogic->cReplyQueueEntries;
664
665 PDMCritSectLeave(&pLsiLogic->ReplyFreeQueueCritSect);
666
667 /* Build 64bit physical address. */
668 RTGCPHYS GCPhysReplyMessage = LSILOGIC_RTGCPHYS_FROM_U32(pLsiLogic->u32HostMFAHighAddr, u32ReplyFrameAddressLow);
669 size_t cbReplyCopied = (pLsiLogic->cbReplyFrame < sizeof(MptReplyUnion)) ? pLsiLogic->cbReplyFrame : sizeof(MptReplyUnion);
670
671 /* Write reply to guest memory. */
672 PDMDevHlpPhysWrite(pLsiLogic->CTX_SUFF(pDevIns), GCPhysReplyMessage, pReply, cbReplyCopied);
673
674 /* Write low 32bits of reply frame into post reply queue. */
675 rc = PDMCritSectEnter(&pLsiLogic->ReplyPostQueueCritSect, VINF_SUCCESS);
676 AssertRC(rc);
677
678#if 0
679 /* Check for a entry in the queue. */
680 if (RT_UNLIKELY(pLsiLogic->uReplyPostQueueNextAddressRead != pLsiLogic->uReplyPostQueueNextEntryFreeWrite))
681 {
682 /* Set error code. */
683 lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INSUFFICIENT_RESOURCES);
684 PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect);
685 return;
686 }
687#endif
688
689 /* We have a address reply. Set the 31th bit to indicate that. */
690 ASMAtomicWriteU32(&pLsiLogic->CTX_SUFF(pReplyPostQueueBase)[pLsiLogic->uReplyPostQueueNextEntryFreeWrite],
691 RT_BIT(31) | (u32ReplyFrameAddressLow >> 1));
692 ASMAtomicIncU32(&pLsiLogic->uReplyPostQueueNextEntryFreeWrite);
693 pLsiLogic->uReplyPostQueueNextEntryFreeWrite %= pLsiLogic->cReplyQueueEntries;
694
695 PDMCritSectLeave(&pLsiLogic->ReplyPostQueueCritSect);
696
697 if (fForceReplyFifo)
698 {
699 pLsiLogic->fDoorbellInProgress = false;
700 lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
701 }
702
703 /* Set interrupt. */
704 lsilogicSetInterrupt(pLsiLogic, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
705#else
706 AssertMsgFailed(("This is not allowed to happen.\n"));
707#endif
708 }
709}
710
711#ifdef IN_RING3
712/**
713 * Processes a given Request from the guest
714 *
715 * @returns VBox status code.
716 * @param pLsiLogic Pointer to the device instance.
717 * @param pMessageHdr Pointer to the message header of the request.
718 * @param pReply Pointer to the reply.
719 */
720static int lsilogicProcessMessageRequest(PLSILOGICSCSI pLsiLogic, PMptMessageHdr pMessageHdr, PMptReplyUnion pReply)
721{
722 int rc = VINF_SUCCESS;
723 bool fForceReplyPostFifo = false;
724
725#ifdef DEBUG
726 if (pMessageHdr->u8Function < RT_ELEMENTS(g_apszMPTFunctionNames))
727 Log(("Message request function: %s\n", g_apszMPTFunctionNames[pMessageHdr->u8Function]));
728 else
729 Log(("Message request function: <unknown>\n"));
730#endif
731
732 memset(pReply, 0, sizeof(MptReplyUnion));
733
734 switch (pMessageHdr->u8Function)
735 {
736 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
737 {
738 PMptSCSITaskManagementRequest pTaskMgmtReq = (PMptSCSITaskManagementRequest)pMessageHdr;
739
740 LogFlow(("u8TaskType=%u\n", pTaskMgmtReq->u8TaskType));
741 LogFlow(("u32TaskMessageContext=%#x\n", pTaskMgmtReq->u32TaskMessageContext));
742
743 pReply->SCSITaskManagement.u8MessageLength = 6; /* 6 32bit dwords. */
744 pReply->SCSITaskManagement.u8TaskType = pTaskMgmtReq->u8TaskType;
745 pReply->SCSITaskManagement.u32TerminationCount = 0;
746 fForceReplyPostFifo = true;
747 break;
748 }
749 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
750 {
751 /*
752 * This request sets the I/O controller to the
753 * operational state.
754 */
755 PMptIOCInitRequest pIOCInitReq = (PMptIOCInitRequest)pMessageHdr;
756
757 /* Update configuration values. */
758 pLsiLogic->enmWhoInit = (LSILOGICWHOINIT)pIOCInitReq->u8WhoInit;
759 pLsiLogic->cbReplyFrame = pIOCInitReq->u16ReplyFrameSize;
760 pLsiLogic->cMaxBuses = pIOCInitReq->u8MaxBuses;
761 pLsiLogic->cMaxDevices = pIOCInitReq->u8MaxDevices;
762 pLsiLogic->u32HostMFAHighAddr = pIOCInitReq->u32HostMfaHighAddr;
763 pLsiLogic->u32SenseBufferHighAddr = pIOCInitReq->u32SenseBufferHighAddr;
764
765 if (pLsiLogic->enmState == LSILOGICSTATE_READY)
766 {
767 pLsiLogic->enmState = LSILOGICSTATE_OPERATIONAL;
768 }
769
770 /* Return reply. */
771 pReply->IOCInit.u8MessageLength = 5;
772 pReply->IOCInit.u8WhoInit = pLsiLogic->enmWhoInit;
773 pReply->IOCInit.u8MaxDevices = pLsiLogic->cMaxDevices;
774 pReply->IOCInit.u8MaxBuses = pLsiLogic->cMaxBuses;
775 break;
776 }
777 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
778 {
779 pReply->IOCFacts.u8MessageLength = 15; /* 15 32bit dwords. */
780
781 if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
782 {
783 pReply->IOCFacts.u16MessageVersion = 0x0102; /* Version from the specification. */
784 pReply->IOCFacts.u8NumberOfPorts = pLsiLogic->cPorts;
785 }
786 else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
787 {
788 pReply->IOCFacts.u16MessageVersion = 0x0105; /* Version from the specification. */
789 pReply->IOCFacts.u8NumberOfPorts = pLsiLogic->cPorts;
790 }
791 else
792 AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType));
793
794 pReply->IOCFacts.u8IOCNumber = 0; /* PCI function number. */
795 pReply->IOCFacts.u16IOCExceptions = 0;
796 pReply->IOCFacts.u8MaxChainDepth = LSILOGICSCSI_MAXIMUM_CHAIN_DEPTH;
797 pReply->IOCFacts.u8WhoInit = pLsiLogic->enmWhoInit;
798 pReply->IOCFacts.u8BlockSize = 12; /* Block size in 32bit dwords. This is the largest request we can get (SCSI I/O). */
799 pReply->IOCFacts.u8Flags = 0; /* Bit 0 is set if the guest must upload the FW prior to using the controller. Obviously not needed here. */
800 pReply->IOCFacts.u16ReplyQueueDepth = pLsiLogic->cReplyQueueEntries - 1; /* One entry is always free. */
801 pReply->IOCFacts.u16RequestFrameSize = 128; /* @todo Figure out where it is needed. */
802 pReply->IOCFacts.u16ProductID = 0xcafe; /* Our own product ID :) */
803 pReply->IOCFacts.u32CurrentHostMFAHighAddr = pLsiLogic->u32HostMFAHighAddr;
804 pReply->IOCFacts.u16GlobalCredits = pLsiLogic->cRequestQueueEntries - 1; /* One entry is always free. */
805
806 pReply->IOCFacts.u8EventState = 0; /* Event notifications not enabled. */
807 pReply->IOCFacts.u32CurrentSenseBufferHighAddr = pLsiLogic->u32SenseBufferHighAddr;
808 pReply->IOCFacts.u16CurReplyFrameSize = pLsiLogic->cbReplyFrame;
809 pReply->IOCFacts.u8MaxDevices = pLsiLogic->cMaxDevices;
810 pReply->IOCFacts.u8MaxBuses = pLsiLogic->cMaxBuses;
811 pReply->IOCFacts.u32FwImageSize = 0; /* No image needed. */
812 pReply->IOCFacts.u32FWVersion = 0;
813 break;
814 }
815 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
816 {
817 PMptPortFactsRequest pPortFactsReq = (PMptPortFactsRequest)pMessageHdr;
818
819 pReply->PortFacts.u8MessageLength = 10;
820 pReply->PortFacts.u8PortNumber = pPortFactsReq->u8PortNumber;
821
822 if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
823 {
824 /* This controller only supports one bus with bus number 0. */
825 if (pPortFactsReq->u8PortNumber >= pLsiLogic->cPorts)
826 {
827 pReply->PortFacts.u8PortType = 0; /* Not existant. */
828 }
829 else
830 {
831 pReply->PortFacts.u8PortType = 0x01; /* SCSI Port. */
832 pReply->PortFacts.u16MaxDevices = LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
833 pReply->PortFacts.u16ProtocolFlags = RT_BIT(3) | RT_BIT(0); /* SCSI initiator and LUN supported. */
834 pReply->PortFacts.u16PortSCSIID = 7; /* Default */
835 pReply->PortFacts.u16MaxPersistentIDs = 0;
836 pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
837 pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */
838 }
839 }
840 else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
841 {
842 if (pPortFactsReq->u8PortNumber >= pLsiLogic->cPorts)
843 {
844 pReply->PortFacts.u8PortType = 0; /* Not existant. */
845 }
846 else
847 {
848 pReply->PortFacts.u8PortType = 0x30; /* SAS Port. */
849 pReply->PortFacts.u16MaxDevices = pLsiLogic->cPorts;
850 pReply->PortFacts.u16ProtocolFlags = RT_BIT(3) | RT_BIT(0); /* SCSI initiator and LUN supported. */
851 pReply->PortFacts.u16PortSCSIID = pLsiLogic->cPorts;
852 pReply->PortFacts.u16MaxPersistentIDs = 0;
853 pReply->PortFacts.u16MaxPostedCmdBuffers = 0; /* Only applies for target mode which we dont support. */
854 pReply->PortFacts.u16MaxLANBuckets = 0; /* Only for the LAN controller. */
855 }
856 }
857 else
858 AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType));
859 break;
860 }
861 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
862 {
863 /*
864 * The port enable request notifies the IOC to make the port available and perform
865 * appropriate discovery on the associated link.
866 */
867 PMptPortEnableRequest pPortEnableReq = (PMptPortEnableRequest)pMessageHdr;
868
869 pReply->PortEnable.u8MessageLength = 5;
870 pReply->PortEnable.u8PortNumber = pPortEnableReq->u8PortNumber;
871 break;
872 }
873 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
874 {
875 PMptEventNotificationRequest pEventNotificationReq = (PMptEventNotificationRequest)pMessageHdr;
876
877 if (pEventNotificationReq->u8Switch)
878 pLsiLogic->fEventNotificationEnabled = true;
879 else
880 pLsiLogic->fEventNotificationEnabled = false;
881
882 pReply->EventNotification.u16EventDataLength = 1; /* 1 32bit D-Word. */
883 pReply->EventNotification.u8MessageLength = 8;
884 pReply->EventNotification.u8MessageFlags = (1 << 7);
885 pReply->EventNotification.u8AckRequired = 0;
886 pReply->EventNotification.u32Event = MPT_EVENT_EVENT_CHANGE;
887 pReply->EventNotification.u32EventContext = 0;
888 pReply->EventNotification.u32EventData = pLsiLogic->fEventNotificationEnabled ? 1 : 0;
889
890 break;
891 }
892 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
893 {
894 AssertMsgFailed(("todo"));
895 break;
896 }
897 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
898 {
899 PMptConfigurationRequest pConfigurationReq = (PMptConfigurationRequest)pMessageHdr;
900
901 rc = lsilogicProcessConfigurationRequest(pLsiLogic, pConfigurationReq, &pReply->Configuration);
902 AssertRC(rc);
903 break;
904 }
905 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST: /* Should be handled already. */
906 default:
907 AssertMsgFailed(("Invalid request function %#x\n", pMessageHdr->u8Function));
908 }
909
910 /* Copy common bits from request message frame to reply. */
911 pReply->Header.u8Function = pMessageHdr->u8Function;
912 pReply->Header.u32MessageContext = pMessageHdr->u32MessageContext;
913
914 lsilogicFinishAddressReply(pLsiLogic, pReply, fForceReplyPostFifo);
915 return rc;
916}
917#endif
918
919/**
920 * Writes a value to a register at a given offset.
921 *
922 * @returns VBox status code.
923 * @param pThis Pointer to the LsiLogic SCSI controller instance data.
924 * @param uOffset Offset of the register to write.
925 * @param pv Pointer to the value to write
926 * @param cb Number of bytes to write.
927 */
928static int lsilogicRegisterWrite(PLSILOGICSCSI pThis, uint32_t uOffset, void *pv, unsigned cb)
929{
930 uint32_t u32 = *(uint32_t *)pv;
931
932 LogFlowFunc(("pThis=%#p uOffset=%#x pv=%#p{%.*Rhxs} cb=%u\n", pThis, uOffset, pv, cb, pv, cb));
933
934 switch (uOffset)
935 {
936 case LSILOGIC_REG_REPLY_QUEUE:
937 {
938 /* Add the entry to the reply free queue. */
939 ASMAtomicWriteU32(&pThis->CTX_SUFF(pReplyFreeQueueBase)[pThis->uReplyFreeQueueNextEntryFreeWrite], u32);
940 pThis->uReplyFreeQueueNextEntryFreeWrite++;
941 pThis->uReplyFreeQueueNextEntryFreeWrite %= pThis->cReplyQueueEntries;
942 break;
943 }
944 case LSILOGIC_REG_REQUEST_QUEUE:
945 {
946 ASMAtomicWriteU32(&pThis->CTX_SUFF(pRequestQueueBase)[pThis->uRequestQueueNextEntryFreeWrite], u32);
947 pThis->uRequestQueueNextEntryFreeWrite++;
948 pThis->uRequestQueueNextEntryFreeWrite %= pThis->cRequestQueueEntries;
949
950 /* Send notification to R3 if there is not one send already. */
951 if (!ASMAtomicXchgBool(&pThis->fNotificationSend, true))
952 {
953 PPDMQUEUEITEMCORE pNotificationItem = PDMQueueAlloc(pThis->CTX_SUFF(pNotificationQueue));
954 AssertPtr(pNotificationItem);
955
956 PDMQueueInsert(pThis->CTX_SUFF(pNotificationQueue), pNotificationItem);
957 }
958 break;
959 }
960 case LSILOGIC_REG_DOORBELL:
961 {
962 /*
963 * When the guest writes to this register a real device would set the
964 * doorbell status bit in the interrupt status register to indicate that the IOP
965 * has still to process the message.
966 * The guest needs to wait with posting new messages here until the bit is cleared.
967 * Because the guest is not continuing execution while we are here we can skip this.
968 */
969 if (!pThis->fDoorbellInProgress)
970 {
971 uint32_t uFunction = LSILOGIC_REG_DOORBELL_GET_FUNCTION(u32);
972
973 switch (uFunction)
974 {
975 case LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET:
976 {
977 pThis->enmState = LSILOGICSTATE_RESET;
978
979 /* Reset interrupt states. */
980 pThis->uInterruptMask = 0;
981 pThis->uInterruptStatus = 0;
982 lsilogicUpdateInterrupt(pThis);
983
984 /* Reset the queues. */
985 pThis->uReplyFreeQueueNextEntryFreeWrite = 0;
986 pThis->uReplyFreeQueueNextAddressRead = 0;
987 pThis->uReplyPostQueueNextEntryFreeWrite = 0;
988 pThis->uReplyPostQueueNextAddressRead = 0;
989 pThis->uRequestQueueNextEntryFreeWrite = 0;
990 pThis->uRequestQueueNextAddressRead = 0;
991 pThis->enmState = LSILOGICSTATE_READY;
992 break;
993 }
994 case LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET:
995 {
996 AssertMsgFailed(("todo\n"));
997 break;
998 }
999 case LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE:
1000 {
1001 pThis->cMessage = LSILOGIC_REG_DOORBELL_GET_SIZE(u32);
1002 pThis->iMessage = 0;
1003 AssertMsg(pThis->cMessage <= RT_ELEMENTS(pThis->aMessage),
1004 ("Message doesn't fit into the buffer, cMessage=%u", pThis->cMessage));
1005 pThis->fDoorbellInProgress = true;
1006 /* Update the interrupt status to notify the guest that a doorbell function was started. */
1007 lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1008 break;
1009 }
1010 case LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL:
1011 {
1012 AssertMsgFailed(("todo\n"));
1013 break;
1014 }
1015 default:
1016 AssertMsgFailed(("Unknown function %u to perform\n", uFunction));
1017 }
1018 }
1019 else
1020 {
1021 /*
1022 * We are already performing a doorbell function.
1023 * Get the remaining parameters.
1024 */
1025 AssertMsg(pThis->iMessage < RT_ELEMENTS(pThis->aMessage), ("Message is too big to fit into the buffer\n"));
1026 /*
1027 * If the last byte of the message is written, force a switch to R3 because some requests might force
1028 * a reply through the FIFO which cannot be handled in GC or R0.
1029 */
1030#ifndef IN_RING3
1031 if (pThis->iMessage == pThis->cMessage - 1)
1032 return VINF_IOM_HC_MMIO_WRITE;
1033#endif
1034 pThis->aMessage[pThis->iMessage++] = u32;
1035#ifdef IN_RING3
1036 if (pThis->iMessage == pThis->cMessage)
1037 {
1038 int rc = lsilogicProcessMessageRequest(pThis, (PMptMessageHdr)pThis->aMessage, &pThis->ReplyBuffer);
1039 AssertRC(rc);
1040 }
1041#endif
1042 }
1043 break;
1044 }
1045 case LSILOGIC_REG_HOST_INTR_STATUS:
1046 {
1047 /*
1048 * Clear the bits the guest wants except the system doorbell interrupt and the IO controller
1049 * status bit.
1050 * The former bit is always cleared no matter what the guest writes to the register and
1051 * the latter one is read only.
1052 */
1053 pThis->uInterruptStatus = pThis->uInterruptStatus & ~LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL;
1054
1055 /*
1056 * Check if there is still a doorbell function in progress. Set the
1057 * system doorbell interrupt bit again if it is.
1058 * We do not use lsilogicSetInterrupt here because the interrupt status
1059 * is updated afterwards anyway.
1060 */
1061 if ( (pThis->fDoorbellInProgress)
1062 && (pThis->cMessage == pThis->iMessage))
1063 {
1064 if (pThis->uNextReplyEntryRead == pThis->cReplySize)
1065 {
1066 /* Reply finished. Reset doorbell in progress status. */
1067 Log(("%s: Doorbell function finished\n", __FUNCTION__));
1068 pThis->fDoorbellInProgress = false;
1069 }
1070 ASMAtomicOrU32(&pThis->uInterruptStatus, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
1071 }
1072
1073 lsilogicUpdateInterrupt(pThis);
1074 break;
1075 }
1076 case LSILOGIC_REG_HOST_INTR_MASK:
1077 {
1078 pThis->uInterruptMask = (u32 & LSILOGIC_REG_HOST_INTR_MASK_W_MASK);
1079 lsilogicUpdateInterrupt(pThis);
1080 break;
1081 }
1082 case LSILOGIC_REG_WRITE_SEQUENCE:
1083 {
1084 if (pThis->fDiagnosticEnabled)
1085 {
1086 /* Any value will cause a reset and disabling access. */
1087 pThis->fDiagnosticEnabled = false;
1088 pThis->iDiagnosticAccess = 0;
1089 }
1090 else if ((u32 & 0xf) == g_lsilogicDiagnosticAccess[pThis->iDiagnosticAccess])
1091 {
1092 pThis->iDiagnosticAccess++;
1093 if (pThis->iDiagnosticAccess == RT_ELEMENTS(g_lsilogicDiagnosticAccess))
1094 {
1095 /*
1096 * Key sequence successfully written. Enable access to diagnostic
1097 * memory and register.
1098 */
1099 pThis->fDiagnosticEnabled = true;
1100 }
1101 }
1102 else
1103 {
1104 /* Wrong value written - reset to beginning. */
1105 pThis->iDiagnosticAccess = 0;
1106 }
1107 break;
1108 }
1109 case LSILOGIC_REG_HOST_DIAGNOSTIC:
1110 {
1111#ifndef IN_RING3
1112 return VINF_IOM_HC_IOPORT_WRITE;
1113#else
1114 if (u32 & LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER)
1115 {
1116 lsilogicHardReset(pThis);
1117 }
1118 break;
1119#endif
1120 }
1121 default: /* Ignore. */
1122 {
1123 break;
1124 }
1125 }
1126 return VINF_SUCCESS;
1127}
1128
1129/**
1130 * Reads the content of a register at a given offset.
1131 *
1132 * @returns VBox status code.
1133 * @param pThis Pointer to the LsiLogic SCSI controller instance data.
1134 * @param uOffset Offset of the register to read.
1135 * @param pv Where to store the content of the register.
1136 * @param cb Number of bytes to read.
1137 */
1138static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t uOffset, void *pv, unsigned cb)
1139{
1140 uint32_t u32 = 0;
1141
1142 /* Align to a 4 byte offset. */
1143 switch (uOffset & ~3)
1144 {
1145 case LSILOGIC_REG_REPLY_QUEUE:
1146 {
1147 /*
1148 * Non 4-byte access may cause real strange behavior because the data is part of a physical guest address.
1149 * But some drivers use 1-byte access to scan for SCSI controllers.
1150 */
1151 if (RT_UNLIKELY(cb != 4))
1152 LogFlowFunc((": cb is not 4 (%u)\n", cb));
1153
1154 if (pThis->uReplyPostQueueNextEntryFreeWrite != pThis->uReplyPostQueueNextAddressRead)
1155 {
1156 u32 = pThis->CTX_SUFF(pReplyPostQueueBase)[pThis->uReplyPostQueueNextAddressRead];
1157 pThis->uReplyPostQueueNextAddressRead++;
1158 pThis->uReplyPostQueueNextAddressRead %= pThis->cReplyQueueEntries;
1159 }
1160 else
1161 {
1162 /* The reply post queue is empty. Reset interrupt. */
1163 u32 = UINT32_C(0xffffffff);
1164 lsilogicClearInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR);
1165 }
1166 Log(("%s: Returning address %#x\n", __FUNCTION__, u32));
1167 break;
1168 }
1169 case LSILOGIC_REG_DOORBELL:
1170 {
1171 u32 = LSILOGIC_REG_DOORBELL_SET_STATE(pThis->enmState);
1172 u32 |= LSILOGIC_REG_DOORBELL_SET_USED(pThis->fDoorbellInProgress);
1173 u32 |= LSILOGIC_REG_DOORBELL_SET_WHOINIT(pThis->enmWhoInit);
1174 /*
1175 * If there is a doorbell function in progress we pass the return value
1176 * instead of the status code. We transfer 16bit of the reply
1177 * during one read.
1178 */
1179 if (pThis->fDoorbellInProgress)
1180 {
1181 /* Return next 16bit value. */
1182 u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++];
1183 }
1184 else
1185 {
1186 /* We return the status code of the I/O controller. */
1187 u32 |= pThis->u16IOCFaultCode;
1188 }
1189 break;
1190 }
1191 case LSILOGIC_REG_HOST_INTR_STATUS:
1192 {
1193 u32 = pThis->uInterruptStatus;
1194 break;
1195 }
1196 case LSILOGIC_REG_HOST_INTR_MASK:
1197 {
1198 u32 = pThis->uInterruptMask;
1199 break;
1200 }
1201 case LSILOGIC_REG_HOST_DIAGNOSTIC:
1202 {
1203 if (pThis->fDiagnosticEnabled)
1204 u32 = LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE;
1205 else
1206 u32 = 0;
1207 break;
1208 }
1209 case LSILOGIC_REG_TEST_BASE_ADDRESS: /* The spec doesn't say anything about these registers, so we just ignore them */
1210 case LSILOGIC_REG_DIAG_RW_DATA:
1211 case LSILOGIC_REG_DIAG_RW_ADDRESS:
1212 default: /* Ignore. */
1213 {
1214 break;
1215 }
1216 }
1217
1218 /* Clip data according to the read size. */
1219 switch (cb)
1220 {
1221 case 4:
1222 {
1223 *(uint32_t *)pv = u32;
1224 break;
1225 }
1226 case 2:
1227 {
1228 uint8_t uBitsOff = (uOffset - (uOffset & 3))*8;
1229
1230 u32 &= (0xffff << uBitsOff);
1231 *(uint16_t *)pv = (uint16_t)(u32 >> uBitsOff);
1232 break;
1233 }
1234 case 1:
1235 {
1236 uint8_t uBitsOff = (uOffset - (uOffset & 3))*8;
1237
1238 u32 &= (0xff << uBitsOff);
1239 *(uint8_t *)pv = (uint8_t)(u32 >> uBitsOff);
1240 break;
1241 }
1242 default:
1243 AssertMsgFailed(("Invalid access size %u\n", cb));
1244 }
1245
1246 LogFlowFunc(("pThis=%#p uOffset=%#x pv=%#p{%.*Rhxs} cb=%u\n", pThis, uOffset, pv, cb, pv, cb));
1247
1248 return VINF_SUCCESS;
1249}
1250
1251PDMBOTHCBDECL(int) lsilogicIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
1252 RTIOPORT Port, uint32_t u32, unsigned cb)
1253{
1254 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1255 uint32_t uOffset = Port - pThis->IOPortBase;
1256
1257 Assert(cb <= 4);
1258
1259 int rc = lsilogicRegisterWrite(pThis, uOffset, &u32, cb);
1260 if (rc == VINF_IOM_HC_MMIO_WRITE)
1261 rc = VINF_IOM_HC_IOPORT_WRITE;
1262
1263 return rc;
1264}
1265
1266PDMBOTHCBDECL(int) lsilogicIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
1267 RTIOPORT Port, uint32_t *pu32, unsigned cb)
1268{
1269 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1270 uint32_t uOffset = Port - pThis->IOPortBase;
1271
1272 Assert(cb <= 4);
1273
1274 return lsilogicRegisterRead(pThis, uOffset, pu32, cb);
1275}
1276
1277PDMBOTHCBDECL(int) lsilogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1278 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1279{
1280 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1281 uint32_t uOffset = GCPhysAddr - pThis->GCPhysMMIOBase;
1282
1283 return lsilogicRegisterWrite(pThis, uOffset, pv, cb);
1284}
1285
1286PDMBOTHCBDECL(int) lsilogicMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1287 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1288{
1289 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1290 uint32_t uOffset = GCPhysAddr - pThis->GCPhysMMIOBase;
1291
1292 return lsilogicRegisterRead(pThis, uOffset, pv, cb);
1293}
1294
1295PDMBOTHCBDECL(int) lsilogicDiagnosticWrite(PPDMDEVINS pDevIns, void *pvUser,
1296 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1297{
1298 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1299
1300 LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
1301
1302 return VINF_SUCCESS;
1303}
1304
1305PDMBOTHCBDECL(int) lsilogicDiagnosticRead(PPDMDEVINS pDevIns, void *pvUser,
1306 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1307{
1308 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
1309
1310 LogFlowFunc(("pThis=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pThis, GCPhysAddr, pv, cb, pv, cb));
1311
1312 return VINF_SUCCESS;
1313}
1314
1315#ifdef IN_RING3
1316
1317/**
1318 * Copies a contigous buffer into the scatter gather list provided by the guest.
1319 *
1320 * @returns nothing
1321 * @param pTaskState Pointer to the task state which contains the SGL.
1322 * @param pvBuf Pointer to the buffer to copy.
1323 * @param cbCopy Number of bytes to copy.
1324 */
1325static void lsilogicScatterGatherListCopyFromBuffer(PLSILOGICTASKSTATE pTaskState, void *pvBuf, size_t cbCopy)
1326{
1327 unsigned cSGEntry = 0;
1328 PRTSGSEG pSGEntry = &pTaskState->pSGListHead[cSGEntry];
1329 uint8_t *pu8Buf = (uint8_t *)pvBuf;
1330
1331 while (cSGEntry < pTaskState->cSGListEntries)
1332 {
1333 size_t cbToCopy = (cbCopy < pSGEntry->cbSeg) ? cbCopy : pSGEntry->cbSeg;
1334
1335 memcpy(pSGEntry->pvSeg, pu8Buf, cbToCopy);
1336
1337 cbCopy -= cbToCopy;
1338 /* We finished. */
1339 if (!cbCopy)
1340 break;
1341
1342 /* Advance the buffer. */
1343 pu8Buf += cbToCopy;
1344
1345 /* Go to the next entry in the list. */
1346 pSGEntry++;
1347 cSGEntry++;
1348 }
1349}
1350
1351/**
1352 * Copy a temporary buffer into a part of the guest scatter gather list
1353 * described by the given descriptor entry.
1354 *
1355 * @returns nothing.
1356 * @param pDevIns Pointer to the device instance data.
1357 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
1358 * to write to which are unaligned.
1359 */
1360static void lsilogicCopyFromBufferIntoSGList(PPDMDEVINS pDevIns, PLSILOGICTASKSTATESGENTRY pSGInfo)
1361{
1362 RTGCPHYS GCPhysBuffer = pSGInfo->u.GCPhysAddrBufferUnaligned;
1363
1364 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
1365
1366 /* Copy into SG entry. */
1367 PDMDevHlpPhysWrite(pDevIns, GCPhysBuffer, pSGInfo->pvBuf, pSGInfo->cbBuf);
1368
1369}
1370
1371/**
1372 * Copy a part of the guest scatter gather list into a temporary buffer.
1373 *
1374 * @returns nothing.
1375 * @param pDevIns Pointer to the device instance data.
1376 * @param pSGInfo Pointer to the segment info structure which describes the guest segments
1377 * to read from which are unaligned.
1378 */
1379static void lsilogicCopyFromSGListIntoBuffer(PPDMDEVINS pDevIns, PLSILOGICTASKSTATESGENTRY pSGInfo)
1380{
1381 RTGCPHYS GCPhysBuffer = pSGInfo->u.GCPhysAddrBufferUnaligned;
1382
1383 AssertMsg(!pSGInfo->fGuestMemory, ("This is not possible\n"));
1384
1385 /* Copy into temporary buffer. */
1386 PDMDevHlpPhysRead(pDevIns, GCPhysBuffer, pSGInfo->pvBuf, pSGInfo->cbBuf);
1387}
1388
1389static int lsilogicScatterGatherListAllocate(PLSILOGICTASKSTATE pTaskState, uint32_t cSGList, uint32_t cSGInfo, uint32_t cbUnaligned)
1390{
1391 if (pTaskState->cSGListSize < cSGList)
1392 {
1393 /* The entries are not allocated yet or the number is too small. */
1394 if (pTaskState->cSGListSize)
1395 RTMemFree(pTaskState->pSGListHead);
1396
1397 /* Allocate R3 scatter gather list. */
1398 pTaskState->pSGListHead = (PRTSGSEG)RTMemAllocZ(cSGList * sizeof(RTSGSEG));
1399 if (!pTaskState->pSGListHead)
1400 return VERR_NO_MEMORY;
1401
1402 /* Reset usage statistics. */
1403 pTaskState->cSGListSize = cSGList;
1404 pTaskState->cSGListEntries = cSGList;
1405 pTaskState->cSGListTooBig = 0;
1406 }
1407 else if (pTaskState->cSGListSize > cSGList)
1408 {
1409 /*
1410 * The list is too big. Increment counter.
1411 * So that the destroying function can free
1412 * the list if it is too big too many times
1413 * in a row.
1414 */
1415 pTaskState->cSGListEntries = cSGList;
1416 pTaskState->cSGListTooBig++;
1417 }
1418 else
1419 {
1420 /*
1421 * Needed entries matches current size.
1422 * Reset counter.
1423 */
1424 pTaskState->cSGListEntries = cSGList;
1425 pTaskState->cSGListTooBig = 0;
1426 }
1427
1428 if (pTaskState->cSGInfoSize < cSGInfo)
1429 {
1430 /* The entries are not allocated yet or the number is too small. */
1431 if (pTaskState->cSGInfoSize)
1432 RTMemFree(pTaskState->paSGEntries);
1433
1434 pTaskState->paSGEntries = (PLSILOGICTASKSTATESGENTRY)RTMemAllocZ(cSGInfo * sizeof(LSILOGICTASKSTATESGENTRY));
1435 if (!pTaskState->paSGEntries)
1436 return VERR_NO_MEMORY;
1437
1438 /* Reset usage statistics. */
1439 pTaskState->cSGInfoSize = cSGInfo;
1440 pTaskState->cSGInfoEntries = cSGInfo;
1441 pTaskState->cSGInfoTooBig = 0;
1442 }
1443 else if (pTaskState->cSGInfoSize > cSGInfo)
1444 {
1445 /*
1446 * The list is too big. Increment counter.
1447 * So that the destroying function can free
1448 * the list if it is too big too many times
1449 * in a row.
1450 */
1451 pTaskState->cSGInfoEntries = cSGInfo;
1452 pTaskState->cSGInfoTooBig++;
1453 }
1454 else
1455 {
1456 /*
1457 * Needed entries matches current size.
1458 * Reset counter.
1459 */
1460 pTaskState->cSGInfoEntries = cSGInfo;
1461 pTaskState->cSGInfoTooBig = 0;
1462 }
1463
1464
1465 if (pTaskState->cbBufferUnaligned < cbUnaligned)
1466 {
1467 if (pTaskState->pvBufferUnaligned)
1468 RTMemPageFree(pTaskState->pvBufferUnaligned, pTaskState->cbBufferUnaligned);
1469
1470 Log(("%s: Allocating buffer for unaligned segments cbUnaligned=%u\n", __FUNCTION__, cbUnaligned));
1471
1472 pTaskState->pvBufferUnaligned = RTMemPageAlloc(cbUnaligned);
1473 if (!pTaskState->pvBufferUnaligned)
1474 return VERR_NO_MEMORY;
1475
1476 pTaskState->cbBufferUnaligned = cbUnaligned;
1477 }
1478
1479 /* Make debugging easier. */
1480#ifdef DEBUG
1481 memset(pTaskState->pSGListHead, 0, pTaskState->cSGListSize * sizeof(RTSGSEG));
1482 memset(pTaskState->paSGEntries, 0, pTaskState->cSGInfoSize * sizeof(LSILOGICTASKSTATESGENTRY));
1483 if (pTaskState->pvBufferUnaligned)
1484 memset(pTaskState->pvBufferUnaligned, 0, pTaskState->cbBufferUnaligned);
1485#endif
1486 return VINF_SUCCESS;
1487}
1488
1489/**
1490 * Destroy a scatter gather list.
1491 *
1492 * @returns nothing.
1493 * @param pLsiLogic Pointer to the LsiLogic SCSI controller.
1494 * @param pTaskState Pointer to the task state.
1495 */
1496static void lsilogicScatterGatherListDestroy(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
1497{
1498 PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns);
1499 PLSILOGICTASKSTATESGENTRY pSGInfoCurr = pTaskState->paSGEntries;
1500
1501 for (unsigned i = 0; i < pTaskState->cSGInfoEntries; i++)
1502 {
1503 if (pSGInfoCurr->fGuestMemory)
1504 {
1505 /* Release the lock. */
1506 PDMDevHlpPhysReleasePageMappingLock(pDevIns, &pSGInfoCurr->u.PageLock);
1507 }
1508 else if (!pSGInfoCurr->fBufferContainsData)
1509 {
1510 /* Copy the data into the guest segments now. */
1511 lsilogicCopyFromBufferIntoSGList(pLsiLogic->CTX_SUFF(pDevIns), pSGInfoCurr);
1512 }
1513
1514 pSGInfoCurr++;
1515 }
1516
1517 /* Free allocated memory if the list was too big too many times. */
1518 if (pTaskState->cSGListTooBig >= LSILOGIC_NR_OF_ALLOWED_BIGGER_LISTS)
1519 lsilogicTaskStateClear(pTaskState);
1520}
1521
1522#ifdef DEBUG
1523/**
1524 * Dump an SG entry.
1525 *
1526 * @returns nothing.
1527 * @param pSGEntry Pointer to the SG entry to dump
1528 */
1529static void lsilogicDumpSGEntry(PMptSGEntryUnion pSGEntry)
1530{
1531 switch (pSGEntry->Simple32.u2ElementType)
1532 {
1533 case MPTSGENTRYTYPE_SIMPLE:
1534 {
1535 Log(("%s: Dumping info for SIMPLE SG entry:\n", __FUNCTION__));
1536 Log(("%s: u24Length=%u\n", __FUNCTION__, pSGEntry->Simple32.u24Length));
1537 Log(("%s: fEndOfList=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfList));
1538 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.f64BitAddress));
1539 Log(("%s: fBufferContainsData=%d\n", __FUNCTION__, pSGEntry->Simple32.fBufferContainsData));
1540 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Simple32.fLocalAddress));
1541 Log(("%s: fEndOfBuffer=%d\n", __FUNCTION__, pSGEntry->Simple32.fEndOfBuffer));
1542 Log(("%s: fLastElement=%d\n", __FUNCTION__, pSGEntry->Simple32.fLastElement));
1543 Log(("%s: u32DataBufferAddressLow=%u\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1544 if (pSGEntry->Simple32.f64BitAddress)
1545 {
1546 Log(("%s: u32DataBufferAddressHigh=%u\n", __FUNCTION__, pSGEntry->Simple64.u32DataBufferAddressHigh));
1547 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__,
1548 ((uint64_t)pSGEntry->Simple64.u32DataBufferAddressHigh << 32) | pSGEntry->Simple64.u32DataBufferAddressLow));
1549 }
1550 else
1551 Log(("%s: GCDataBufferAddress=%RGp\n", __FUNCTION__, pSGEntry->Simple32.u32DataBufferAddressLow));
1552
1553 break;
1554 }
1555 case MPTSGENTRYTYPE_CHAIN:
1556 {
1557 Log(("%s: Dumping info for CHAIN SG entry:\n", __FUNCTION__));
1558 Log(("%s: u16Length=%u\n", __FUNCTION__, pSGEntry->Chain.u16Length));
1559 Log(("%s: u8NExtChainOffset=%d\n", __FUNCTION__, pSGEntry->Chain.u8NextChainOffset));
1560 Log(("%s: f64BitAddress=%d\n", __FUNCTION__, pSGEntry->Chain.f64BitAddress));
1561 Log(("%s: fLocalAddress=%d\n", __FUNCTION__, pSGEntry->Chain.fLocalAddress));
1562 Log(("%s: u32SegmentAddressLow=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1563 Log(("%s: u32SegmentAddressHigh=%u\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressHigh));
1564 if (pSGEntry->Chain.f64BitAddress)
1565 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__,
1566 ((uint64_t)pSGEntry->Chain.u32SegmentAddressHigh << 32) | pSGEntry->Chain.u32SegmentAddressLow));
1567 else
1568 Log(("%s: GCSegmentAddress=%RGp\n", __FUNCTION__, pSGEntry->Chain.u32SegmentAddressLow));
1569 break;
1570 }
1571 }
1572}
1573#endif
1574
1575/**
1576 * Create scatter gather list descriptors.
1577 *
1578 * @returns VBox status code.
1579 * @param pLsiLogic Pointer to the LsiLogic SCSI controller.
1580 * @param pTaskState Pointer to the task state.
1581 * @param GCPhysSGLStart Guest physical address of the first SG entry.
1582 * @param uChainOffset Offset in bytes from the beginning of the SGL segment to the chain element.
1583 * @thread EMT
1584 */
1585static int lsilogicScatterGatherListCreate(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState,
1586 RTGCPHYS GCPhysSGLStart, uint32_t uChainOffset)
1587{
1588 int rc = VINF_SUCCESS;
1589 PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns);
1590 PVM pVM = PDMDevHlpGetVM(pDevIns);
1591 bool fUnaligned; /* Flag whether the current buffer is unaligned. */
1592 uint32_t cbUnaligned; /* Size of the unaligned buffers. */
1593 uint32_t cSGEntriesR3 = 0;
1594 uint32_t cSGInfo = 0;
1595 uint32_t cbSegment = 0;
1596 PLSILOGICTASKSTATESGENTRY pSGInfoCurr = NULL;
1597 uint8_t *pu8BufferUnalignedPos = NULL;
1598 uint8_t *pbBufferUnalignedSGInfoPos = NULL;
1599 uint32_t cbUnalignedComplete = 0;
1600 bool fDoMapping = false;
1601 bool fEndOfList;
1602 RTGCPHYS GCPhysSGEntryNext;
1603 RTGCPHYS GCPhysSegmentStart;
1604 uint32_t uChainOffsetNext;
1605
1606 /*
1607 * Two passes - one to count needed scatter gather list entries and needed unaligned
1608 * buffers and one to actually map the SG list into R3.
1609 */
1610 for (int i = 0; i < 2; i++)
1611 {
1612 fUnaligned = false;
1613 cbUnaligned = 0;
1614 fEndOfList = false;
1615
1616 GCPhysSGEntryNext = GCPhysSGLStart;
1617 uChainOffsetNext = uChainOffset;
1618 GCPhysSegmentStart = GCPhysSGLStart;
1619
1620 if (fDoMapping)
1621 {
1622 Log(("%s: cSGInfo=%u\n", __FUNCTION__, cSGInfo));
1623
1624 /* The number of needed SG entries in R3 is known. Allocate needed memory. */
1625 rc = lsilogicScatterGatherListAllocate(pTaskState, cSGInfo, cSGInfo, cbUnalignedComplete);
1626 AssertMsgRC(rc, ("Failed to allocate scatter gather array rc=%Rrc\n", rc));
1627
1628 /* We are now able to map the pages into R3. */
1629 pSGInfoCurr = pTaskState->paSGEntries;
1630 /* Initialize first segment to remove the need for additional if checks later in the code. */
1631 pSGInfoCurr->fGuestMemory= false;
1632 pu8BufferUnalignedPos = (uint8_t *)pTaskState->pvBufferUnaligned;
1633 pbBufferUnalignedSGInfoPos = pu8BufferUnalignedPos;
1634 }
1635
1636 /* Go through the list until we reach the end. */
1637 while (!fEndOfList)
1638 {
1639 bool fEndOfSegment = false;
1640
1641 while (!fEndOfSegment)
1642 {
1643 MptSGEntryUnion SGEntry;
1644
1645 Log(("%s: Reading SG entry from %RGp\n", __FUNCTION__, GCPhysSGEntryNext));
1646
1647 /* Read the entry. */
1648 PDMDevHlpPhysRead(pDevIns, GCPhysSGEntryNext, &SGEntry, sizeof(MptSGEntryUnion));
1649
1650#ifdef DEBUG
1651 lsilogicDumpSGEntry(&SGEntry);
1652#endif
1653
1654 AssertMsg(SGEntry.Simple32.u2ElementType == MPTSGENTRYTYPE_SIMPLE, ("Invalid SG entry type\n"));
1655
1656 /* Check if this is a zero element. */
1657 if ( !SGEntry.Simple32.u24Length
1658 && SGEntry.Simple32.fEndOfList
1659 && SGEntry.Simple32.fEndOfBuffer)
1660 {
1661 pTaskState->cSGListEntries = 0;
1662 pTaskState->cSGInfoEntries = 0;
1663 return VINF_SUCCESS;
1664 }
1665
1666 uint32_t cbDataToTransfer = SGEntry.Simple32.u24Length;
1667 bool fBufferContainsData = !!SGEntry.Simple32.fBufferContainsData;
1668 RTGCPHYS GCPhysAddrDataBuffer = SGEntry.Simple32.u32DataBufferAddressLow;
1669
1670 if (SGEntry.Simple32.f64BitAddress)
1671 {
1672 GCPhysAddrDataBuffer |= ((uint64_t)SGEntry.Simple64.u32DataBufferAddressHigh) << 32;
1673 GCPhysSGEntryNext += sizeof(MptSGEntrySimple64);
1674 }
1675 else
1676 GCPhysSGEntryNext += sizeof(MptSGEntrySimple32);
1677
1678 if (fDoMapping)
1679 {
1680 pSGInfoCurr->fGuestMemory = false;
1681 pSGInfoCurr->fBufferContainsData = fBufferContainsData;
1682 pSGInfoCurr->cbBuf = cbDataToTransfer;
1683 pSGInfoCurr->pvBuf = pbBufferUnalignedSGInfoPos;
1684 pbBufferUnalignedSGInfoPos += cbDataToTransfer;
1685 pSGInfoCurr->u.GCPhysAddrBufferUnaligned = GCPhysAddrDataBuffer;
1686 if (fBufferContainsData)
1687 lsilogicCopyFromSGListIntoBuffer(pDevIns, pSGInfoCurr);
1688 pSGInfoCurr++;
1689 }
1690 else
1691 {
1692 cbUnalignedComplete += cbDataToTransfer;
1693 cSGInfo++;
1694 }
1695
1696 /* Check if we reached the end of the list. */
1697 if (SGEntry.Simple32.fEndOfList)
1698 {
1699 /* We finished. */
1700 fEndOfSegment = true;
1701 fEndOfList = true;
1702 }
1703 else if (SGEntry.Simple32.fLastElement)
1704 {
1705 fEndOfSegment = true;
1706 }
1707 } /* while (!fEndOfSegment) */
1708
1709 /* Get next chain element. */
1710 if (uChainOffsetNext)
1711 {
1712 MptSGEntryChain SGEntryChain;
1713
1714 PDMDevHlpPhysRead(pDevIns, GCPhysSegmentStart + uChainOffsetNext, &SGEntryChain, sizeof(MptSGEntryChain));
1715
1716 AssertMsg(SGEntryChain.u2ElementType == MPTSGENTRYTYPE_CHAIN, ("Invalid SG entry type\n"));
1717
1718 /* Set the next address now. */
1719 GCPhysSGEntryNext = SGEntryChain.u32SegmentAddressLow;
1720 if (SGEntryChain.f64BitAddress)
1721 GCPhysSGEntryNext |= ((uint64_t)SGEntryChain.u32SegmentAddressHigh) << 32;
1722
1723 GCPhysSegmentStart = GCPhysSGEntryNext;
1724 uChainOffsetNext = SGEntryChain.u8NextChainOffset * sizeof(uint32_t);
1725 }
1726
1727 } /* while (!fEndOfList) */
1728
1729 fDoMapping = true;
1730 if (fUnaligned)
1731 cbUnalignedComplete += cbUnaligned;
1732 }
1733
1734 uint32_t cSGEntries;
1735 PRTSGSEG pSGEntryCurr = pTaskState->pSGListHead;
1736 pSGInfoCurr = pTaskState->paSGEntries;
1737
1738 /* Initialize first entry. */
1739 pSGEntryCurr->pvSeg = pSGInfoCurr->pvBuf;
1740 pSGEntryCurr->cbSeg = pSGInfoCurr->cbBuf;
1741 pSGInfoCurr++;
1742 cSGEntries = 1;
1743
1744 /* Construct the scatter gather list. */
1745 for (unsigned i = 0; i < (pTaskState->cSGInfoEntries-1); i++)
1746 {
1747 if (pSGEntryCurr->cbSeg % 512 != 0)
1748 {
1749 AssertMsg((uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg == pSGInfoCurr->pvBuf,
1750 ("Buffer ist not sector aligned but the buffer addresses are not adjacent\n"));
1751
1752 pSGEntryCurr->cbSeg += pSGInfoCurr->cbBuf;
1753 }
1754 else
1755 {
1756 if (((uint8_t *)pSGEntryCurr->pvSeg + pSGEntryCurr->cbSeg) == pSGInfoCurr->pvBuf)
1757 {
1758 pSGEntryCurr->cbSeg += pSGInfoCurr->cbBuf;
1759 }
1760 else
1761 {
1762 pSGEntryCurr++;
1763 cSGEntries++;
1764 pSGEntryCurr->pvSeg = pSGInfoCurr->pvBuf;
1765 pSGEntryCurr->cbSeg = pSGInfoCurr->cbBuf;
1766 }
1767 }
1768
1769 pSGInfoCurr++;
1770 }
1771
1772 pTaskState->cSGListEntries = cSGEntries;
1773
1774 return rc;
1775}
1776
1777/*
1778 * Disabled because the sense buffer provided by the LsiLogic driver for Windows XP
1779 * crosses page boundaries.
1780 */
1781#if 0
1782/**
1783 * Free the sense buffer.
1784 *
1785 * @returns nothing.
1786 * @param pTaskState Pointer to the task state.
1787 */
1788static void lsilogicFreeGCSenseBuffer(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
1789{
1790 PVM pVM = PDMDevHlpGetVM(pLsiLogic->CTX_SUFF(pDevIns));
1791
1792 PGMPhysReleasePageMappingLock(pVM, &pTaskState->PageLockSense);
1793 pTaskState->pbSenseBuffer = NULL;
1794}
1795
1796/**
1797 * Map the sense buffer into R3.
1798 *
1799 * @returns VBox status code.
1800 * @param pTaskState Pointer to the task state.
1801 * @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary.
1802 */
1803static int lsilogicMapGCSenseBufferIntoR3(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
1804{
1805 int rc = VINF_SUCCESS;
1806 PPDMDEVINS pDevIns = pLsiLogic->CTX_SUFF(pDevIns);
1807 RTGCPHYS GCPhysAddrSenseBuffer;
1808
1809 GCPhysAddrSenseBuffer = pTaskState->GuestRequest.SCSIIO.u32SenseBufferLowAddress;
1810 GCPhysAddrSenseBuffer |= ((uint64_t)pLsiLogic->u32SenseBufferHighAddr << 32);
1811
1812#ifdef RT_STRICT
1813 uint32_t cbSenseBuffer = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
1814#endif
1815 RTGCPHYS GCPhysAddrSenseBufferBase = PAGE_ADDRESS(GCPhysAddrSenseBuffer);
1816
1817 AssertMsg(GCPhysAddrSenseBuffer >= GCPhysAddrSenseBufferBase,
1818 ("Impossible GCPhysAddrSenseBuffer < GCPhysAddrSenseBufferBase\n"));
1819
1820 /* Sanity checks for the assumption. */
1821 AssertMsg(((GCPhysAddrSenseBuffer + cbSenseBuffer) <= (GCPhysAddrSenseBufferBase + PAGE_SIZE)),
1822 ("Sense buffer crosses page boundary\n"));
1823
1824 rc = PDMDevHlpPhysGCPhys2CCPtr(pDevIns, GCPhysAddrSenseBufferBase, (void **)&pTaskState->pbSenseBuffer, &pTaskState->PageLockSense);
1825 AssertMsgRC(rc, ("Mapping sense buffer failed rc=%Rrc\n", rc));
1826
1827 /* Correct start address of the sense buffer. */
1828 pTaskState->pbSenseBuffer += (GCPhysAddrSenseBuffer - GCPhysAddrSenseBufferBase);
1829
1830 return rc;
1831}
1832#endif
1833
1834#ifdef DEBUG
1835static void lsilogicDumpSCSIIORequest(PMptSCSIIORequest pSCSIIORequest)
1836{
1837 Log(("%s: u8TargetID=%d\n", __FUNCTION__, pSCSIIORequest->u8TargetID));
1838 Log(("%s: u8Bus=%d\n", __FUNCTION__, pSCSIIORequest->u8Bus));
1839 Log(("%s: u8ChainOffset=%d\n", __FUNCTION__, pSCSIIORequest->u8ChainOffset));
1840 Log(("%s: u8Function=%d\n", __FUNCTION__, pSCSIIORequest->u8Function));
1841 Log(("%s: u8CDBLength=%d\n", __FUNCTION__, pSCSIIORequest->u8CDBLength));
1842 Log(("%s: u8SenseBufferLength=%d\n", __FUNCTION__, pSCSIIORequest->u8SenseBufferLength));
1843 Log(("%s: u8MessageFlags=%d\n", __FUNCTION__, pSCSIIORequest->u8MessageFlags));
1844 Log(("%s: u32MessageContext=%#x\n", __FUNCTION__, pSCSIIORequest->u32MessageContext));
1845 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8LUN); i++)
1846 Log(("%s: u8LUN[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8LUN[i]));
1847 Log(("%s: u32Control=%#x\n", __FUNCTION__, pSCSIIORequest->u32Control));
1848 for (unsigned i = 0; i < RT_ELEMENTS(pSCSIIORequest->au8CDB); i++)
1849 Log(("%s: u8CDB[%d]=%d\n", __FUNCTION__, i, pSCSIIORequest->au8CDB[i]));
1850 Log(("%s: u32DataLength=%#x\n", __FUNCTION__, pSCSIIORequest->u32DataLength));
1851 Log(("%s: u32SenseBufferLowAddress=%#x\n", __FUNCTION__, pSCSIIORequest->u32SenseBufferLowAddress));
1852}
1853#endif
1854
1855/**
1856 * Processes a SCSI I/O request by setting up the request
1857 * and sending it to the underlying SCSI driver.
1858 * Steps needed to complete request are done in the
1859 * callback called by the driver below upon completion of
1860 * the request.
1861 *
1862 * @returns VBox status code.
1863 * @param pLsiLogic Pointer to the device instance which sends the request.
1864 * @param pTaskState Pointer to the task state data.
1865 */
1866static int lsilogicProcessSCSIIORequest(PLSILOGICSCSI pLsiLogic, PLSILOGICTASKSTATE pTaskState)
1867{
1868 int rc = VINF_SUCCESS;
1869
1870#ifdef DEBUG
1871 lsilogicDumpSCSIIORequest(&pTaskState->GuestRequest.SCSIIO);
1872#endif
1873
1874 pTaskState->fBIOS = false;
1875
1876 uint32_t uChainOffset = pTaskState->GuestRequest.SCSIIO.u8ChainOffset;
1877
1878 if (uChainOffset)
1879 uChainOffset = uChainOffset * sizeof(uint32_t) - sizeof(MptSCSIIORequest);
1880
1881 /* Create Scatter gather list. */
1882 rc = lsilogicScatterGatherListCreate(pLsiLogic, pTaskState,
1883 pTaskState->GCPhysMessageFrameAddr + sizeof(MptSCSIIORequest),
1884 uChainOffset);
1885 AssertRC(rc);
1886
1887#if 0
1888 /* Map sense buffer. */
1889 rc = lsilogicMapGCSenseBufferIntoR3(pLsiLogic, pTaskState);
1890 AssertRC(rc);
1891#endif
1892
1893 if (RT_LIKELY( (pTaskState->GuestRequest.SCSIIO.u8TargetID < pLsiLogic->cDeviceStates)
1894 && (pTaskState->GuestRequest.SCSIIO.u8Bus == 0)))
1895 {
1896 PLSILOGICDEVICE pTargetDevice;
1897 pTargetDevice = &pLsiLogic->paDeviceStates[pTaskState->GuestRequest.SCSIIO.u8TargetID];
1898
1899 if (pTargetDevice->pDrvBase)
1900 {
1901 /* Setup the SCSI request. */
1902 pTaskState->pTargetDevice = pTargetDevice;
1903 pTaskState->PDMScsiRequest.uLogicalUnit = pTaskState->GuestRequest.SCSIIO.au8LUN[1];
1904
1905 uint8_t uDataDirection = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_GET(pTaskState->GuestRequest.SCSIIO.u32Control);
1906
1907 if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE)
1908 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_NONE;
1909 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE)
1910 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_TO_DEVICE;
1911 else if (uDataDirection == MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ)
1912 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_FROM_DEVICE;
1913
1914 pTaskState->PDMScsiRequest.cbCDB = pTaskState->GuestRequest.SCSIIO.u8CDBLength;
1915 pTaskState->PDMScsiRequest.pbCDB = pTaskState->GuestRequest.SCSIIO.au8CDB;
1916 pTaskState->PDMScsiRequest.cbScatterGather = pTaskState->GuestRequest.SCSIIO.u32DataLength;
1917 pTaskState->PDMScsiRequest.cScatterGatherEntries = pTaskState->cSGListEntries;
1918 pTaskState->PDMScsiRequest.paScatterGatherHead = pTaskState->pSGListHead;
1919 pTaskState->PDMScsiRequest.cbSenseBuffer = sizeof(pTaskState->abSenseBuffer);
1920 memset(pTaskState->abSenseBuffer, 0, pTaskState->PDMScsiRequest.cbSenseBuffer);
1921 pTaskState->PDMScsiRequest.pbSenseBuffer = pTaskState->abSenseBuffer;
1922 pTaskState->PDMScsiRequest.pvUser = pTaskState;
1923
1924 ASMAtomicIncU32(&pTargetDevice->cOutstandingRequests);
1925 rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest);
1926 AssertMsgRC(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc));
1927 return VINF_SUCCESS;
1928 }
1929 else
1930 {
1931 /* Device is not present report SCSI selection timeout. */
1932 pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_DEVICE_NOT_THERE;
1933 }
1934 }
1935 else
1936 {
1937 /* Report out of bounds target ID or bus. */
1938 if (pTaskState->GuestRequest.SCSIIO.u8Bus != 0)
1939 pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_BUS;
1940 else
1941 pTaskState->IOCReply.SCSIIOError.u16IOCStatus = MPT_SCSI_IO_ERROR_IOCSTATUS_INVALID_TARGETID;
1942 }
1943
1944 /* The rest is equal to both errors. */
1945 pTaskState->IOCReply.SCSIIOError.u8TargetID = pTaskState->GuestRequest.SCSIIO.u8TargetID;
1946 pTaskState->IOCReply.SCSIIOError.u8Bus = pTaskState->GuestRequest.SCSIIO.u8Bus;
1947 pTaskState->IOCReply.SCSIIOError.u8MessageLength = sizeof(MptSCSIIOErrorReply) / 4;
1948 pTaskState->IOCReply.SCSIIOError.u8Function = pTaskState->GuestRequest.SCSIIO.u8Function;
1949 pTaskState->IOCReply.SCSIIOError.u8CDBLength = pTaskState->GuestRequest.SCSIIO.u8CDBLength;
1950 pTaskState->IOCReply.SCSIIOError.u8SenseBufferLength = pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength;
1951 pTaskState->IOCReply.SCSIIOError.u32MessageContext = pTaskState->GuestRequest.SCSIIO.u32MessageContext;
1952 pTaskState->IOCReply.SCSIIOError.u8SCSIStatus = SCSI_STATUS_OK;
1953 pTaskState->IOCReply.SCSIIOError.u8SCSIState = MPT_SCSI_IO_ERROR_SCSI_STATE_TERMINATED;
1954 pTaskState->IOCReply.SCSIIOError.u32IOCLogInfo = 0;
1955 pTaskState->IOCReply.SCSIIOError.u32TransferCount = 0;
1956 pTaskState->IOCReply.SCSIIOError.u32SenseCount = 0;
1957 pTaskState->IOCReply.SCSIIOError.u32ResponseInfo = 0;
1958
1959 lsilogicFinishAddressReply(pLsiLogic, &pTaskState->IOCReply, false);
1960 RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState);
1961
1962 return rc;
1963}
1964
1965/**
1966 * Called upon completion of the request from the SCSI driver below.
1967 * This function frees all allocated ressources and notifies the guest
1968 * that the process finished by asserting an interrupt.
1969 *
1970 * @returns VBox status code.
1971 * @param pInterface Pointer to the interface the called funtion belongs to.
1972 * @param pSCSIRequest Pointer to the SCSI request which finished.
1973 */
1974static DECLCALLBACK(int) lsilogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, int rcCompletion)
1975{
1976 PLSILOGICTASKSTATE pTaskState = (PLSILOGICTASKSTATE)pSCSIRequest->pvUser;
1977 PLSILOGICDEVICE pLsiLogicDevice = pTaskState->pTargetDevice;
1978 PLSILOGICSCSI pLsiLogic = pLsiLogicDevice->CTX_SUFF(pLsiLogic);
1979
1980 ASMAtomicDecU32(&pLsiLogicDevice->cOutstandingRequests);
1981
1982 if (RT_UNLIKELY(pTaskState->fBIOS))
1983 {
1984 int rc = vboxscsiRequestFinished(&pLsiLogic->VBoxSCSI, pSCSIRequest);
1985 AssertMsgRC(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc));
1986 }
1987 else
1988 {
1989#if 0
1990 lsilogicFreeGCSenseBuffer(pLsiLogic, pTaskState);
1991#else
1992 RTGCPHYS GCPhysAddrSenseBuffer;
1993
1994 GCPhysAddrSenseBuffer = pTaskState->GuestRequest.SCSIIO.u32SenseBufferLowAddress;
1995 GCPhysAddrSenseBuffer |= ((uint64_t)pLsiLogic->u32SenseBufferHighAddr << 32);
1996
1997 /* Copy the sense buffer over. */
1998 PDMDevHlpPhysWrite(pLsiLogic->CTX_SUFF(pDevIns), GCPhysAddrSenseBuffer, pTaskState->abSenseBuffer,
1999 RT_UNLIKELY(pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength < pTaskState->PDMScsiRequest.cbSenseBuffer)
2000 ? pTaskState->GuestRequest.SCSIIO.u8SenseBufferLength
2001 : pTaskState->PDMScsiRequest.cbSenseBuffer);
2002#endif
2003 lsilogicScatterGatherListDestroy(pLsiLogic, pTaskState);
2004
2005
2006 if (RT_LIKELY(rcCompletion == SCSI_STATUS_OK))
2007 lsilogicFinishContextReply(pLsiLogic, pTaskState->GuestRequest.SCSIIO.u32MessageContext);
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 pTaskState->GCPhysMessageFrameAddr = GCPhysMessageFrameAddr;
3397
3398 /* Read the message header from the guest first. */
3399 PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, sizeof(MptMessageHdr));
3400
3401 /* Determine the size of the request. */
3402 uint32_t cbRequest = 0;
3403
3404 switch (pTaskState->GuestRequest.Header.u8Function)
3405 {
3406 case MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST:
3407 cbRequest = sizeof(MptSCSIIORequest);
3408 break;
3409 case MPT_MESSAGE_HDR_FUNCTION_SCSI_TASK_MGMT:
3410 cbRequest = sizeof(MptSCSITaskManagementRequest);
3411 break;
3412 case MPT_MESSAGE_HDR_FUNCTION_IOC_INIT:
3413 cbRequest = sizeof(MptIOCInitRequest);
3414 break;
3415 case MPT_MESSAGE_HDR_FUNCTION_IOC_FACTS:
3416 cbRequest = sizeof(MptIOCFactsRequest);
3417 break;
3418 case MPT_MESSAGE_HDR_FUNCTION_CONFIG:
3419 cbRequest = sizeof(MptConfigurationRequest);
3420 break;
3421 case MPT_MESSAGE_HDR_FUNCTION_PORT_FACTS:
3422 cbRequest = sizeof(MptPortFactsRequest);
3423 break;
3424 case MPT_MESSAGE_HDR_FUNCTION_PORT_ENABLE:
3425 cbRequest = sizeof(MptPortEnableRequest);
3426 break;
3427 case MPT_MESSAGE_HDR_FUNCTION_EVENT_NOTIFICATION:
3428 cbRequest = sizeof(MptEventNotificationRequest);
3429 break;
3430 case MPT_MESSAGE_HDR_FUNCTION_EVENT_ACK:
3431 AssertMsgFailed(("todo\n"));
3432 //cbRequest = sizeof(MptEventAckRequest);
3433 break;
3434 case MPT_MESSAGE_HDR_FUNCTION_FW_DOWNLOAD:
3435 AssertMsgFailed(("todo\n"));
3436 break;
3437 default:
3438 AssertMsgFailed(("Unknown function issued %u\n", pTaskState->GuestRequest.Header.u8Function));
3439 lsilogicSetIOCFaultCode(pLsiLogic, LSILOGIC_IOCSTATUS_INVALID_FUNCTION);
3440 }
3441
3442 if (cbRequest != 0)
3443 {
3444 /* Read the complete message frame from guest memory now. */
3445 PDMDevHlpPhysRead(pDevIns, GCPhysMessageFrameAddr, &pTaskState->GuestRequest, cbRequest);
3446
3447 /* Handle SCSI I/O requests now. */
3448 if (pTaskState->GuestRequest.Header.u8Function == MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST)
3449 {
3450 rc = lsilogicProcessSCSIIORequest(pLsiLogic, pTaskState);
3451 AssertRC(rc);
3452 }
3453 else
3454 {
3455 MptReplyUnion Reply;
3456 rc = lsilogicProcessMessageRequest(pLsiLogic, &pTaskState->GuestRequest.Header, &Reply);
3457 AssertRC(rc);
3458 RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState);
3459 }
3460
3461 pLsiLogic->uRequestQueueNextAddressRead++;
3462 pLsiLogic->uRequestQueueNextAddressRead %= pLsiLogic->cRequestQueueEntries;
3463 }
3464 }
3465
3466 return true;
3467}
3468
3469/**
3470 * Sets the emulated controller type from a given string.
3471 *
3472 * @returns VBox status code.
3473 *
3474 * @param pThis The LsiLogic devi state.
3475 * @param pcszCtrlType The string to use.
3476 */
3477static int lsilogicGetCtrlTypeFromString(PLSILOGICSCSI pThis, const char *pcszCtrlType)
3478{
3479 int rc = VERR_INVALID_PARAMETER;
3480
3481 if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME))
3482 {
3483 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SPI;
3484 rc = VINF_SUCCESS;
3485 }
3486 else if (!RTStrCmp(pcszCtrlType, LSILOGICSCSI_PCI_SAS_CTRLNAME))
3487 {
3488 pThis->enmCtrlType = LSILOGICCTRLTYPE_SCSI_SAS;
3489 rc = VINF_SUCCESS;
3490 }
3491
3492 return rc;
3493}
3494
3495/**
3496 * Port I/O Handler for IN operations - legacy port.
3497 *
3498 * @returns VBox status code.
3499 *
3500 * @param pDevIns The device instance.
3501 * @param pvUser User argument.
3502 * @param uPort Port number used for the IN operation.
3503 * @param pu32 Where to store the result.
3504 * @param cb Number of bytes read.
3505 */
3506static int lsilogicIsaIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
3507 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3508{
3509 int rc;
3510 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3511
3512 Assert(cb == 1);
3513
3514 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3515 ? Port - LSILOGIC_ISA_IO_PORT
3516 : Port - LSILOGIC_SAS_ISA_IO_PORT;
3517 rc = vboxscsiReadRegister(&pThis->VBoxSCSI, iRegister, pu32);
3518
3519 Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n",
3520 __FUNCTION__, pu32, 1, pu32, iRegister, rc));
3521
3522 return rc;
3523}
3524
3525/**
3526 * Prepares a request from the BIOS.
3527 *
3528 * @returns VBox status code.
3529 * @param pLsiLogic Pointer to the LsiLogic device instance.
3530 */
3531static int lsilogicPrepareBIOSSCSIRequest(PLSILOGICSCSI pLsiLogic)
3532{
3533 int rc;
3534 PLSILOGICTASKSTATE pTaskState;
3535 uint32_t uTargetDevice;
3536
3537 rc = RTMemCacheAllocEx(pLsiLogic->hTaskCache, (void **)&pTaskState);
3538 AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc);
3539
3540 pTaskState->fBIOS = true;
3541
3542 rc = vboxscsiSetupRequest(&pLsiLogic->VBoxSCSI, &pTaskState->PDMScsiRequest, &uTargetDevice);
3543 AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc);
3544
3545 pTaskState->PDMScsiRequest.pvUser = pTaskState;
3546
3547 if (uTargetDevice < pLsiLogic->cDeviceStates)
3548 {
3549 pTaskState->pTargetDevice = &pLsiLogic->paDeviceStates[uTargetDevice];
3550
3551 if (pTaskState->pTargetDevice->pDrvBase)
3552 {
3553 ASMAtomicIncU32(&pTaskState->pTargetDevice->cOutstandingRequests);
3554
3555 rc = pTaskState->pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->pTargetDevice->pDrvSCSIConnector,
3556 &pTaskState->PDMScsiRequest);
3557 AssertMsgRCReturn(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc), rc);
3558 return VINF_SUCCESS;
3559 }
3560 }
3561
3562 /* Device is not present. */
3563 AssertMsg(pTaskState->PDMScsiRequest.pbCDB[0] == SCSI_INQUIRY,
3564 ("Device is not present but command is not inquiry\n"));
3565
3566 SCSIINQUIRYDATA ScsiInquiryData;
3567
3568 memset(&ScsiInquiryData, 0, sizeof(SCSIINQUIRYDATA));
3569 ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
3570 ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
3571
3572 memcpy(pLsiLogic->VBoxSCSI.pBuf, &ScsiInquiryData, 5);
3573
3574 rc = vboxscsiRequestFinished(&pLsiLogic->VBoxSCSI, &pTaskState->PDMScsiRequest);
3575 AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc);
3576
3577 RTMemCacheFree(pLsiLogic->hTaskCache, pTaskState);
3578 return rc;
3579}
3580
3581/**
3582 * Port I/O Handler for OUT operations - legacy port.
3583 *
3584 * @returns VBox status code.
3585 *
3586 * @param pDevIns The device instance.
3587 * @param pvUser User argument.
3588 * @param uPort Port number used for the IN operation.
3589 * @param u32 The value to output.
3590 * @param cb The value size in bytes.
3591 */
3592static int lsilogicIsaIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
3593 RTIOPORT Port, uint32_t u32, unsigned cb)
3594{
3595 int rc;
3596 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3597
3598 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n",
3599 pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port));
3600
3601 Assert(cb == 1);
3602
3603 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3604 ? Port - LSILOGIC_ISA_IO_PORT
3605 : Port - LSILOGIC_SAS_ISA_IO_PORT;
3606 rc = vboxscsiWriteRegister(&pThis->VBoxSCSI, iRegister, (uint8_t)u32);
3607 if (rc == VERR_MORE_DATA)
3608 {
3609 rc = lsilogicPrepareBIOSSCSIRequest(pThis);
3610 AssertRC(rc);
3611 }
3612 else if (RT_FAILURE(rc))
3613 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
3614
3615 return VINF_SUCCESS;
3616}
3617
3618/**
3619 * Port I/O Handler for primary port range OUT string operations.
3620 * @see FNIOMIOPORTOUTSTRING for details.
3621 */
3622static DECLCALLBACK(int) lsilogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
3623{
3624 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3625 int rc;
3626
3627 Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
3628 pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
3629
3630 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3631 ? Port - LSILOGIC_ISA_IO_PORT
3632 : Port - LSILOGIC_SAS_ISA_IO_PORT;
3633 rc = vboxscsiWriteString(pDevIns, &pThis->VBoxSCSI, iRegister,
3634 pGCPtrSrc, pcTransfer, cb);
3635 if (rc == VERR_MORE_DATA)
3636 {
3637 rc = lsilogicPrepareBIOSSCSIRequest(pThis);
3638 AssertRC(rc);
3639 }
3640 else if (RT_FAILURE(rc))
3641 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
3642
3643 return rc;
3644}
3645
3646/**
3647 * Port I/O Handler for primary port range IN string operations.
3648 * @see FNIOMIOPORTINSTRING for details.
3649 */
3650static DECLCALLBACK(int) lsilogicIsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
3651{
3652 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3653
3654 LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
3655 pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
3656
3657 uint8_t iRegister = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3658 ? Port - LSILOGIC_ISA_IO_PORT
3659 : Port - LSILOGIC_SAS_ISA_IO_PORT;
3660 return vboxscsiReadString(pDevIns, &pThis->VBoxSCSI, iRegister,
3661 pGCPtrDst, pcTransfer, cb);
3662}
3663
3664static DECLCALLBACK(int) lsilogicMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3665 RTGCPHYS GCPhysAddress, uint32_t cb,
3666 PCIADDRESSSPACE enmType)
3667{
3668 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3669 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3670 int rc = VINF_SUCCESS;
3671 const char *pcszCtrl = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3672 ? "LsiLogic"
3673 : "LsiLogicSas";
3674 const char *pcszDiag = pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
3675 ? "LsiLogicDiag"
3676 : "LsiLogicSasDiag";
3677
3678 Log2(("%s: registering area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
3679
3680 AssertMsg( (enmType == PCI_ADDRESS_SPACE_MEM && cb >= LSILOGIC_PCI_SPACE_MEM_SIZE)
3681 || (enmType == PCI_ADDRESS_SPACE_IO && cb >= LSILOGIC_PCI_SPACE_IO_SIZE),
3682 ("PCI region type and size do not match\n"));
3683
3684 if ((enmType == PCI_ADDRESS_SPACE_MEM) && (iRegion == 1))
3685 {
3686 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3687 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
3688 lsilogicMMIOWrite, lsilogicMMIORead, NULL, pcszCtrl);
3689 if (RT_FAILURE(rc))
3690 return rc;
3691
3692 if (pThis->fR0Enabled)
3693 {
3694 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
3695 "lsilogicMMIOWrite", "lsilogicMMIORead", NULL);
3696 if (RT_FAILURE(rc))
3697 return rc;
3698 }
3699
3700 if (pThis->fGCEnabled)
3701 {
3702 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, 0,
3703 "lsilogicMMIOWrite", "lsilogicMMIORead", NULL);
3704 if (RT_FAILURE(rc))
3705 return rc;
3706 }
3707
3708 pThis->GCPhysMMIOBase = GCPhysAddress;
3709 }
3710 else if ((enmType == PCI_ADDRESS_SPACE_MEM) && (iRegion == 2))
3711 {
3712 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3713 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
3714 lsilogicDiagnosticWrite, lsilogicDiagnosticRead, NULL, pcszDiag);
3715 if (RT_FAILURE(rc))
3716 return rc;
3717
3718 if (pThis->fR0Enabled)
3719 {
3720 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
3721 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead", NULL);
3722 if (RT_FAILURE(rc))
3723 return rc;
3724 }
3725
3726 if (pThis->fGCEnabled)
3727 {
3728 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, 0,
3729 "lsilogicDiagnosticWrite", "lsilogicDiagnosticRead", NULL);
3730 if (RT_FAILURE(rc))
3731 return rc;
3732 }
3733 }
3734 else if (enmType == PCI_ADDRESS_SPACE_IO)
3735 {
3736 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
3737 NULL, lsilogicIOPortWrite, lsilogicIOPortRead, NULL, NULL, pcszCtrl);
3738 if (RT_FAILURE(rc))
3739 return rc;
3740
3741 if (pThis->fR0Enabled)
3742 {
3743 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
3744 0, "lsilogicIOPortWrite", "lsilogicIOPortRead", NULL, NULL, pcszCtrl);
3745 if (RT_FAILURE(rc))
3746 return rc;
3747 }
3748
3749 if (pThis->fGCEnabled)
3750 {
3751 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, LSILOGIC_PCI_SPACE_IO_SIZE,
3752 0, "lsilogicIOPortWrite", "lsilogicIOPortRead", NULL, NULL, pcszCtrl);
3753 if (RT_FAILURE(rc))
3754 return rc;
3755 }
3756
3757 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
3758 }
3759 else
3760 AssertMsgFailed(("Invalid enmType=%d iRegion=%d\n", enmType, iRegion));
3761
3762 return rc;
3763}
3764
3765/**
3766 * Allocate the queues.
3767 *
3768 * @returns VBox status code.
3769 *
3770 * @param pThis The LsiLogic device instance.
3771 */
3772static int lsilogicQueuesAlloc(PLSILOGICSCSI pThis)
3773{
3774 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
3775 uint32_t cbQueues;
3776
3777 Assert(!pThis->pReplyFreeQueueBaseR3);
3778
3779 cbQueues = 2*pThis->cReplyQueueEntries * sizeof(uint32_t);
3780 cbQueues += pThis->cRequestQueueEntries * sizeof(uint32_t);
3781 int rc = MMHyperAlloc(pVM, cbQueues, 1, MM_TAG_PDM_DEVICE_USER,
3782 (void **)&pThis->pReplyFreeQueueBaseR3);
3783 if (RT_FAILURE(rc))
3784 return VERR_NO_MEMORY;
3785 pThis->pReplyFreeQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
3786 pThis->pReplyFreeQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
3787
3788 pThis->pReplyPostQueueBaseR3 = pThis->pReplyFreeQueueBaseR3 + pThis->cReplyQueueEntries;
3789 pThis->pReplyPostQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pReplyPostQueueBaseR3);
3790 pThis->pReplyPostQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pReplyPostQueueBaseR3);
3791
3792 pThis->pRequestQueueBaseR3 = pThis->pReplyPostQueueBaseR3 + pThis->cReplyQueueEntries;
3793 pThis->pRequestQueueBaseR0 = MMHyperR3ToR0(pVM, (void *)pThis->pRequestQueueBaseR3);
3794 pThis->pRequestQueueBaseRC = MMHyperR3ToRC(pVM, (void *)pThis->pRequestQueueBaseR3);
3795
3796 return VINF_SUCCESS;
3797}
3798
3799/**
3800 * Free the hyper memory used or the queues.
3801 *
3802 * @returns nothing.
3803 *
3804 * @param pThis The LsiLogic device instance.
3805 */
3806static void lsilogicQueuesFree(PLSILOGICSCSI pThis)
3807{
3808 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
3809 int rc = VINF_SUCCESS;
3810
3811 AssertPtr(pThis->pReplyFreeQueueBaseR3);
3812
3813 rc = MMHyperFree(pVM, (void *)pThis->pReplyFreeQueueBaseR3);
3814 AssertRC(rc);
3815
3816 pThis->pReplyFreeQueueBaseR3 = NULL;
3817 pThis->pReplyPostQueueBaseR3 = NULL;
3818 pThis->pRequestQueueBaseR3 = NULL;
3819}
3820
3821static DECLCALLBACK(int) lsilogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
3822{
3823 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3824
3825 SSMR3PutU32(pSSM, pThis->enmCtrlType);
3826 SSMR3PutU32(pSSM, pThis->cDeviceStates);
3827 SSMR3PutU32(pSSM, pThis->cPorts);
3828
3829 /* Save the device config. */
3830 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
3831 SSMR3PutBool(pSSM, pThis->paDeviceStates[i].pDrvBase != NULL);
3832
3833 return VINF_SSM_DONT_CALL_AGAIN;
3834}
3835
3836static DECLCALLBACK(int) lsilogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3837{
3838 PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3839
3840 /* Every device first. */
3841 lsilogicLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
3842 for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++)
3843 {
3844 PLSILOGICDEVICE pDevice = &pLsiLogic->paDeviceStates[i];
3845
3846 AssertMsg(!pDevice->cOutstandingRequests,
3847 ("There are still outstanding requests on this device\n"));
3848 SSMR3PutU32(pSSM, pDevice->cOutstandingRequests);
3849 }
3850 /* Now the main device state. */
3851 SSMR3PutU32 (pSSM, pLsiLogic->enmState);
3852 SSMR3PutU32 (pSSM, pLsiLogic->enmWhoInit);
3853 SSMR3PutBool (pSSM, pLsiLogic->fDoorbellInProgress);
3854 SSMR3PutBool (pSSM, pLsiLogic->fDiagnosticEnabled);
3855 SSMR3PutBool (pSSM, pLsiLogic->fNotificationSend);
3856 SSMR3PutBool (pSSM, pLsiLogic->fEventNotificationEnabled);
3857 SSMR3PutU32 (pSSM, pLsiLogic->uInterruptMask);
3858 SSMR3PutU32 (pSSM, pLsiLogic->uInterruptStatus);
3859 for (unsigned i = 0; i < RT_ELEMENTS(pLsiLogic->aMessage); i++)
3860 SSMR3PutU32 (pSSM, pLsiLogic->aMessage[i]);
3861 SSMR3PutU32 (pSSM, pLsiLogic->iMessage);
3862 SSMR3PutU32 (pSSM, pLsiLogic->cMessage);
3863 SSMR3PutMem (pSSM, &pLsiLogic->ReplyBuffer, sizeof(pLsiLogic->ReplyBuffer));
3864 SSMR3PutU32 (pSSM, pLsiLogic->uNextReplyEntryRead);
3865 SSMR3PutU32 (pSSM, pLsiLogic->cReplySize);
3866 SSMR3PutU16 (pSSM, pLsiLogic->u16IOCFaultCode);
3867 SSMR3PutU32 (pSSM, pLsiLogic->u32HostMFAHighAddr);
3868 SSMR3PutU32 (pSSM, pLsiLogic->u32SenseBufferHighAddr);
3869 SSMR3PutU8 (pSSM, pLsiLogic->cMaxDevices);
3870 SSMR3PutU8 (pSSM, pLsiLogic->cMaxBuses);
3871 SSMR3PutU16 (pSSM, pLsiLogic->cbReplyFrame);
3872 SSMR3PutU32 (pSSM, pLsiLogic->iDiagnosticAccess);
3873 SSMR3PutU32 (pSSM, pLsiLogic->cReplyQueueEntries);
3874 SSMR3PutU32 (pSSM, pLsiLogic->cRequestQueueEntries);
3875 SSMR3PutU32 (pSSM, pLsiLogic->uReplyFreeQueueNextEntryFreeWrite);
3876 SSMR3PutU32 (pSSM, pLsiLogic->uReplyFreeQueueNextAddressRead);
3877 SSMR3PutU32 (pSSM, pLsiLogic->uReplyPostQueueNextEntryFreeWrite);
3878 SSMR3PutU32 (pSSM, pLsiLogic->uReplyPostQueueNextAddressRead);
3879 SSMR3PutU32 (pSSM, pLsiLogic->uRequestQueueNextEntryFreeWrite);
3880 SSMR3PutU32 (pSSM, pLsiLogic->uRequestQueueNextAddressRead);
3881
3882 for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++)
3883 SSMR3PutU32(pSSM, pLsiLogic->pReplyFreeQueueBaseR3[i]);
3884 for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++)
3885 SSMR3PutU32(pSSM, pLsiLogic->pReplyPostQueueBaseR3[i]);
3886 for (unsigned i = 0; i < pLsiLogic->cRequestQueueEntries; i++)
3887 SSMR3PutU32(pSSM, pLsiLogic->pRequestQueueBaseR3[i]);
3888
3889 SSMR3PutU16 (pSSM, pLsiLogic->u16NextHandle);
3890
3891 PMptConfigurationPagesSupported pPages = pLsiLogic->pConfigurationPages;
3892
3893 SSMR3PutMem (pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
3894 SSMR3PutMem (pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
3895 SSMR3PutMem (pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
3896 SSMR3PutMem (pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
3897 SSMR3PutMem (pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
3898 SSMR3PutMem (pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
3899 SSMR3PutMem (pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
3900 SSMR3PutMem (pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
3901 SSMR3PutMem (pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
3902 SSMR3PutMem (pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
3903 SSMR3PutMem (pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
3904 SSMR3PutMem (pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
3905 SSMR3PutMem (pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
3906 SSMR3PutMem (pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
3907 SSMR3PutMem (pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
3908 SSMR3PutMem (pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
3909 SSMR3PutMem (pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
3910 SSMR3PutMem (pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
3911 SSMR3PutMem (pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
3912 SSMR3PutMem (pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
3913 SSMR3PutMem (pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
3914 SSMR3PutMem (pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
3915 SSMR3PutMem (pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
3916 SSMR3PutMem (pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
3917
3918 /* Device dependent pages */
3919 if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
3920 {
3921 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
3922
3923 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
3924 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
3925 SSMR3PutMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
3926
3927 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
3928 {
3929 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
3930 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
3931 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
3932 SSMR3PutMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
3933 }
3934 }
3935 else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
3936 {
3937 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
3938
3939 SSMR3PutU32(pSSM, pSasPages->cbManufacturingPage7);
3940 SSMR3PutU32(pSSM, pSasPages->cbSASIOUnitPage0);
3941 SSMR3PutU32(pSSM, pSasPages->cbSASIOUnitPage1);
3942
3943 SSMR3PutMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
3944 SSMR3PutMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
3945 SSMR3PutMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
3946
3947 SSMR3PutMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
3948 SSMR3PutMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
3949
3950 SSMR3PutU32(pSSM, pSasPages->cPHYs);
3951 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
3952 {
3953 SSMR3PutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
3954 SSMR3PutMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
3955 }
3956
3957 /* The number of devices first. */
3958 SSMR3PutU32(pSSM, pSasPages->cDevices);
3959
3960 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
3961
3962 while (pCurr)
3963 {
3964 SSMR3PutMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
3965 SSMR3PutMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
3966 SSMR3PutMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
3967
3968 pCurr = pCurr->pNext;
3969 }
3970 }
3971 else
3972 AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType));
3973
3974 /* Now the data for the BIOS interface. */
3975 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.regIdentify);
3976 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.uTargetDevice);
3977 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.uTxDir);
3978 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.cbCDB);
3979 SSMR3PutMem (pSSM, pLsiLogic->VBoxSCSI.aCDB, sizeof(pLsiLogic->VBoxSCSI.aCDB));
3980 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.iCDB);
3981 SSMR3PutU32 (pSSM, pLsiLogic->VBoxSCSI.cbBuf);
3982 SSMR3PutU32 (pSSM, pLsiLogic->VBoxSCSI.iBuf);
3983 SSMR3PutBool (pSSM, pLsiLogic->VBoxSCSI.fBusy);
3984 SSMR3PutU8 (pSSM, pLsiLogic->VBoxSCSI.enmState);
3985 if (pLsiLogic->VBoxSCSI.cbCDB)
3986 SSMR3PutMem(pSSM, pLsiLogic->VBoxSCSI.pBuf, pLsiLogic->VBoxSCSI.cbBuf);
3987
3988 return SSMR3PutU32(pSSM, ~0);
3989}
3990
3991static DECLCALLBACK(int) lsilogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3992{
3993 PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
3994 int rc;
3995
3996 if ( uVersion != LSILOGIC_SAVED_STATE_VERSION
3997 && uVersion != LSILOGIC_SAVED_STATE_VERSION_PRE_SAS
3998 && uVersion != LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
3999 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4000
4001 /* device config */
4002 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4003 {
4004 LSILOGICCTRLTYPE enmCtrlType;
4005 uint32_t cDeviceStates, cPorts;
4006
4007 rc = SSMR3GetU32(pSSM, (uint32_t *)&enmCtrlType);
4008 AssertRCReturn(rc, rc);
4009 rc = SSMR3GetU32(pSSM, &cDeviceStates);
4010 AssertRCReturn(rc, rc);
4011 rc = SSMR3GetU32(pSSM, &cPorts);
4012 AssertRCReturn(rc, rc);
4013
4014 if (enmCtrlType != pLsiLogic->enmCtrlType)
4015 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Controller type): config=%d state=%d"),
4016 pLsiLogic->enmCtrlType, enmCtrlType);
4017 if (cDeviceStates != pLsiLogic->cDeviceStates)
4018 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Device states): config=%u state=%u"),
4019 pLsiLogic->cDeviceStates, cDeviceStates);
4020 if (cPorts != pLsiLogic->cPorts)
4021 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target config mismatch (Ports): config=%u state=%u"),
4022 pLsiLogic->cPorts, cPorts);
4023 }
4024 if (uVersion > LSILOGIC_SAVED_STATE_VERSION_VBOX_30)
4025 {
4026 for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++)
4027 {
4028 bool fPresent;
4029 rc = SSMR3GetBool(pSSM, &fPresent);
4030 AssertRCReturn(rc, rc);
4031 if (fPresent != (pLsiLogic->paDeviceStates[i].pDrvBase != NULL))
4032 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"),
4033 i, pLsiLogic->paDeviceStates[i].pDrvBase != NULL, fPresent);
4034 }
4035 }
4036 if (uPass != SSM_PASS_FINAL)
4037 return VINF_SUCCESS;
4038
4039 /* Every device first. */
4040 for (unsigned i = 0; i < pLsiLogic->cDeviceStates; i++)
4041 {
4042 PLSILOGICDEVICE pDevice = &pLsiLogic->paDeviceStates[i];
4043
4044 AssertMsg(!pDevice->cOutstandingRequests,
4045 ("There are still outstanding requests on this device\n"));
4046 SSMR3GetU32(pSSM, (uint32_t *)&pDevice->cOutstandingRequests);
4047 }
4048 /* Now the main device state. */
4049 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->enmState);
4050 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->enmWhoInit);
4051 SSMR3GetBool (pSSM, &pLsiLogic->fDoorbellInProgress);
4052 SSMR3GetBool (pSSM, &pLsiLogic->fDiagnosticEnabled);
4053 SSMR3GetBool (pSSM, &pLsiLogic->fNotificationSend);
4054 SSMR3GetBool (pSSM, &pLsiLogic->fEventNotificationEnabled);
4055 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uInterruptMask);
4056 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uInterruptStatus);
4057 for (unsigned i = 0; i < RT_ELEMENTS(pLsiLogic->aMessage); i++)
4058 SSMR3GetU32 (pSSM, &pLsiLogic->aMessage[i]);
4059 SSMR3GetU32 (pSSM, &pLsiLogic->iMessage);
4060 SSMR3GetU32 (pSSM, &pLsiLogic->cMessage);
4061 SSMR3GetMem (pSSM, &pLsiLogic->ReplyBuffer, sizeof(pLsiLogic->ReplyBuffer));
4062 SSMR3GetU32 (pSSM, &pLsiLogic->uNextReplyEntryRead);
4063 SSMR3GetU32 (pSSM, &pLsiLogic->cReplySize);
4064 SSMR3GetU16 (pSSM, &pLsiLogic->u16IOCFaultCode);
4065 SSMR3GetU32 (pSSM, &pLsiLogic->u32HostMFAHighAddr);
4066 SSMR3GetU32 (pSSM, &pLsiLogic->u32SenseBufferHighAddr);
4067 SSMR3GetU8 (pSSM, &pLsiLogic->cMaxDevices);
4068 SSMR3GetU8 (pSSM, &pLsiLogic->cMaxBuses);
4069 SSMR3GetU16 (pSSM, &pLsiLogic->cbReplyFrame);
4070 SSMR3GetU32 (pSSM, &pLsiLogic->iDiagnosticAccess);
4071
4072 uint32_t cReplyQueueEntries, cRequestQueueEntries;
4073 SSMR3GetU32 (pSSM, &cReplyQueueEntries);
4074 SSMR3GetU32 (pSSM, &cRequestQueueEntries);
4075
4076 if ( cReplyQueueEntries != pLsiLogic->cReplyQueueEntries
4077 || cRequestQueueEntries != pLsiLogic->cRequestQueueEntries)
4078 {
4079 LogFlow(("Reallocating queues cReplyQueueEntries=%u cRequestQueuEntries=%u\n",
4080 cReplyQueueEntries, cRequestQueueEntries));
4081 lsilogicQueuesFree(pLsiLogic);
4082 pLsiLogic->cReplyQueueEntries = cReplyQueueEntries;
4083 pLsiLogic->cRequestQueueEntries = cRequestQueueEntries;
4084 rc = lsilogicQueuesAlloc(pLsiLogic);
4085 if (RT_FAILURE(rc))
4086 return rc;
4087 }
4088
4089 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyFreeQueueNextEntryFreeWrite);
4090 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyFreeQueueNextAddressRead);
4091 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyPostQueueNextEntryFreeWrite);
4092 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uReplyPostQueueNextAddressRead);
4093 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uRequestQueueNextEntryFreeWrite);
4094 SSMR3GetU32 (pSSM, (uint32_t *)&pLsiLogic->uRequestQueueNextAddressRead);
4095
4096 PMptConfigurationPagesSupported pPages = pLsiLogic->pConfigurationPages;
4097
4098 if (uVersion <= LSILOGIC_SAVED_STATE_VERSION_PRE_SAS)
4099 {
4100 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4101 MptConfigurationPagesSupported_SSM_V2 ConfigPagesV2;
4102
4103 if (pLsiLogic->enmCtrlType != LSILOGICCTRLTYPE_SCSI_SPI)
4104 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: Expected SPI SCSI controller"));
4105
4106 SSMR3GetMem(pSSM, &ConfigPagesV2,
4107 sizeof(MptConfigurationPagesSupported_SSM_V2));
4108
4109 pPages->ManufacturingPage0 = ConfigPagesV2.ManufacturingPage0;
4110 pPages->ManufacturingPage1 = ConfigPagesV2.ManufacturingPage1;
4111 pPages->ManufacturingPage2 = ConfigPagesV2.ManufacturingPage2;
4112 pPages->ManufacturingPage3 = ConfigPagesV2.ManufacturingPage3;
4113 pPages->ManufacturingPage4 = ConfigPagesV2.ManufacturingPage4;
4114 pPages->IOUnitPage0 = ConfigPagesV2.IOUnitPage0;
4115 pPages->IOUnitPage1 = ConfigPagesV2.IOUnitPage1;
4116 pPages->IOUnitPage2 = ConfigPagesV2.IOUnitPage2;
4117 pPages->IOUnitPage3 = ConfigPagesV2.IOUnitPage3;
4118 pPages->IOCPage0 = ConfigPagesV2.IOCPage0;
4119 pPages->IOCPage1 = ConfigPagesV2.IOCPage1;
4120 pPages->IOCPage2 = ConfigPagesV2.IOCPage2;
4121 pPages->IOCPage3 = ConfigPagesV2.IOCPage3;
4122 pPages->IOCPage4 = ConfigPagesV2.IOCPage4;
4123 pPages->IOCPage6 = ConfigPagesV2.IOCPage6;
4124
4125 pSpiPages->aPortPages[0].SCSISPIPortPage0 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage0;
4126 pSpiPages->aPortPages[0].SCSISPIPortPage1 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage1;
4127 pSpiPages->aPortPages[0].SCSISPIPortPage2 = ConfigPagesV2.aPortPages[0].SCSISPIPortPage2;
4128
4129 for (unsigned i = 0; i < RT_ELEMENTS(pPages->u.SpiPages.aBuses[0].aDevicePages); i++)
4130 {
4131 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage0;
4132 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage1;
4133 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage2;
4134 pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3 = ConfigPagesV2.aBuses[0].aDevicePages[i].SCSISPIDevicePage3;
4135 }
4136 }
4137 else
4138 {
4139 /* Queue content */
4140 for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++)
4141 SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pReplyFreeQueueBaseR3[i]);
4142 for (unsigned i = 0; i < pLsiLogic->cReplyQueueEntries; i++)
4143 SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pReplyPostQueueBaseR3[i]);
4144 for (unsigned i = 0; i < pLsiLogic->cRequestQueueEntries; i++)
4145 SSMR3GetU32(pSSM, (uint32_t *)&pLsiLogic->pRequestQueueBaseR3[i]);
4146
4147 SSMR3GetU16(pSSM, &pLsiLogic->u16NextHandle);
4148
4149 /* Configuration pages */
4150 SSMR3GetMem(pSSM, &pPages->ManufacturingPage0, sizeof(MptConfigurationPageManufacturing0));
4151 SSMR3GetMem(pSSM, &pPages->ManufacturingPage1, sizeof(MptConfigurationPageManufacturing1));
4152 SSMR3GetMem(pSSM, &pPages->ManufacturingPage2, sizeof(MptConfigurationPageManufacturing2));
4153 SSMR3GetMem(pSSM, &pPages->ManufacturingPage3, sizeof(MptConfigurationPageManufacturing3));
4154 SSMR3GetMem(pSSM, &pPages->ManufacturingPage4, sizeof(MptConfigurationPageManufacturing4));
4155 SSMR3GetMem(pSSM, &pPages->ManufacturingPage5, sizeof(MptConfigurationPageManufacturing5));
4156 SSMR3GetMem(pSSM, &pPages->ManufacturingPage6, sizeof(MptConfigurationPageManufacturing6));
4157 SSMR3GetMem(pSSM, &pPages->ManufacturingPage8, sizeof(MptConfigurationPageManufacturing8));
4158 SSMR3GetMem(pSSM, &pPages->ManufacturingPage9, sizeof(MptConfigurationPageManufacturing9));
4159 SSMR3GetMem(pSSM, &pPages->ManufacturingPage10, sizeof(MptConfigurationPageManufacturing10));
4160 SSMR3GetMem(pSSM, &pPages->IOUnitPage0, sizeof(MptConfigurationPageIOUnit0));
4161 SSMR3GetMem(pSSM, &pPages->IOUnitPage1, sizeof(MptConfigurationPageIOUnit1));
4162 SSMR3GetMem(pSSM, &pPages->IOUnitPage2, sizeof(MptConfigurationPageIOUnit2));
4163 SSMR3GetMem(pSSM, &pPages->IOUnitPage3, sizeof(MptConfigurationPageIOUnit3));
4164 SSMR3GetMem(pSSM, &pPages->IOUnitPage4, sizeof(MptConfigurationPageIOUnit4));
4165 SSMR3GetMem(pSSM, &pPages->IOCPage0, sizeof(MptConfigurationPageIOC0));
4166 SSMR3GetMem(pSSM, &pPages->IOCPage1, sizeof(MptConfigurationPageIOC1));
4167 SSMR3GetMem(pSSM, &pPages->IOCPage2, sizeof(MptConfigurationPageIOC2));
4168 SSMR3GetMem(pSSM, &pPages->IOCPage3, sizeof(MptConfigurationPageIOC3));
4169 SSMR3GetMem(pSSM, &pPages->IOCPage4, sizeof(MptConfigurationPageIOC4));
4170 SSMR3GetMem(pSSM, &pPages->IOCPage6, sizeof(MptConfigurationPageIOC6));
4171 SSMR3GetMem(pSSM, &pPages->BIOSPage1, sizeof(MptConfigurationPageBIOS1));
4172 SSMR3GetMem(pSSM, &pPages->BIOSPage2, sizeof(MptConfigurationPageBIOS2));
4173 SSMR3GetMem(pSSM, &pPages->BIOSPage4, sizeof(MptConfigurationPageBIOS4));
4174
4175 /* Device dependent pages */
4176 if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4177 {
4178 PMptConfigurationPagesSpi pSpiPages = &pPages->u.SpiPages;
4179
4180 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage0, sizeof(MptConfigurationPageSCSISPIPort0));
4181 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage1, sizeof(MptConfigurationPageSCSISPIPort1));
4182 SSMR3GetMem(pSSM, &pSpiPages->aPortPages[0].SCSISPIPortPage2, sizeof(MptConfigurationPageSCSISPIPort2));
4183
4184 for (unsigned i = 0; i < RT_ELEMENTS(pSpiPages->aBuses[0].aDevicePages); i++)
4185 {
4186 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage0, sizeof(MptConfigurationPageSCSISPIDevice0));
4187 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage1, sizeof(MptConfigurationPageSCSISPIDevice1));
4188 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage2, sizeof(MptConfigurationPageSCSISPIDevice2));
4189 SSMR3GetMem(pSSM, &pSpiPages->aBuses[0].aDevicePages[i].SCSISPIDevicePage3, sizeof(MptConfigurationPageSCSISPIDevice3));
4190 }
4191 }
4192 else if (pLsiLogic->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4193 {
4194 uint32_t cbPage0, cbPage1, cPHYs, cbManufacturingPage7;
4195 PMptConfigurationPagesSas pSasPages = &pPages->u.SasPages;
4196
4197 SSMR3GetU32(pSSM, &cbManufacturingPage7);
4198 SSMR3GetU32(pSSM, &cbPage0);
4199 SSMR3GetU32(pSSM, &cbPage1);
4200
4201 if ( (cbPage0 != pSasPages->cbSASIOUnitPage0)
4202 || (cbPage1 != pSasPages->cbSASIOUnitPage1)
4203 || (cbManufacturingPage7 != pSasPages->cbManufacturingPage7))
4204 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4205
4206 AssertPtr(pSasPages->pManufacturingPage7);
4207 AssertPtr(pSasPages->pSASIOUnitPage0);
4208 AssertPtr(pSasPages->pSASIOUnitPage1);
4209
4210 SSMR3GetMem(pSSM, pSasPages->pManufacturingPage7, pSasPages->cbManufacturingPage7);
4211 SSMR3GetMem(pSSM, pSasPages->pSASIOUnitPage0, pSasPages->cbSASIOUnitPage0);
4212 SSMR3GetMem(pSSM, pSasPages->pSASIOUnitPage1, pSasPages->cbSASIOUnitPage1);
4213
4214 SSMR3GetMem(pSSM, &pSasPages->SASIOUnitPage2, sizeof(MptConfigurationPageSASIOUnit2));
4215 SSMR3GetMem(pSSM, &pSasPages->SASIOUnitPage3, sizeof(MptConfigurationPageSASIOUnit3));
4216
4217 SSMR3GetU32(pSSM, &cPHYs);
4218 if (cPHYs != pSasPages->cPHYs)
4219 return VERR_SSM_LOAD_CONFIG_MISMATCH;
4220
4221 AssertPtr(pSasPages->paPHYs);
4222 for (unsigned i = 0; i < pSasPages->cPHYs; i++)
4223 {
4224 SSMR3GetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage0, sizeof(MptConfigurationPageSASPHY0));
4225 SSMR3GetMem(pSSM, &pSasPages->paPHYs[i].SASPHYPage1, sizeof(MptConfigurationPageSASPHY1));
4226 }
4227
4228 /* The number of devices first. */
4229 SSMR3GetU32(pSSM, &pSasPages->cDevices);
4230
4231 PMptSASDevice pCurr = pSasPages->pSASDeviceHead;
4232
4233 for (unsigned i = 0; i < pSasPages->cDevices; i++)
4234 {
4235 SSMR3GetMem(pSSM, &pCurr->SASDevicePage0, sizeof(MptConfigurationPageSASDevice0));
4236 SSMR3GetMem(pSSM, &pCurr->SASDevicePage1, sizeof(MptConfigurationPageSASDevice1));
4237 SSMR3GetMem(pSSM, &pCurr->SASDevicePage2, sizeof(MptConfigurationPageSASDevice2));
4238
4239 pCurr = pCurr->pNext;
4240 }
4241
4242 Assert(!pCurr);
4243 }
4244 else
4245 AssertMsgFailed(("Invalid controller type %d\n", pLsiLogic->enmCtrlType));
4246 }
4247
4248 /* Now the data for the BIOS interface. */
4249 SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.regIdentify);
4250 SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.uTargetDevice);
4251 SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.uTxDir);
4252 SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.cbCDB);
4253 SSMR3GetMem (pSSM, pLsiLogic->VBoxSCSI.aCDB, sizeof(pLsiLogic->VBoxSCSI.aCDB));
4254 SSMR3GetU8 (pSSM, &pLsiLogic->VBoxSCSI.iCDB);
4255 SSMR3GetU32 (pSSM, &pLsiLogic->VBoxSCSI.cbBuf);
4256 SSMR3GetU32 (pSSM, &pLsiLogic->VBoxSCSI.iBuf);
4257 SSMR3GetBool(pSSM, (bool *)&pLsiLogic->VBoxSCSI.fBusy);
4258 SSMR3GetU8 (pSSM, (uint8_t *)&pLsiLogic->VBoxSCSI.enmState);
4259 if (pLsiLogic->VBoxSCSI.cbCDB)
4260 {
4261 pLsiLogic->VBoxSCSI.pBuf = (uint8_t *)RTMemAllocZ(pLsiLogic->VBoxSCSI.cbCDB);
4262 if (!pLsiLogic->VBoxSCSI.pBuf)
4263 {
4264 LogRel(("LsiLogic: Out of memory during restore.\n"));
4265 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
4266 N_("LsiLogic: Out of memory during restore\n"));
4267 }
4268 SSMR3GetMem(pSSM, pLsiLogic->VBoxSCSI.pBuf, pLsiLogic->VBoxSCSI.cbBuf);
4269 }
4270
4271 uint32_t u32;
4272 rc = SSMR3GetU32(pSSM, &u32);
4273 if (RT_FAILURE(rc))
4274 return rc;
4275 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4276
4277 return VINF_SUCCESS;
4278}
4279
4280/**
4281 * Gets the pointer to the status LED of a device - called from the SCSi driver.
4282 *
4283 * @returns VBox status code.
4284 * @param pInterface Pointer to the interface structure containing the called function pointer.
4285 * @param iLUN The unit which status LED we desire. Always 0 here as the driver
4286 * doesn't know about other LUN's.
4287 * @param ppLed Where to store the LED pointer.
4288 */
4289static DECLCALLBACK(int) lsilogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4290{
4291 PLSILOGICDEVICE pDevice = PDMILEDPORTS_2_PLSILOGICDEVICE(pInterface);
4292 if (iLUN == 0)
4293 {
4294 *ppLed = &pDevice->Led;
4295 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4296 return VINF_SUCCESS;
4297 }
4298 return VERR_PDM_LUN_NOT_FOUND;
4299}
4300
4301
4302/**
4303 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4304 */
4305static DECLCALLBACK(void *) lsilogicDeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4306{
4307 PLSILOGICDEVICE pDevice = PDMIBASE_2_PLSILOGICDEVICE(pInterface);
4308
4309 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
4310 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pDevice->ISCSIPort);
4311 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
4312 return NULL;
4313}
4314
4315/**
4316 * Gets the pointer to the status LED of a unit.
4317 *
4318 * @returns VBox status code.
4319 * @param pInterface Pointer to the interface structure containing the called function pointer.
4320 * @param iLUN The unit which status LED we desire.
4321 * @param ppLed Where to store the LED pointer.
4322 */
4323static DECLCALLBACK(int) lsilogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4324{
4325 PLSILOGICSCSI pLsiLogic = PDMILEDPORTS_2_PLSILOGICSCSI(pInterface);
4326 if (iLUN < pLsiLogic->cDeviceStates)
4327 {
4328 *ppLed = &pLsiLogic->paDeviceStates[iLUN].Led;
4329 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
4330 return VINF_SUCCESS;
4331 }
4332 return VERR_PDM_LUN_NOT_FOUND;
4333}
4334
4335/**
4336 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4337 */
4338static DECLCALLBACK(void *) lsilogicStatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4339{
4340 PLSILOGICSCSI pThis = PDMIBASE_2_PLSILOGICSCSI(pInterface);
4341 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
4342 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
4343 return NULL;
4344}
4345
4346/**
4347 * Detach notification.
4348 *
4349 * One harddisk at one port has been unplugged.
4350 * The VM is suspended at this point.
4351 *
4352 * @param pDevIns The device instance.
4353 * @param iLUN The logical unit which is being detached.
4354 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4355 */
4356static DECLCALLBACK(void) lsilogicDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4357{
4358 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4359 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN];
4360
4361 if (iLUN >= pThis->cDeviceStates)
4362 return;
4363
4364 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
4365 ("LsiLogic: Device does not support hotplugging\n"));
4366
4367 Log(("%s:\n", __FUNCTION__));
4368
4369 /*
4370 * Zero some important members.
4371 */
4372 pDevice->pDrvBase = NULL;
4373 pDevice->pDrvSCSIConnector = NULL;
4374}
4375
4376/**
4377 * Attach command.
4378 *
4379 * This is called when we change block driver.
4380 *
4381 * @returns VBox status code.
4382 * @param pDevIns The device instance.
4383 * @param iLUN The logical unit which is being detached.
4384 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4385 */
4386static DECLCALLBACK(int) lsilogicAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4387{
4388 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4389 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[iLUN];
4390 int rc;
4391
4392 if (iLUN >= pThis->cDeviceStates)
4393 return VERR_PDM_LUN_NOT_FOUND;
4394
4395 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
4396 ("LsiLogic: Device does not support hotplugging\n"),
4397 VERR_INVALID_PARAMETER);
4398
4399 /* the usual paranoia */
4400 AssertRelease(!pDevice->pDrvBase);
4401 AssertRelease(!pDevice->pDrvSCSIConnector);
4402 Assert(pDevice->iLUN == iLUN);
4403
4404 /*
4405 * Try attach the block device and get the interfaces,
4406 * required as well as optional.
4407 */
4408 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
4409 if (RT_SUCCESS(rc))
4410 {
4411 /* Get SCSI connector interface. */
4412 pDevice->pDrvSCSIConnector = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMISCSICONNECTOR);
4413 AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
4414 }
4415 else
4416 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
4417
4418 if (RT_FAILURE(rc))
4419 {
4420 pDevice->pDrvBase = NULL;
4421 pDevice->pDrvSCSIConnector = NULL;
4422 }
4423 return rc;
4424}
4425
4426/**
4427 * @copydoc FNPDMDEVRESET
4428 */
4429static DECLCALLBACK(void) lsilogicReset(PPDMDEVINS pDevIns)
4430{
4431 PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4432 int rc;
4433
4434 rc = lsilogicHardReset(pLsiLogic);
4435 AssertRC(rc);
4436
4437 vboxscsiInitialize(&pLsiLogic->VBoxSCSI);
4438}
4439
4440/**
4441 * @copydoc FNPDMDEVRELOCATE
4442 */
4443static DECLCALLBACK(void) lsilogicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4444{
4445 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4446
4447 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
4448 pThis->pNotificationQueueRC = PDMQueueRCPtr(pThis->pNotificationQueueR3);
4449
4450 /* Relocate queues. */
4451 pThis->pReplyFreeQueueBaseRC += offDelta;
4452 pThis->pReplyPostQueueBaseRC += offDelta;
4453 pThis->pRequestQueueBaseRC += offDelta;
4454}
4455
4456/**
4457 * @copydoc FNPDMDEVDESTRUCT
4458 */
4459static DECLCALLBACK(int) lsilogicDestruct(PPDMDEVINS pDevIns)
4460{
4461 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4462 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
4463
4464 PDMR3CritSectDelete(&pThis->ReplyFreeQueueCritSect);
4465 PDMR3CritSectDelete(&pThis->ReplyPostQueueCritSect);
4466
4467 if (pThis->paDeviceStates)
4468 RTMemFree(pThis->paDeviceStates);
4469
4470 /* Destroy task cache. */
4471 int rc = VINF_SUCCESS;
4472 if (pThis->hTaskCache != NIL_RTMEMCACHE)
4473 rc = RTMemCacheDestroy(pThis->hTaskCache);
4474
4475 lsilogicConfigurationPagesFree(pThis);
4476
4477 return rc;
4478}
4479
4480/**
4481 * @copydoc FNPDMDEVCONSTRUCT
4482 */
4483static DECLCALLBACK(int) lsilogicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4484{
4485 PLSILOGICSCSI pThis = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
4486 int rc = VINF_SUCCESS;
4487 char *pszCtrlType = NULL;
4488 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4489
4490 /*
4491 * Validate and read configuration.
4492 */
4493 rc = CFGMR3AreValuesValid(pCfg, "GCEnabled\0"
4494 "R0Enabled\0"
4495 "ReplyQueueDepth\0"
4496 "RequestQueueDepth\0"
4497 "ControllerType\0"
4498 "NumPorts\0");
4499 if (RT_FAILURE(rc))
4500 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4501 N_("LsiLogic configuration error: unknown option specified"));
4502 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
4503 if (RT_FAILURE(rc))
4504 return PDMDEV_SET_ERROR(pDevIns, rc,
4505 N_("LsiLogic configuration error: failed to read GCEnabled as boolean"));
4506 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, pThis->fGCEnabled));
4507
4508 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
4509 if (RT_FAILURE(rc))
4510 return PDMDEV_SET_ERROR(pDevIns, rc,
4511 N_("LsiLogic configuration error: failed to read R0Enabled as boolean"));
4512 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, pThis->fR0Enabled));
4513
4514 rc = CFGMR3QueryU32Def(pCfg, "ReplyQueueDepth",
4515 &pThis->cReplyQueueEntries,
4516 LSILOGICSCSI_REPLY_QUEUE_DEPTH_DEFAULT);
4517 if (RT_FAILURE(rc))
4518 return PDMDEV_SET_ERROR(pDevIns, rc,
4519 N_("LsiLogic configuration error: failed to read ReplyQueue as integer"));
4520 Log(("%s: ReplyQueueDepth=%u\n", __FUNCTION__, pThis->cReplyQueueEntries));
4521
4522 rc = CFGMR3QueryU32Def(pCfg, "RequestQueueDepth",
4523 &pThis->cRequestQueueEntries,
4524 LSILOGICSCSI_REQUEST_QUEUE_DEPTH_DEFAULT);
4525 if (RT_FAILURE(rc))
4526 return PDMDEV_SET_ERROR(pDevIns, rc,
4527 N_("LsiLogic configuration error: failed to read RequestQueue as integer"));
4528 Log(("%s: RequestQueueDepth=%u\n", __FUNCTION__, pThis->cRequestQueueEntries));
4529
4530 rc = CFGMR3QueryStringAllocDef(pCfg, "ControllerType",
4531 &pszCtrlType, LSILOGICSCSI_PCI_SPI_CTRLNAME);
4532 if (RT_FAILURE(rc))
4533 return PDMDEV_SET_ERROR(pDevIns, rc,
4534 N_("LsiLogic configuration error: failed to read ControllerType as string"));
4535 Log(("%s: ControllerType=%s\n", __FUNCTION__, pszCtrlType));
4536
4537 rc = lsilogicGetCtrlTypeFromString(pThis, pszCtrlType);
4538 MMR3HeapFree(pszCtrlType);
4539
4540 if (RT_FAILURE(rc))
4541 return PDMDEV_SET_ERROR(pDevIns, rc,
4542 N_("LsiLogic configuration error: failed to determine controller type from string"));
4543
4544 rc = CFGMR3QueryU8(pCfg, "NumPorts",
4545 &pThis->cPorts);
4546 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4547 {
4548 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4549 pThis->cPorts = LSILOGICSCSI_PCI_SPI_PORTS_MAX;
4550 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4551 pThis->cPorts = LSILOGICSCSI_PCI_SAS_PORTS_DEFAULT;
4552 else
4553 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
4554 }
4555 else if (RT_FAILURE(rc))
4556 return PDMDEV_SET_ERROR(pDevIns, rc,
4557 N_("LsiLogic configuration error: failed to read NumPorts as integer"));
4558
4559 /* Init static parts. */
4560 PCIDevSetVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_VENDOR_ID); /* LsiLogic */
4561
4562 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4563 {
4564 PCIDevSetDeviceId (&pThis->PciDev, LSILOGICSCSI_PCI_SPI_DEVICE_ID); /* LSI53C1030 */
4565 PCIDevSetSubSystemVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_VENDOR_ID);
4566 PCIDevSetSubSystemId (&pThis->PciDev, LSILOGICSCSI_PCI_SPI_SUBSYSTEM_ID);
4567 }
4568 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4569 {
4570 PCIDevSetDeviceId (&pThis->PciDev, LSILOGICSCSI_PCI_SAS_DEVICE_ID); /* SAS1068 */
4571 PCIDevSetSubSystemVendorId(&pThis->PciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_VENDOR_ID);
4572 PCIDevSetSubSystemId (&pThis->PciDev, LSILOGICSCSI_PCI_SAS_SUBSYSTEM_ID);
4573 }
4574 else
4575 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
4576
4577 PCIDevSetClassProg (&pThis->PciDev, 0x00); /* SCSI */
4578 PCIDevSetClassSub (&pThis->PciDev, 0x00); /* SCSI */
4579 PCIDevSetClassBase (&pThis->PciDev, 0x01); /* Mass storage */
4580 PCIDevSetInterruptPin(&pThis->PciDev, 0x01); /* Interrupt pin A */
4581
4582 pThis->pDevInsR3 = pDevIns;
4583 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
4584 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
4585 pThis->IBase.pfnQueryInterface = lsilogicStatusQueryInterface;
4586 pThis->ILeds.pfnQueryStatusLed = lsilogicStatusQueryStatusLed;
4587
4588 /*
4589 * Register the PCI device, it's I/O regions.
4590 */
4591 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->PciDev);
4592 if (RT_FAILURE(rc))
4593 return rc;
4594
4595 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicMap);
4596 if (RT_FAILURE(rc))
4597 return rc;
4598
4599 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
4600 if (RT_FAILURE(rc))
4601 return rc;
4602
4603 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, LSILOGIC_PCI_SPACE_MEM_SIZE, PCI_ADDRESS_SPACE_MEM, lsilogicMap);
4604 if (RT_FAILURE(rc))
4605 return rc;
4606
4607 /* Intialize task queue. */
4608 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 2, 0,
4609 lsilogicNotifyQueueConsumer, true,
4610 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4611 ? "LsiLogic-Task"
4612 : "LsiLogicSAS-Task",
4613 &pThis->pNotificationQueueR3);
4614 if (RT_FAILURE(rc))
4615 return rc;
4616 pThis->pNotificationQueueR0 = PDMQueueR0Ptr(pThis->pNotificationQueueR3);
4617 pThis->pNotificationQueueRC = PDMQueueRCPtr(pThis->pNotificationQueueR3);
4618
4619 /*
4620 * We need one entry free in the queue.
4621 */
4622 pThis->cReplyQueueEntries++;
4623 pThis->cRequestQueueEntries++;
4624
4625 /*
4626 * Allocate memory for the queues.
4627 */
4628 rc = lsilogicQueuesAlloc(pThis);
4629 if (RT_FAILURE(rc))
4630 return rc;
4631
4632 /*
4633 * Create critical sections protecting the reply post and free queues.
4634 */
4635 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyFreeQueueCritSect, RT_SRC_POS,
4636 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4637 ? "LsiLogicRFQ"
4638 : "LsiLogicSasRFQ");
4639 if (RT_FAILURE(rc))
4640 return PDMDEV_SET_ERROR(pDevIns, rc,
4641 N_("LsiLogic: cannot create critical section for reply free queue"));
4642
4643 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->ReplyPostQueueCritSect, RT_SRC_POS,
4644 pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI
4645 ? "LsiLogicRPQ"
4646 : "LsiLogicSasRPQ");
4647 if (RT_FAILURE(rc))
4648 return PDMDEV_SET_ERROR(pDevIns, rc,
4649 N_("LsiLogic: cannot create critical section for reply post queue"));
4650
4651 /*
4652 * Allocate task cache.
4653 */
4654 rc = RTMemCacheCreate(&pThis->hTaskCache, sizeof(LSILOGICTASKSTATE), 0, UINT32_MAX,
4655 lsilogicTaskStateCtor, lsilogicTaskStateDtor, NULL, 0);
4656 if (RT_FAILURE(rc))
4657 return PDMDEV_SET_ERROR(pDevIns, rc,
4658 N_("Cannot create task cache"));
4659
4660 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4661 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SPI_DEVICES_PER_BUS_MAX;
4662 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4663 pThis->cDeviceStates = pThis->cPorts * LSILOGICSCSI_PCI_SAS_DEVICES_PER_PORT_MAX;
4664 else
4665 AssertMsgFailed(("Invalid controller type: %d\n", pThis->enmCtrlType));
4666
4667 /*
4668 * Allocate device states.
4669 */
4670 pThis->paDeviceStates = (PLSILOGICDEVICE)RTMemAllocZ(sizeof(LSILOGICDEVICE) * pThis->cDeviceStates);
4671 if (!pThis->paDeviceStates)
4672 return PDMDEV_SET_ERROR(pDevIns, rc,
4673 N_("Failed to allocate memory for device states"));
4674
4675 for (unsigned i = 0; i < pThis->cDeviceStates; i++)
4676 {
4677 char szName[24];
4678 PLSILOGICDEVICE pDevice = &pThis->paDeviceStates[i];
4679
4680 /* Initialize static parts of the device. */
4681 pDevice->iLUN = i;
4682 pDevice->pLsiLogicR3 = pThis;
4683 pDevice->Led.u32Magic = PDMLED_MAGIC;
4684 pDevice->IBase.pfnQueryInterface = lsilogicDeviceQueryInterface;
4685 pDevice->ISCSIPort.pfnSCSIRequestCompleted = lsilogicDeviceSCSIRequestCompleted;
4686 pDevice->ILed.pfnQueryStatusLed = lsilogicDeviceQueryStatusLed;
4687
4688 RTStrPrintf(szName, sizeof(szName), "Device%d", i);
4689
4690 /* Attach SCSI driver. */
4691 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, szName);
4692 if (RT_SUCCESS(rc))
4693 {
4694 /* Get SCSI connector interface. */
4695 pDevice->pDrvSCSIConnector = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMISCSICONNECTOR);
4696 AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
4697 }
4698 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4699 {
4700 pDevice->pDrvBase = NULL;
4701 rc = VINF_SUCCESS;
4702 Log(("LsiLogic: no driver attached to device %s\n", szName));
4703 }
4704 else
4705 {
4706 AssertLogRelMsgFailed(("LsiLogic: Failed to attach %s\n", szName));
4707 return rc;
4708 }
4709 }
4710
4711 /*
4712 * Attach status driver (optional).
4713 */
4714 PPDMIBASE pBase;
4715 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
4716 if (RT_SUCCESS(rc))
4717 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
4718 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4719 {
4720 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
4721 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot attach to status driver"));
4722 }
4723
4724 /* Initialize the SCSI emulation for the BIOS. */
4725 rc = vboxscsiInitialize(&pThis->VBoxSCSI);
4726 AssertRC(rc);
4727
4728 /* Register I/O port space in ISA region for BIOS access. */
4729 if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SPI)
4730 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_ISA_IO_PORT, 3, NULL,
4731 lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead,
4732 lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr,
4733 "LsiLogic BIOS");
4734 else if (pThis->enmCtrlType == LSILOGICCTRLTYPE_SCSI_SAS)
4735 rc = PDMDevHlpIOPortRegister(pDevIns, LSILOGIC_SAS_ISA_IO_PORT, 3, NULL,
4736 lsilogicIsaIOPortWrite, lsilogicIsaIOPortRead,
4737 lsilogicIsaIOPortWriteStr, lsilogicIsaIOPortReadStr,
4738 "LsiLogic SAS BIOS");
4739 else
4740 AssertMsgFailed(("Invalid controller type %d\n", pThis->enmCtrlType));
4741
4742 if (RT_FAILURE(rc))
4743 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register legacy I/O handlers"));
4744
4745 /* Register save state handlers. */
4746 rc = PDMDevHlpSSMRegister3(pDevIns, LSILOGIC_SAVED_STATE_VERSION, sizeof(*pThis),
4747 lsilogicLiveExec, lsilogicSaveExec, lsilogicLoadExec);
4748 if (RT_FAILURE(rc))
4749 return PDMDEV_SET_ERROR(pDevIns, rc, N_("LsiLogic cannot register save state handlers"));
4750
4751 pThis->enmWhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
4752
4753 /* Perform hard reset. */
4754 rc = lsilogicHardReset(pThis);
4755 AssertRC(rc);
4756
4757 return rc;
4758}
4759
4760/**
4761 * The device registration structure - SPI SCSI controller.
4762 */
4763const PDMDEVREG g_DeviceLsiLogicSCSI =
4764{
4765 /* u32Version */
4766 PDM_DEVREG_VERSION,
4767 /* szName */
4768 "lsilogicscsi",
4769 /* szRCMod */
4770 "VBoxDDGC.gc",
4771 /* szR0Mod */
4772 "VBoxDDR0.r0",
4773 /* pszDescription */
4774 "LSI Logic 53c1030 SCSI controller.\n",
4775 /* fFlags */
4776 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
4777 /* fClass */
4778 PDM_DEVREG_CLASS_STORAGE,
4779 /* cMaxInstances */
4780 ~0,
4781 /* cbInstance */
4782 sizeof(LSILOGICSCSI),
4783 /* pfnConstruct */
4784 lsilogicConstruct,
4785 /* pfnDestruct */
4786 lsilogicDestruct,
4787 /* pfnRelocate */
4788 lsilogicRelocate,
4789 /* pfnIOCtl */
4790 NULL,
4791 /* pfnPowerOn */
4792 NULL,
4793 /* pfnReset */
4794 lsilogicReset,
4795 /* pfnSuspend */
4796 NULL,
4797 /* pfnResume */
4798 NULL,
4799 /* pfnAttach */
4800 lsilogicAttach,
4801 /* pfnDetach */
4802 lsilogicDetach,
4803 /* pfnQueryInterface. */
4804 NULL,
4805 /* pfnInitComplete */
4806 NULL,
4807 /* pfnPowerOff */
4808 NULL,
4809 /* pfnSoftReset */
4810 NULL,
4811 /* u32VersionEnd */
4812 PDM_DEVREG_VERSION
4813};
4814
4815/**
4816 * The device registration structure - SAS controller.
4817 */
4818const PDMDEVREG g_DeviceLsiLogicSAS =
4819{
4820 /* u32Version */
4821 PDM_DEVREG_VERSION,
4822 /* szName */
4823 "lsilogicsas",
4824 /* szRCMod */
4825 "VBoxDDGC.gc",
4826 /* szR0Mod */
4827 "VBoxDDR0.r0",
4828 /* pszDescription */
4829 "LSI Logic SAS1068 controller.\n",
4830 /* fFlags */
4831 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
4832 /* fClass */
4833 PDM_DEVREG_CLASS_STORAGE,
4834 /* cMaxInstances */
4835 ~0,
4836 /* cbInstance */
4837 sizeof(LSILOGICSCSI),
4838 /* pfnConstruct */
4839 lsilogicConstruct,
4840 /* pfnDestruct */
4841 lsilogicDestruct,
4842 /* pfnRelocate */
4843 lsilogicRelocate,
4844 /* pfnIOCtl */
4845 NULL,
4846 /* pfnPowerOn */
4847 NULL,
4848 /* pfnReset */
4849 lsilogicReset,
4850 /* pfnSuspend */
4851 NULL,
4852 /* pfnResume */
4853 NULL,
4854 /* pfnAttach */
4855 lsilogicAttach,
4856 /* pfnDetach */
4857 lsilogicDetach,
4858 /* pfnQueryInterface. */
4859 NULL,
4860 /* pfnInitComplete */
4861 NULL,
4862 /* pfnPowerOff */
4863 NULL,
4864 /* pfnSoftReset */
4865 NULL,
4866 /* u32VersionEnd */
4867 PDM_DEVREG_VERSION
4868};
4869
4870#endif /* IN_RING3 */
4871#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4872
Note: See TracBrowser for help on using the repository browser.

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