VirtualBox

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

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

LsiLogic: Don't assert when not reading 4 byte from a register. A SCSI Linux driver scans the range for a device before the controller is nitialized

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

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