VirtualBox

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

最後變更 在這個檔案從23913是 23814,由 vboxsync 提交於 15 年 前

DevLsiLogicSCSI,tstDeviceStructSize: Critical section realigning.

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

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