VirtualBox

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

Last change on this file since 28855 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use