VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DevBusLogic.cpp@ 30597

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

alignment check on BUSLOGIC::CritSectIntr.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 111.4 KB
Line 
1/* $Id: DevBusLogic.cpp 30597 2010-07-05 09:09:01Z vboxsync $ */
2/** @file
3 * VBox storage devices: BusLogic SCSI host adapter BT-958.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Implemented looking at the driver source in the linux kernel (drivers/scsi/BusLogic.[ch]). */
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23//#define DEBUG
24#define LOG_GROUP LOG_GROUP_DEV_BUSLOGIC
25#include <VBox/pdmdev.h>
26#include <VBox/pdmifs.h>
27#include <VBox/pdmcritsect.h>
28#include <VBox/scsi.h>
29#include <iprt/asm.h>
30#include <iprt/assert.h>
31#include <iprt/string.h>
32#include <iprt/log.h>
33#ifdef IN_RING3
34# include <iprt/alloc.h>
35# include <iprt/memcache.h>
36# include <iprt/param.h>
37# include <iprt/uuid.h>
38#endif
39
40#include "VBoxSCSI.h"
41#include "../Builtins.h"
42
43/* Maximum number of attached devices the adapter can handle. */
44#define BUSLOGIC_MAX_DEVICES 16
45
46/* Maximum number of scatter gather elements this device can handle. */
47#define BUSLOGIC_MAX_SCATTER_GATHER_LIST_SIZE 128
48
49/* Size of the command buffer. */
50#define BUSLOGIC_COMMAND_SIZE_MAX 5
51
52/* Size of the reply buffer. */
53#define BUSLOGIC_REPLY_SIZE_MAX 64
54
55/* I/O port registered in the ISA compatible range to let the BIOS access
56 * the controller.
57 */
58#define BUSLOGIC_ISA_IO_PORT 0x330
59
60/** State saved version. */
61#define BUSLOGIC_SAVED_STATE_MINOR_VERSION 1
62
63/**
64 * State of a device attached to the buslogic host adapter.
65 *
66 * @implements PDMIBASE
67 * @implements PDMISCSIPORT
68 * @implements PDMILEDPORTS
69 */
70typedef struct BUSLOGICDEVICE
71{
72 /** Pointer to the owning buslogic device instance. - R3 pointer */
73 R3PTRTYPE(struct BUSLOGIC *) pBusLogicR3;
74 /** Pointer to the owning buslogic device instance. - R0 pointer */
75 R0PTRTYPE(struct BUSLOGIC *) pBusLogicR0;
76 /** Pointer to the owning buslogic device instance. - RC pointer */
77 RCPTRTYPE(struct BUSLOGIC *) pBusLogicRC;
78
79 /** Flag whether device is present. */
80 bool fPresent;
81 /** LUN of the device. */
82 RTUINT iLUN;
83
84#if HC_ARCH_BITS == 64
85 uint32_t Alignment0;
86#endif
87
88 /** Our base interace. */
89 PDMIBASE IBase;
90 /** SCSI port interface. */
91 PDMISCSIPORT ISCSIPort;
92 /** Led interface. */
93 PDMILEDPORTS ILed;
94 /** Pointer to the attached driver's base interface. */
95 R3PTRTYPE(PPDMIBASE) pDrvBase;
96 /** Pointer to the underlying SCSI connector interface. */
97 R3PTRTYPE(PPDMISCSICONNECTOR) pDrvSCSIConnector;
98 /** The status LED state for this device. */
99 PDMLED Led;
100
101#if HC_ARCH_BITS == 64
102 uint32_t Alignment1;
103#endif
104
105 /** Number of outstanding tasks on the port. */
106 volatile uint32_t cOutstandingRequests;
107
108} BUSLOGICDEVICE, *PBUSLOGICDEVICE;
109
110/*
111 * Commands the BusLogic adapter supports.
112 */
113enum BUSLOGICCOMMAND
114{
115 BUSLOGICCOMMAND_TEST_COMMAND_COMPLETE_INTERRUPT = 0x00,
116 BUSLOGICCOMMAND_INITIALIZE_MAILBOX = 0x01,
117 BUSLOGICCOMMAND_EXECUTE_MAILBOX_COMMAND = 0x02,
118 BUSLOGICCOMMAND_EXECUTE_BIOS_COMMAND = 0x03,
119 BUSLOGICCOMMAND_INQUIRE_BOARD_ID = 0x04,
120 BUSLOGICCOMMAND_ENABLE_OUTGOING_MAILBOX_AVAILABLE_INTERRUPT = 0x05,
121 BUSLOGICCOMMAND_SET_SCSI_SELECTION_TIMEOUT = 0x06,
122 BUSLOGICCOMMAND_SET_PREEMPT_TIME_ON_BUS = 0x07,
123 BUSLOGICCOMMAND_SET_TIME_OFF_BUS = 0x08,
124 BUSLOGICCOMMAND_SET_BUS_TRANSFER_RATE = 0x09,
125 BUSLOGICCOMMAND_INQUIRE_INSTALLED_DEVICES_ID_0_TO_7 = 0x0a,
126 BUSLOGICCOMMAND_INQUIRE_CONFIGURATION = 0x0b,
127 BUSLOGICCOMMAND_ENABLE_TARGET_MODE = 0x0c,
128 BUSLOGICCOMMAND_INQUIRE_SETUP_INFORMATION = 0x0d,
129 BUSLOGICCOMMAND_WRITE_ADAPTER_LOCAL_RAM = 0x1a,
130 BUSLOGICCOMMAND_READ_ADAPTER_LOCAL_RAM = 0x1b,
131 BUSLOGICCOMMAND_WRITE_BUSMASTER_CHIP_FIFO = 0x1c,
132 BUSLOGICCOMMAND_READ_BUSMASTER_CHIP_FIFO = 0x1d,
133 BUSLOGICCOMMAND_ECHO_COMMAND_DATA = 0x1f,
134 BUSLOGICCOMMAND_HOST_ADAPTER_DIAGNOSTIC = 0x20,
135 BUSLOGICCOMMAND_SET_ADAPTER_OPTIONS = 0x21,
136 BUSLOGICCOMMAND_INQUIRE_INSTALLED_DEVICES_ID_8_TO_15 = 0x23,
137 BUSLOGICCOMMAND_INQUIRE_TARGET_DEVICES = 0x24,
138 BUSLOGICCOMMAND_DISABLE_HOST_ADAPTER_INTERRUPT = 0x25,
139 BUSLOGICCOMMAND_INITIALIZE_EXTENDED_MAILBOX = 0x81,
140 BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND = 0x83,
141 BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_3RD_LETTER = 0x84,
142 BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_LETTER = 0x85,
143 BUSLOGICCOMMAND_INQUIRE_PCI_HOST_ADAPTER_INFORMATION = 0x86,
144 BUSLOGICCOMMAND_INQUIRE_HOST_ADAPTER_MODEL_NUMBER = 0x8b,
145 BUSLOGICCOMMAND_INQUIRE_SYNCHRONOUS_PERIOD = 0x8c,
146 BUSLOGICCOMMAND_INQUIRE_EXTENDED_SETUP_INFORMATION = 0x8d,
147 BUSLOGICCOMMAND_ENABLE_STRICT_ROUND_ROBIN_MODE = 0x8f,
148 BUSLOGICCOMMAND_STORE_HOST_ADAPTER_LOCAL_RAM = 0x90,
149 BUSLOGICCOMMAND_FETCH_HOST_ADAPTER_LOCAL_RAM = 0x91,
150 BUSLOGICCOMMAND_STORE_LOCAL_DATA_IN_EEPROM = 0x92,
151 BUSLOGICCOMMAND_UPLOAD_AUTO_SCSI_CODE = 0x94,
152 BUSLOGICCOMMAND_MODIFY_IO_ADDRESS = 0x95,
153 BUSLOGICCOMMAND_SET_CCB_FORMAT = 0x96,
154 BUSLOGICCOMMAND_WRITE_INQUIRY_BUFFER = 0x9a,
155 BUSLOGICCOMMAND_READ_INQUIRY_BUFFER = 0x9b,
156 BUSLOGICCOMMAND_FLASH_ROM_UPLOAD_DOWNLOAD = 0xa7,
157 BUSLOGICCOMMAND_READ_SCAM_DATA = 0xa8,
158 BUSLOGICCOMMAND_WRITE_SCAM_DATA = 0xa9
159} BUSLOGICCOMMAND;
160
161#pragma pack(1)
162/**
163 * Auto SCSI structure which is located
164 * in host adapter RAM and contains several
165 * configuration parameters.
166 */
167typedef struct AutoSCSIRam
168{
169 uint8_t aInternalSignature[2];
170 uint8_t cbInformation;
171 uint8_t aHostAdaptertype[6];
172 uint8_t uReserved1;
173 bool fFloppyEnabled: 1;
174 bool fFloppySecondary: 1;
175 bool fLevelSensitiveInterrupt: 1;
176 unsigned char uReserved2: 2;
177 unsigned char uSystemRAMAreForBIOS: 3;
178 unsigned char uDMAChannel: 7;
179 bool fDMAAutoConfiguration: 1;
180 unsigned char uIrqChannel: 7;
181 bool fIrqAutoConfiguration: 1;
182 uint8_t uDMATransferRate;
183 uint8_t uSCSIId;
184 bool fLowByteTerminated: 1;
185 bool fParityCheckingEnabled: 1;
186 bool fHighByteTerminated: 1;
187 bool fNoisyCablingEnvironment: 1;
188 bool fFastSynchronousNeogtiation: 1;
189 bool fBusResetEnabled: 1;
190 bool fReserved3: 1;
191 bool fActiveNegotiationEnabled: 1;
192 uint8_t uBusOnDelay;
193 uint8_t uBusOffDelay;
194 bool fHostAdapterBIOSEnabled: 1;
195 bool fBIOSRedirectionOfInt19: 1;
196 bool fExtendedTranslation: 1;
197 bool fMapRemovableAsFixed: 1;
198 bool fReserved4: 1;
199 bool fBIOSSupportsMoreThan2Drives: 1;
200 bool fBIOSInterruptMode: 1;
201 bool fFlopticalSupport: 1;
202 uint16_t u16DeviceEnabledMask;
203 uint16_t u16WidePermittedMask;
204 uint16_t u16FastPermittedMask;
205 uint16_t u16SynchronousPermittedMask;
206 uint16_t u16DisconnectPermittedMask;
207 uint16_t u16SendStartUnitCommandMask;
208 uint16_t u16IgnoreInBIOSScanMask;
209 unsigned char uPCIInterruptPin: 2;
210 unsigned char uHostAdapterIoPortAddress: 2;
211 bool fStrictRoundRobinMode: 1;
212 bool fVesaBusSpeedGreaterThan33MHz: 1;
213 bool fVesaBurstWrite: 1;
214 bool fVesaBurstRead: 1;
215 uint16_t u16UltraPermittedMask;
216 uint32_t uReserved5;
217 uint8_t uReserved6;
218 uint8_t uAutoSCSIMaximumLUN;
219 bool fReserved7: 1;
220 bool fSCAMDominant: 1;
221 bool fSCAMenabled: 1;
222 bool fSCAMLevel2: 1;
223 unsigned char uReserved8: 4;
224 bool fInt13Extension: 1;
225 bool fReserved9: 1;
226 bool fCDROMBoot: 1;
227 unsigned char uReserved10: 5;
228 unsigned char uBootTargetId: 4;
229 unsigned char uBootChannel: 4;
230 bool fForceBusDeviceScanningOrder: 1;
231 unsigned char uReserved11: 7;
232 uint16_t u16NonTaggedToAlternateLunPermittedMask;
233 uint16_t u16RenegotiateSyncAfterCheckConditionMask;
234 uint8_t aReserved12[10];
235 uint8_t aManufacturingDiagnostic[2];
236 uint16_t u16Checksum;
237} AutoSCSIRam, *PAutoSCSIRam;
238AssertCompileSize(AutoSCSIRam, 64);
239#pragma pack()
240
241#pragma pack(1)
242/**
243 * The local Ram.
244 */
245typedef union HostAdapterLocalRam
246{
247 /* Byte view. */
248 uint8_t u8View[256];
249 /* Structured view. */
250 struct
251 {
252 /** Offset 0 - 63 is for BIOS. */
253 uint8_t u8Bios[64];
254 /** Auto SCSI structure. */
255 AutoSCSIRam autoSCSIData;
256 } structured;
257} HostAdapterLocalRam, *PHostAdapterLocalRam;
258AssertCompileSize(HostAdapterLocalRam, 256);
259#pragma pack()
260
261/**
262 * Main BusLogic device state.
263 *
264 * @extends PCIDEVICE
265 * @implements PDMILEDPORTS
266 */
267typedef struct BUSLOGIC
268{
269 /** The PCI device structure. */
270 PCIDEVICE dev;
271 /** Pointer to the device instance - HC ptr */
272 PPDMDEVINSR3 pDevInsR3;
273 /** Pointer to the device instance - R0 ptr */
274 PPDMDEVINSR0 pDevInsR0;
275 /** Pointer to the device instance - RC ptr. */
276 PPDMDEVINSRC pDevInsRC;
277
278 /** Whether R0 is enabled. */
279 bool fR0Enabled;
280 /** Whether RC is enabled. */
281 bool fGCEnabled;
282
283 /** Base address of the I/O ports. */
284 RTIOPORT IOPortBase;
285 /** Base address of the memory mapping. */
286 RTGCPHYS MMIOBase;
287 /** Status register - Readonly. */
288 volatile uint8_t regStatus;
289 /** Interrupt register - Readonly. */
290 volatile uint8_t regInterrupt;
291 /** Geometry register - Readonly. */
292 volatile uint8_t regGeometry;
293
294 /** Local RAM for the fetch hostadapter local RAM request.
295 * I don't know how big the buffer really is but the maximum
296 * seems to be 256 bytes because the offset and count field in the command request
297 * are only one byte big.
298 */
299 HostAdapterLocalRam LocalRam;
300
301 /** Command code the guest issued. */
302 uint8_t uOperationCode;
303 /** Buffer for the command parameters the adapter is currently receiving from the guest.
304 * Size of the largest command which is possible.
305 */
306 uint8_t aCommandBuffer[BUSLOGIC_COMMAND_SIZE_MAX]; /* Size of the biggest request. */
307 /** Current position in the command buffer. */
308 uint8_t iParameter;
309 /** Parameters left until the command is complete. */
310 uint8_t cbCommandParametersLeft;
311
312 /** Whether we are using the RAM or reply buffer. */
313 bool fUseLocalRam;
314 /** Buffer to store reply data from the controller to the guest. */
315 uint8_t aReplyBuffer[BUSLOGIC_REPLY_SIZE_MAX]; /* Size of the biggest reply. */
316 /** Position in the buffer we are reading next. */
317 uint8_t iReply;
318 /** Bytes left until the reply buffer is empty. */
319 uint8_t cbReplyParametersLeft;
320
321 /** Flag whether IRQs are enabled. */
322 bool fIRQEnabled;
323 /** Flag whether the ISA I/O port range is disabled
324 * to prevent the BIOs to access the device. */
325 bool fISAEnabled;
326
327 /** Number of mailboxes the guest set up. */
328 uint32_t cMailbox;
329
330#if HC_ARCH_BITS == 64
331 uint32_t Alignment0;
332#endif
333
334 /** Physical base address of the outgoing mailboxes. */
335 RTGCPHYS GCPhysAddrMailboxOutgoingBase;
336 /** Current outgoing mailbox position. */
337 uint32_t uMailboxOutgoingPositionCurrent;
338 /** Number of mailboxes ready. */
339 volatile uint32_t cMailboxesReady;
340 /** Whether a notification to R3 was send. */
341 volatile bool fNotificationSend;
342
343#if HC_ARCH_BITS == 64
344 uint32_t Alignment1;
345#endif
346
347 /** Physical base address of the incoming mailboxes. */
348 RTGCPHYS GCPhysAddrMailboxIncomingBase;
349 /** Current incoming mailbox position. */
350 uint32_t uMailboxIncomingPositionCurrent;
351
352 /** Whether strict round robin is enabled. */
353 bool fStrictRoundRobinMode;
354 /** Whether the extended LUN CCB format is enabled for 32 possible logical units. */
355 bool fExtendedLunCCBFormat;
356
357 /** Queue to send tasks to R3. - HC ptr */
358 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;
359 /** Queue to send tasks to R3. - HC ptr */
360 R0PTRTYPE(PPDMQUEUE) pNotifierQueueR0;
361 /** Queue to send tasks to R3. - RC ptr */
362 RCPTRTYPE(PPDMQUEUE) pNotifierQueueRC;
363
364 uint32_t Alignment2;
365
366 /** Critical section protecting access to the interrupt status register. */
367 PDMCRITSECT CritSectIntr;
368
369 /** Cache for task states. */
370 R3PTRTYPE(RTMEMCACHE) hTaskCache;
371
372 /** Device state for BIOS access. */
373 VBOXSCSI VBoxSCSI;
374
375 /** BusLogic device states. */
376 BUSLOGICDEVICE aDeviceStates[BUSLOGIC_MAX_DEVICES];
377
378 /** The base interface.
379 * @todo use PDMDEVINS::IBase */
380 PDMIBASE IBase;
381 /** Status Port - Leds interface. */
382 PDMILEDPORTS ILeds;
383 /** Partner of ILeds. */
384 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
385
386#if HC_ARCH_BITS == 64
387 uint32_t Alignment3;
388#endif
389
390 /** Indicates that PDMDevHlpAsyncNotificationCompleted should be called when
391 * a port is entering the idle state. */
392 bool volatile fSignalIdle;
393
394} BUSLOGIC, *PBUSLOGIC;
395
396/** Register offsets in the I/O port space. */
397#define BUSLOGIC_REGISTER_CONTROL 0 /* Writeonly */
398/** Fields for the control register. */
399# define BUSLOGIC_REGISTER_CONTROL_SCSI_BUSRESET RT_BIT(4)
400# define BUSLOGIC_REGISTER_CONTROL_INTERRUPT_RESET RT_BIT(5)
401# define BUSLOGIC_REGISTER_CONTROL_SOFT_RESET RT_BIT(6)
402# define BUSLOGIC_REGISTER_CONTROL_HARD_RESET RT_BIT(7)
403
404#define BUSLOGIC_REGISTER_STATUS 0 /* Readonly */
405/** Fields for the status register. */
406# define BUSLOGIC_REGISTER_STATUS_COMMAND_INVALID RT_BIT(0)
407# define BUSLOGIC_REGISTER_STATUS_DATA_IN_REGISTER_READY RT_BIT(2)
408# define BUSLOGIC_REGISTER_STATUS_COMMAND_PARAMETER_REGISTER_BUSY RT_BIT(3)
409# define BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY RT_BIT(4)
410# define BUSLOGIC_REGISTER_STATUS_INITIALIZATION_REQUIRED RT_BIT(5)
411# define BUSLOGIC_REGISTER_STATUS_DIAGNOSTIC_FAILURE RT_BIT(6)
412# define BUSLOGIC_REGISTER_STATUS_DIAGNOSTIC_ACTIVE RT_BIT(7)
413
414#define BUSLOGIC_REGISTER_COMMAND 1 /* Writeonly */
415#define BUSLOGIC_REGISTER_DATAIN 1 /* Readonly */
416#define BUSLOGIC_REGISTER_INTERRUPT 2 /* Readonly */
417/** Fields for the interrupt register. */
418# define BUSLOGIC_REGISTER_INTERRUPT_INCOMING_MAILBOX_LOADED RT_BIT(0)
419# define BUSLOGIC_REGISTER_INTERRUPT_OUTCOMING_MAILBOX_AVAILABLE RT_BIT(1)
420# define BUSLOGIC_REGISTER_INTERRUPT_COMMAND_COMPLETE RT_BIT(2)
421# define BUSLOGIC_REGISTER_INTERRUPT_EXTERNAL_BUS_RESET RT_BIT(3)
422# define BUSLOGIC_REGISTER_INTERRUPT_INTERRUPT_VALID RT_BIT(7)
423
424#define BUSLOGIC_REGISTER_GEOMETRY 3 /* Readonly */
425# define BUSLOGIC_REGISTER_GEOMETRY_EXTENTED_TRANSLATION_ENABLED RT_BIT(7)
426
427/* Structure for the INQUIRE_PCI_HOST_ADAPTER_INFORMATION reply. */
428#pragma pack(1)
429typedef struct ReplyInquirePCIHostAdapterInformation
430{
431 uint8_t IsaIOPort;
432 uint8_t IRQ;
433 unsigned char LowByteTerminated:1;
434 unsigned char HighByteTerminated:1;
435 unsigned char uReserved:2; /* Reserved. */
436 unsigned char JP1:1; /* Whatever that means. */
437 unsigned char JP2:1; /* Whatever that means. */
438 unsigned char JP3:1; /* Whatever that means. */
439 /** Whether the provided info is valid. */
440 unsigned char InformationIsValid: 1;
441 uint8_t uReserved2; /* Reserved. */
442} ReplyInquirePCIHostAdapterInformation, *PReplyInquirePCIHostAdapterInformation;
443AssertCompileSize(ReplyInquirePCIHostAdapterInformation, 4);
444#pragma pack()
445
446/* Structure for the INQUIRE_CONFIGURATION reply. */
447#pragma pack(1)
448typedef struct ReplyInquireConfiguration
449{
450 unsigned char uReserved1: 5;
451 bool fDmaChannel5: 1;
452 bool fDmaChannel6: 1;
453 bool fDmaChannel7: 1;
454 bool fIrqChannel9: 1;
455 bool fIrqChannel10: 1;
456 bool fIrqChannel11: 1;
457 bool fIrqChannel12: 1;
458 unsigned char uReserved2: 1;
459 bool fIrqChannel14: 1;
460 bool fIrqChannel15: 1;
461 unsigned char uReserved3: 1;
462 unsigned char uHostAdapterId: 4;
463 unsigned char uReserved4: 4;
464} ReplyInquireConfiguration, *PReplyInquireConfiguration;
465AssertCompileSize(ReplyInquireConfiguration, 3);
466#pragma pack()
467
468/* Structure for the INQUIRE_SETUP_INFORMATION reply. */
469#pragma pack(1)
470typedef struct ReplyInquireSetupInformationSynchronousValue
471{
472 unsigned char uOffset: 4;
473 unsigned char uTransferPeriod: 3;
474 bool fSynchronous: 1;
475}ReplyInquireSetupInformationSynchronousValue, *PReplyInquireSetupInformationSynchronousValue;
476AssertCompileSize(ReplyInquireSetupInformationSynchronousValue, 1);
477#pragma pack()
478
479#pragma pack(1)
480typedef struct ReplyInquireSetupInformation
481{
482 bool fSynchronousInitiationEnabled: 1;
483 bool fParityCheckingEnabled: 1;
484 unsigned char uReserved1: 6;
485 uint8_t uBusTransferRate;
486 uint8_t uPreemptTimeOnBus;
487 uint8_t uTimeOffBus;
488 uint8_t cMailbox;
489 uint8_t MailboxAddress[3];
490 ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8];
491 uint8_t uDisconnectPermittedId0To7;
492 uint8_t uSignature;
493 uint8_t uCharacterD;
494 uint8_t uHostBusType;
495 uint8_t uWideTransferPermittedId0To7;
496 uint8_t uWideTransfersActiveId0To7;
497 ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8];
498 uint8_t uDisconnectPermittedId8To15;
499 uint8_t uReserved2;
500 uint8_t uWideTransferPermittedId8To15;
501 uint8_t uWideTransfersActiveId8To15;
502} ReplyInquireSetupInformation, *PReplyInquireSetupInformation;
503AssertCompileSize(ReplyInquireSetupInformation, 34);
504#pragma pack()
505
506/* Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */
507#pragma pack(1)
508typedef struct ReplyInquireExtendedSetupInformation
509{
510 uint8_t uBusType;
511 uint8_t uBiosAddress;
512 uint16_t u16ScatterGatherLimit;
513 uint8_t cMailbox;
514 uint32_t uMailboxAddressBase;
515 unsigned char uReserved1: 2;
516 bool fFastEISA: 1;
517 unsigned char uReserved2: 3;
518 bool fLevelSensitiveInterrupt: 1;
519 unsigned char uReserved3: 1;
520 unsigned char aFirmwareRevision[3];
521 bool fHostWideSCSI: 1;
522 bool fHostDifferentialSCSI: 1;
523 bool fHostSupportsSCAM: 1;
524 bool fHostUltraSCSI: 1;
525 bool fHostSmartTermination: 1;
526 unsigned char uReserved4: 3;
527} ReplyInquireExtendedSetupInformation, *PReplyInquireExtendedSetupInformation;
528AssertCompileSize(ReplyInquireExtendedSetupInformation, 14);
529#pragma pack()
530
531/* Structure for the INITIALIZE EXTENDED MAILBOX request. */
532#pragma pack(1)
533typedef struct RequestInitializeExtendedMailbox
534{
535 /** Number of mailboxes in guest memory. */
536 uint8_t cMailbox;
537 /** Physical address of the first mailbox. */
538 uint32_t uMailboxBaseAddress;
539} RequestInitializeExtendedMailbox, *PRequestInitializeExtendedMailbox;
540AssertCompileSize(RequestInitializeExtendedMailbox, 5);
541#pragma pack()
542
543/*
544 * Structure of a mailbox in guest memory.
545 * The incoming and outgoing mailbox have the same size
546 * but the incoming one has some more fields defined which
547 * are marked as reserved in the outgoing one.
548 * The last field is also different from the type.
549 * For outgoing mailboxes it is the action and
550 * for incoming ones the completion status code for the task.
551 * We use one structure for both types.
552 */
553#pragma pack(1)
554typedef struct Mailbox
555{
556 /** Physical adress of the CCB structure in the guest memory. */
557 uint32_t u32PhysAddrCCB;
558 /** Type specific data. */
559 union
560 {
561 /** For outgoing mailboxes. */
562 struct
563 {
564 /** Reserved */
565 uint8_t uReserved[3];
566 /** Action code. */
567 uint8_t uActionCode;
568 } out;
569 /** For incoming mailboxes. */
570 struct
571 {
572 /** The host adapter status after finishing the request. */
573 uint8_t uHostAdapterStatus;
574 /** The status of the device which executed the request after executing it. */
575 uint8_t uTargetDeviceStatus;
576 /** Reserved. */
577 uint8_t uReserved;
578 /** The completion status code of the request. */
579 uint8_t uCompletionCode;
580 } in;
581 } u;
582} Mailbox, *PMailbox;
583AssertCompileSize(Mailbox, 8);
584#pragma pack()
585
586/*
587 * Action codes for outgoing mailboxes.
588 */
589enum BUSLOGIC_MAILBOX_OUTGOING_ACTION
590{
591 BUSLOGIC_MAILBOX_OUTGOING_ACTION_FREE = 0x00,
592 BUSLOGIC_MAILBOX_OUTGOING_ACTION_START_COMMAND = 0x01,
593 BUSLOGIC_MAILBOX_OUTGOING_ACTION_ABORT_COMMAND = 0x02
594};
595
596/*
597 * Completion codes for incoming mailboxes.
598 */
599enum BUSLOGIC_MAILBOX_INCOMING_COMPLETION
600{
601 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_FREE = 0x00,
602 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITHOUT_ERROR = 0x01,
603 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_ABORTED = 0x02,
604 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_ABORTED_NOT_FOUND = 0x03,
605 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITH_ERROR = 0x04,
606 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_INVALID_CCB = 0x05
607};
608
609/*
610 * Host adapter status for incoming mailboxes.
611 */
612enum BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS
613{
614 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED = 0x00,
615 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_LINKED_CMD_COMPLETED = 0x0a,
616 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_LINKED_CMD_COMPLETED_WITH_FLAG = 0x0b,
617 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_DATA_UNDERUN = 0x0c,
618 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_SCSI_SELECTION_TIMEOUT = 0x11,
619 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_DATA_OVERRUN = 0x12,
620 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_UNEXPECTED_BUS_FREE = 0x13,
621 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_INVALID_BUS_PHASE_REQUESTED = 0x14,
622 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_INVALID_OUTGOING_MAILBOX_ACTION_CODE = 0x15,
623 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_INVALID_COMMAND_OPERATION_CODE = 0x16,
624 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_LINKED_CCB_HAS_INVALID_LUN = 0x17,
625 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_INVALID_COMMAND_PARAMETER = 0x1a,
626 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_AUTO_REQUEST_SENSE_FAILED = 0x1b,
627 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_TAGGED_QUEUING_MESSAGE_REJECTED = 0x1c,
628 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_UNSUPPORTED_MESSAGE_RECEIVED = 0x1d,
629 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_HOST_ADAPTER_HARDWARE_FAILED = 0x20,
630 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_TARGET_FAILED_RESPONSE_TO_ATN = 0x21,
631 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_HOST_ADAPTER_ASSERTED_RST = 0x22,
632 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_OTHER_DEVICE_ASSERTED_RST = 0x23,
633 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_TARGET_DEVICE_RECONNECTED_IMPROPERLY = 0x24,
634 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_HOST_ADAPTER_ASSERTED_BUS_DEVICE_RESET = 0x25,
635 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_ABORT_QUEUE_GENERATED = 0x26,
636 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_HOST_ADAPTER_SOFTWARE_ERROR = 0x27,
637 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_HOST_ADAPTER_HARDWARE_TIMEOUT_ERROR = 0x30,
638 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_SCSI_PARITY_ERROR_DETECTED = 0x34
639};
640
641/*
642 * Device status codes for incoming mailboxes.
643 */
644enum BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS
645{
646 BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_OPERATION_GOOD = 0x00,
647 BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_CHECK_CONDITION = 0x02,
648 BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_DEVICE_BUSY = 0x08
649};
650
651/*
652 * Opcode types for CCB.
653 */
654enum BUSLOGIC_CCB_OPCODE
655{
656 BUSLOGIC_CCB_OPCODE_INITIATOR_CCB = 0x00,
657 BUSLOGIC_CCB_OPCODE_TARGET_CCB = 0x01,
658 BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_SCATTER_GATHER = 0x02,
659 BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH = 0x03,
660 BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER = 0x04,
661 BUSLOGIC_CCB_OPCODE_BUS_DEVICE_RESET = 0x81
662};
663
664/*
665 * Data transfer direction.
666 */
667enum BUSLOGIC_CCB_DIRECTION
668{
669 BUSLOGIC_CCB_DIRECTION_UNKNOWN = 0x00,
670 BUSLOGIC_CCB_DIRECTION_IN = 0x01,
671 BUSLOGIC_CCB_DIRECTION_OUT = 0x02,
672 BUSLOGIC_CCB_DIRECTION_NO_DATA = 0x03
673};
674
675/*
676 * The command control block for a SCSI request.
677 */
678#pragma pack(1)
679typedef struct CommandControlBlock
680{
681 /** Opcode. */
682 uint8_t uOpcode;
683 /** Reserved */
684 unsigned char uReserved1: 3;
685 /** Data direction for the request. */
686 unsigned char uDataDirection: 2;
687 /** Whether the request is tag queued. */
688 bool fTagQueued: 1;
689 /** Queue tag mode. */
690 unsigned char uQueueTag: 2;
691 /** Length of the SCSI CDB. */
692 uint8_t cbCDB;
693 /** Sense data length. */
694 uint8_t cbSenseData;
695 /** Data length. */
696 uint32_t cbData;
697 /** Data pointer.
698 * This points to the data region or a scatter gather list based on the opcode.
699 */
700 uint32_t u32PhysAddrData;
701 /** Reserved. */
702 uint8_t uReserved2[2];
703 /** Host adapter status. */
704 uint8_t uHostAdapterStatus;
705 /** Device adapter status. */
706 uint8_t uDeviceStatus;
707 /** The device the request is send to. */
708 uint8_t uTargetId;
709 /**The LUN in the device. */
710 unsigned char uLogicalUnit: 5;
711 /** Legacy tag. */
712 bool fLegacyTagEnable: 1;
713 /** Legacy queue tag. */
714 unsigned char uLegacyQueueTag: 2;
715 /** The SCSI CDB. */
716 uint8_t aCDB[12]; /* A CDB can be 12 bytes long. */
717 /** Reserved. */
718 uint8_t uReserved3[6];
719 /** Sense data pointer. */
720 uint32_t u32PhysAddrSenseData;
721} CommandControlBlock, *PCommandControlBlock;
722AssertCompileSize(CommandControlBlock, 40);
723#pragma pack()
724
725#pragma pack(1)
726typedef struct ScatterGatherEntry
727{
728 uint32_t cbSegment;
729 uint32_t u32PhysAddrSegmentBase;
730} ScatterGatherEntry, *PScatterGatherEntry;
731AssertCompileSize(ScatterGatherEntry, 8);
732#pragma pack()
733
734/*
735 * Task state for a CCB request.
736 */
737typedef struct BUSLOGICTASKSTATE
738{
739 /** Device this task is assigned to. */
740 R3PTRTYPE(PBUSLOGICDEVICE) pTargetDeviceR3;
741 /** The command control block from the guest. */
742 CommandControlBlock CommandControlBlockGuest;
743 /** Mailbox read from guest memory. */
744 Mailbox MailboxGuest;
745 /** The SCSI request we pass to the underlying SCSI engine. */
746 PDMSCSIREQUEST PDMScsiRequest;
747 /** Data buffer segment */
748 RTSGSEG DataSeg;
749 /** Pointer to the R3 sense buffer. */
750 uint8_t *pbSenseBuffer;
751 /** Flag whether this is a request from the BIOS. */
752 bool fBIOS;
753} BUSLOGICTASKSTATE, *PBUSLOGICTASKSTATE;
754
755#ifndef VBOX_DEVICE_STRUCT_TESTCASE
756
757RT_C_DECLS_BEGIN
758PDMBOTHCBDECL(int) buslogicIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
759 RTIOPORT Port, uint32_t u32, unsigned cb);
760PDMBOTHCBDECL(int) buslogicIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
761 RTIOPORT Port, uint32_t *pu32, unsigned cb);
762PDMBOTHCBDECL(int) buslogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
763 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
764PDMBOTHCBDECL(int) buslogicMMIORead(PPDMDEVINS pDevIns, void *pvUser,
765 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
766RT_C_DECLS_END
767
768#define PDMIBASE_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, IBase)) )
769#define PDMISCSIPORT_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, ISCSIPort)) )
770#define PDMILEDPORTS_2_PBUSLOGICDEVICE(pInterface) ( (PBUSLOGICDEVICE)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGICDEVICE, ILed)) )
771#define PDMIBASE_2_PBUSLOGIC(pInterface) ( (PBUSLOGIC)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGIC, IBase)) )
772#define PDMILEDPORTS_2_PBUSLOGIC(pInterface) ( (PBUSLOGIC)((uintptr_t)(pInterface) - RT_OFFSETOF(BUSLOGIC, ILeds)) )
773
774/**
775 * Deasserts the interrupt line of the BusLogic adapter.
776 *
777 * @returns nothing
778 * @param pBuslogic Pointer to the BusLogic device instance.
779 */
780static void buslogicClearInterrupt(PBUSLOGIC pBusLogic)
781{
782 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
783 pBusLogic->regInterrupt = 0;
784 PDMDevHlpPCISetIrqNoWait(pBusLogic->CTX_SUFF(pDevIns), 0, 0);
785}
786
787/**
788 * Assert IRQ line of the BusLogic adapter.
789 *
790 * @returns nothing.
791 * @param pBusLogic Pointer to the BusLogic device instance.
792 */
793static void buslogicSetInterrupt(PBUSLOGIC pBusLogic)
794{
795 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
796 pBusLogic->regInterrupt |= BUSLOGIC_REGISTER_INTERRUPT_INTERRUPT_VALID;
797 if (pBusLogic->fIRQEnabled)
798 PDMDevHlpPCISetIrqNoWait(pBusLogic->CTX_SUFF(pDevIns), 0, 1);
799}
800
801#if defined(IN_RING3)
802/**
803 * Initialize local RAM of host adapter with default values.
804 *
805 * @returns nothing.
806 * @param pBusLogic.
807 */
808static void buslogicInitializeLocalRam(PBUSLOGIC pBusLogic)
809{
810 /*
811 * These values are mostly from what I think is right
812 * looking at the dmesg output from a Linux guest inside
813 * a VMware server VM.
814 *
815 * So they don't have to be right :)
816 */
817 memset(pBusLogic->LocalRam.u8View, 0, sizeof(HostAdapterLocalRam));
818 pBusLogic->LocalRam.structured.autoSCSIData.fLevelSensitiveInterrupt = true;
819 pBusLogic->LocalRam.structured.autoSCSIData.fParityCheckingEnabled = true;
820 pBusLogic->LocalRam.structured.autoSCSIData.fExtendedTranslation = true; /* Same as in geometry register. */
821 pBusLogic->LocalRam.structured.autoSCSIData.u16DeviceEnabledMask = ~0; /* All enabled. Maybe mask out non present devices? */
822 pBusLogic->LocalRam.structured.autoSCSIData.u16WidePermittedMask = ~0;
823 pBusLogic->LocalRam.structured.autoSCSIData.u16FastPermittedMask = ~0;
824 pBusLogic->LocalRam.structured.autoSCSIData.u16SynchronousPermittedMask = ~0;
825 pBusLogic->LocalRam.structured.autoSCSIData.u16DisconnectPermittedMask = ~0;
826 pBusLogic->LocalRam.structured.autoSCSIData.fStrictRoundRobinMode = pBusLogic->fStrictRoundRobinMode;
827 pBusLogic->LocalRam.structured.autoSCSIData.u16UltraPermittedMask = ~0;
828 /* @todo calculate checksum? */
829}
830
831/**
832 * Do a hardware reset of the buslogic adapter.
833 *
834 * @returns VBox status code.
835 * @param pBusLogic Pointer to the BusLogic device instance.
836 */
837static int buslogicHwReset(PBUSLOGIC pBusLogic)
838{
839 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
840
841 /* Reset registers to default value. */
842 pBusLogic->regStatus = BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY;
843 pBusLogic->regInterrupt = 0;
844 pBusLogic->regGeometry = BUSLOGIC_REGISTER_GEOMETRY_EXTENTED_TRANSLATION_ENABLED;
845 pBusLogic->uOperationCode = 0xff; /* No command executing. */
846 pBusLogic->iParameter = 0;
847 pBusLogic->cbCommandParametersLeft = 0;
848 pBusLogic->fIRQEnabled = true;
849 pBusLogic->fISAEnabled = true;
850 pBusLogic->uMailboxOutgoingPositionCurrent = 0;
851 pBusLogic->uMailboxIncomingPositionCurrent = 0;
852
853 buslogicInitializeLocalRam(pBusLogic);
854 vboxscsiInitialize(&pBusLogic->VBoxSCSI);
855
856 return VINF_SUCCESS;
857}
858#endif
859
860/**
861 * Resets the command state machine for the next command and notifies the guest.
862 *
863 * @returns nothing.
864 * @param pBusLogic Pointer to the BusLogic device instance
865 */
866static void buslogicCommandComplete(PBUSLOGIC pBusLogic)
867{
868 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
869
870 pBusLogic->fUseLocalRam = false;
871 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY;
872 pBusLogic->iReply = 0;
873
874 /* Modify I/O address does not generate an interrupt. */
875 if ( (pBusLogic->uOperationCode != BUSLOGICCOMMAND_MODIFY_IO_ADDRESS)
876 && (pBusLogic->uOperationCode != BUSLOGICCOMMAND_EXECUTE_MAILBOX_COMMAND))
877 {
878 /* Notify that the command is complete. */
879 pBusLogic->regStatus &= ~BUSLOGIC_REGISTER_STATUS_DATA_IN_REGISTER_READY;
880 pBusLogic->regInterrupt |= BUSLOGIC_REGISTER_INTERRUPT_COMMAND_COMPLETE;
881
882 /*
883 * SCO OpenServer requires that this flag is set after the ECHO COMMAND
884 * DATA command. Doesn't look like it breaks other guests
885 * but we just set it if the command was actually issued just to be sure.
886 */
887 if (pBusLogic->uOperationCode == BUSLOGICCOMMAND_ECHO_COMMAND_DATA)
888 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_INITIALIZATION_REQUIRED;
889
890 buslogicSetInterrupt(pBusLogic);
891 }
892
893 pBusLogic->uOperationCode = 0xff;
894 pBusLogic->iParameter = 0;
895}
896
897#if defined(IN_RING3)
898/**
899 * Initiates a hard reset which was issued from the guest.
900 *
901 * @returns nothing
902 * @param pBusLogic Pointer to the BusLogic device instance.
903 */
904static void buslogicIntiateHardReset(PBUSLOGIC pBusLogic)
905{
906 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
907
908 buslogicHwReset(pBusLogic);
909
910 /* We set the diagnostic active in the status register. */
911 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_DIAGNOSTIC_ACTIVE;
912}
913
914/**
915 * Send a mailbox with set status codes to the guest.
916 *
917 * @returns nothing.
918 * @param pBusLogicR Pointer to the BubsLogic device instance.
919 * @param pTaskState Pointer to the task state with the mailbox to send.
920 * @param uHostAdapterStatus The host adapter status code to set.
921 * @param uDeviceStatus The target device status to set.
922 * @param uMailboxCompletionCode Completion status code to set in the mailbox.
923 */
924static void buslogicSendIncomingMailbox(PBUSLOGIC pBusLogic, PBUSLOGICTASKSTATE pTaskState,
925 uint8_t uHostAdapterStatus, uint8_t uDeviceStatus,
926 uint8_t uMailboxCompletionCode)
927{
928 pTaskState->MailboxGuest.u.in.uHostAdapterStatus = uHostAdapterStatus;
929 pTaskState->MailboxGuest.u.in.uTargetDeviceStatus = uDeviceStatus;
930 pTaskState->MailboxGuest.u.in.uCompletionCode = uMailboxCompletionCode;
931
932 int rc = PDMCritSectEnter(&pBusLogic->CritSectIntr, VINF_SUCCESS);
933 AssertRC(rc);
934 RTGCPHYS GCPhysAddrMailboxIncoming = pBusLogic->GCPhysAddrMailboxIncomingBase + (pBusLogic->uMailboxIncomingPositionCurrent * sizeof(Mailbox));
935 RTGCPHYS GCPhysAddrCCB = (RTGCPHYS)pTaskState->MailboxGuest.u32PhysAddrCCB;
936
937 /* Update CCB. */
938 pTaskState->CommandControlBlockGuest.uHostAdapterStatus = uHostAdapterStatus;
939 pTaskState->CommandControlBlockGuest.uDeviceStatus = uDeviceStatus;
940 PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrCCB, &pTaskState->CommandControlBlockGuest, sizeof(CommandControlBlock));
941
942 /* Update mailbox. */
943 PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxIncoming, &pTaskState->MailboxGuest, sizeof(Mailbox));
944
945 /* Advance to next mailbox position. */
946 pBusLogic->uMailboxIncomingPositionCurrent++;
947 if (pBusLogic->uMailboxIncomingPositionCurrent >= pBusLogic->cMailbox)
948 pBusLogic->uMailboxIncomingPositionCurrent = 0;
949
950 pBusLogic->regInterrupt |= BUSLOGIC_REGISTER_INTERRUPT_INCOMING_MAILBOX_LOADED;
951 buslogicSetInterrupt(pBusLogic);
952
953 PDMCritSectLeave(&pBusLogic->CritSectIntr);
954}
955
956#if defined(DEBUG)
957/**
958 * Dumps the content of a mailbox for debugging purposes.
959 *
960 * @return nothing
961 * @param pMailbox The mialbox to dump.
962 * @param fOutgoing true if dumping the outgoing state.
963 * false if dumping the incoming state.
964 */
965static void buslogicDumpMailboxInfo(PMailbox pMailbox, bool fOutgoing)
966{
967 Log(("%s: Dump for %s mailbox:\n", __FUNCTION__, fOutgoing ? "outgoing" : "incoming"));
968 Log(("%s: u32PhysAddrCCB=%#x\n", __FUNCTION__, pMailbox->u32PhysAddrCCB));
969 if (fOutgoing)
970 {
971 Log(("%s: uActionCode=%u\n", __FUNCTION__, pMailbox->u.out.uActionCode));
972 }
973 else
974 {
975 Log(("%s: uHostAdapterStatus=%u\n", __FUNCTION__, pMailbox->u.in.uHostAdapterStatus));
976 Log(("%s: uTargetDeviceStatus=%u\n", __FUNCTION__, pMailbox->u.in.uTargetDeviceStatus));
977 Log(("%s: uCompletionCode=%u\n", __FUNCTION__, pMailbox->u.in.uCompletionCode));
978 }
979}
980
981/**
982 * Dumps the content of a command control block for debugging purposes.
983 *
984 * @returns nothing.
985 * @param pCCB Pointer to the command control block to dump.
986 */
987static void buslogicDumpCCBInfo(PCommandControlBlock pCCB)
988{
989 Log(("%s: Dump for Command Control Block:\n", __FUNCTION__));
990 Log(("%s: uOpCode=%#x\n", __FUNCTION__, pCCB->uOpcode));
991 Log(("%s: uDataDirection=%u\n", __FUNCTION__, pCCB->uDataDirection));
992 Log(("%s: fTagQueued=%d\n", __FUNCTION__, pCCB->fTagQueued));
993 Log(("%s: uQueueTag=%u\n", __FUNCTION__, pCCB->uQueueTag));
994 Log(("%s: cbCDB=%u\n", __FUNCTION__, pCCB->cbCDB));
995 Log(("%s: cbSenseData=%u\n", __FUNCTION__, pCCB->cbSenseData));
996 Log(("%s: cbData=%u\n", __FUNCTION__, pCCB->cbData));
997 Log(("%s: u32PhysAddrData=%#x\n", __FUNCTION__, pCCB->u32PhysAddrData));
998 Log(("%s: uHostAdapterStatus=%u\n", __FUNCTION__, pCCB->uHostAdapterStatus));
999 Log(("%s: uDeviceStatus=%u\n", __FUNCTION__, pCCB->uDeviceStatus));
1000 Log(("%s: uTargetId=%u\n", __FUNCTION__, pCCB->uTargetId));
1001 Log(("%s: uLogicalUnit=%u\n", __FUNCTION__, pCCB->uLogicalUnit));
1002 Log(("%s: fLegacyTagEnable=%u\n", __FUNCTION__, pCCB->fLegacyTagEnable));
1003 Log(("%s: uLegacyQueueTag=%u\n", __FUNCTION__, pCCB->uLegacyQueueTag));
1004 Log(("%s: uCDB[0]=%#x\n", __FUNCTION__, pCCB->aCDB[0]));
1005 for (int i = 1; i < pCCB->cbCDB; i++)
1006 Log(("%s: uCDB[%d]=%u\n", __FUNCTION__, i, pCCB->aCDB[i]));
1007 Log(("%s: u32PhysAddrSenseData=%#x\n", __FUNCTION__, pCCB->u32PhysAddrSenseData));
1008}
1009#endif
1010
1011/**
1012 * Allocate data buffer.
1013 *
1014 * @returns VBox status code.
1015 * @param pTaskState Pointer to the task state.
1016 */
1017static int buslogicDataBufferAlloc(PBUSLOGICTASKSTATE pTaskState)
1018{
1019 PPDMDEVINS pDevIns = pTaskState->CTX_SUFF(pTargetDevice)->CTX_SUFF(pBusLogic)->CTX_SUFF(pDevIns);
1020
1021 if ( (pTaskState->CommandControlBlockGuest.uDataDirection != BUSLOGIC_CCB_DIRECTION_NO_DATA)
1022 && (pTaskState->CommandControlBlockGuest.cbData > 0))
1023 {
1024 /*
1025 * @todo: Check following assumption and what residual means.
1026 *
1027 * The BusLogic adapter can handle two different data buffer formats.
1028 * The first one is that the data pointer entry in the CCB points to
1029 * the buffer directly. In second mode the data pointer points to a
1030 * scatter gather list which describes the buffer.
1031 */
1032 if ( (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_SCATTER_GATHER)
1033 || (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
1034 {
1035 uint32_t cScatterGatherGCRead;
1036 uint32_t iScatterGatherEntry;
1037 ScatterGatherEntry aScatterGatherReadGC[32]; /* Number of scatter gather list entries read from guest memory. */
1038 uint32_t cScatterGatherGCLeft = pTaskState->CommandControlBlockGuest.cbData / sizeof(ScatterGatherEntry);
1039 RTGCPHYS GCPhysAddrScatterGatherCurrent = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
1040 size_t cbDataToTransfer = 0;
1041
1042 /* Count number of bytes to transfer. */
1043 do
1044 {
1045 cScatterGatherGCRead = (cScatterGatherGCLeft < RT_ELEMENTS(aScatterGatherReadGC))
1046 ? cScatterGatherGCLeft
1047 : RT_ELEMENTS(aScatterGatherReadGC);
1048 cScatterGatherGCLeft -= cScatterGatherGCRead;
1049
1050 /* Read the SG entries. */
1051 PDMDevHlpPhysRead(pDevIns, GCPhysAddrScatterGatherCurrent, &aScatterGatherReadGC[0],
1052 cScatterGatherGCRead * sizeof(ScatterGatherEntry));
1053
1054 for (iScatterGatherEntry = 0; iScatterGatherEntry < cScatterGatherGCRead; iScatterGatherEntry++)
1055 {
1056 RTGCPHYS GCPhysAddrDataBase;
1057
1058 Log(("%s: iScatterGatherEntry=%u\n", __FUNCTION__, iScatterGatherEntry));
1059
1060 GCPhysAddrDataBase = (RTGCPHYS)aScatterGatherReadGC[iScatterGatherEntry].u32PhysAddrSegmentBase;
1061 cbDataToTransfer += aScatterGatherReadGC[iScatterGatherEntry].cbSegment;
1062
1063 Log(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u\n",
1064 __FUNCTION__, GCPhysAddrDataBase,
1065 aScatterGatherReadGC[iScatterGatherEntry].cbSegment));
1066 }
1067
1068 /* Set address to the next entries to read. */
1069 GCPhysAddrScatterGatherCurrent += cScatterGatherGCRead * sizeof(ScatterGatherEntry);
1070 } while (cScatterGatherGCLeft > 0);
1071
1072 Log(("%s: cbDataToTransfer=%d\n", __FUNCTION__, cbDataToTransfer));
1073
1074 /* Allocate buffer */
1075 pTaskState->DataSeg.cbSeg = cbDataToTransfer;
1076 pTaskState->DataSeg.pvSeg = RTMemAlloc(pTaskState->DataSeg.cbSeg);
1077 if (!pTaskState->DataSeg.pvSeg)
1078 return VERR_NO_MEMORY;
1079
1080 /* Copy the data if needed */
1081 if (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_OUT)
1082 {
1083 cScatterGatherGCLeft = pTaskState->CommandControlBlockGuest.cbData / sizeof(ScatterGatherEntry);
1084 GCPhysAddrScatterGatherCurrent = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
1085 uint8_t *pbData = (uint8_t *)pTaskState->DataSeg.pvSeg;
1086
1087 do
1088 {
1089 cScatterGatherGCRead = (cScatterGatherGCLeft < RT_ELEMENTS(aScatterGatherReadGC))
1090 ? cScatterGatherGCLeft
1091 : RT_ELEMENTS(aScatterGatherReadGC);
1092 cScatterGatherGCLeft -= cScatterGatherGCRead;
1093
1094 /* Read the SG entries. */
1095 PDMDevHlpPhysRead(pDevIns, GCPhysAddrScatterGatherCurrent, &aScatterGatherReadGC[0],
1096 cScatterGatherGCRead * sizeof(ScatterGatherEntry));
1097
1098 for (iScatterGatherEntry = 0; iScatterGatherEntry < cScatterGatherGCRead; iScatterGatherEntry++)
1099 {
1100 RTGCPHYS GCPhysAddrDataBase;
1101
1102 Log(("%s: iScatterGatherEntry=%u\n", __FUNCTION__, iScatterGatherEntry));
1103
1104 GCPhysAddrDataBase = (RTGCPHYS)aScatterGatherReadGC[iScatterGatherEntry].u32PhysAddrSegmentBase;
1105 cbDataToTransfer = aScatterGatherReadGC[iScatterGatherEntry].cbSegment;
1106
1107 Log(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u\n", __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer));
1108
1109 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pbData, cbDataToTransfer);
1110 pbData += cbDataToTransfer;
1111 }
1112
1113 /* Set address to the next entries to read. */
1114 GCPhysAddrScatterGatherCurrent += cScatterGatherGCRead * sizeof(ScatterGatherEntry);
1115 } while (cScatterGatherGCLeft > 0);
1116 }
1117
1118 }
1119 else if ( pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB
1120 || pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
1121 {
1122 /* The buffer is not scattered. */
1123 RTGCPHYS GCPhysAddrDataBase = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
1124
1125 AssertMsg(GCPhysAddrDataBase != 0, ("Physical address is 0\n"));
1126
1127 pTaskState->DataSeg.cbSeg = pTaskState->CommandControlBlockGuest.cbData;
1128 pTaskState->DataSeg.pvSeg = RTMemAlloc(pTaskState->DataSeg.cbSeg);
1129 if (!pTaskState->DataSeg.pvSeg)
1130 return VERR_NO_MEMORY;
1131
1132 Log(("Non scattered buffer:\n"));
1133 Log(("u32PhysAddrData=%#x\n", pTaskState->CommandControlBlockGuest.u32PhysAddrData));
1134 Log(("cbData=%u\n", pTaskState->CommandControlBlockGuest.cbData));
1135 Log(("GCPhysAddrDataBase=0x%RGp\n", GCPhysAddrDataBase));
1136
1137 /* Copy the data into the buffer. */
1138 PDMDevHlpPhysRead(pDevIns, GCPhysAddrDataBase, pTaskState->DataSeg.pvSeg, pTaskState->DataSeg.cbSeg);
1139 }
1140 }
1141
1142 return VINF_SUCCESS;
1143}
1144
1145/**
1146 * Free allocated resources used for the scatter gather list.
1147 *
1148 * @returns nothing.
1149 * @param pTaskState Pointer to the task state.
1150 */
1151static void buslogicDataBufferFree(PBUSLOGICTASKSTATE pTaskState)
1152{
1153 PPDMDEVINS pDevIns = pTaskState->CTX_SUFF(pTargetDevice)->CTX_SUFF(pBusLogic)->CTX_SUFF(pDevIns);
1154
1155 if ( (pTaskState->CommandControlBlockGuest.cbData > 0)
1156 && ( (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_IN)
1157 || (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_UNKNOWN)))
1158 {
1159 if ( (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_SCATTER_GATHER)
1160 || (pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_SCATTER_GATHER))
1161 {
1162 uint32_t cScatterGatherGCRead;
1163 uint32_t iScatterGatherEntry;
1164 ScatterGatherEntry aScatterGatherReadGC[32]; /* Number of scatter gather list entries read from guest memory. */
1165 uint32_t cScatterGatherGCLeft = pTaskState->CommandControlBlockGuest.cbData / sizeof(ScatterGatherEntry);
1166 RTGCPHYS GCPhysAddrScatterGatherCurrent = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
1167 uint8_t *pbData = (uint8_t *)pTaskState->DataSeg.pvSeg;
1168
1169 do
1170 {
1171 cScatterGatherGCRead = (cScatterGatherGCLeft < RT_ELEMENTS(aScatterGatherReadGC))
1172 ? cScatterGatherGCLeft
1173 : RT_ELEMENTS(aScatterGatherReadGC);
1174 cScatterGatherGCLeft -= cScatterGatherGCRead;
1175
1176 /* Read the SG entries. */
1177 PDMDevHlpPhysRead(pDevIns, GCPhysAddrScatterGatherCurrent, &aScatterGatherReadGC[0],
1178 cScatterGatherGCRead * sizeof(ScatterGatherEntry));
1179
1180 for (iScatterGatherEntry = 0; iScatterGatherEntry < cScatterGatherGCRead; iScatterGatherEntry++)
1181 {
1182 RTGCPHYS GCPhysAddrDataBase;
1183 size_t cbDataToTransfer;
1184
1185 Log(("%s: iScatterGatherEntry=%u\n", __FUNCTION__, iScatterGatherEntry));
1186
1187 GCPhysAddrDataBase = (RTGCPHYS)aScatterGatherReadGC[iScatterGatherEntry].u32PhysAddrSegmentBase;
1188 cbDataToTransfer = aScatterGatherReadGC[iScatterGatherEntry].cbSegment;
1189
1190 Log(("%s: GCPhysAddrDataBase=%RGp cbDataToTransfer=%u\n", __FUNCTION__, GCPhysAddrDataBase, cbDataToTransfer));
1191
1192 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pbData, cbDataToTransfer);
1193 pbData += cbDataToTransfer;
1194 }
1195
1196 /* Set address to the next entries to read. */
1197 GCPhysAddrScatterGatherCurrent += cScatterGatherGCRead * sizeof(ScatterGatherEntry);
1198 } while (cScatterGatherGCLeft > 0);
1199
1200 }
1201 else if ( pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB
1202 || pTaskState->CommandControlBlockGuest.uOpcode == BUSLOGIC_CCB_OPCODE_INITIATOR_CCB_RESIDUAL_DATA_LENGTH)
1203 {
1204 /* The buffer is not scattered. */
1205 RTGCPHYS GCPhysAddrDataBase = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrData;
1206
1207 AssertMsg(GCPhysAddrDataBase != 0, ("Physical address is 0\n"));
1208
1209 Log(("Non scattered buffer:\n"));
1210 Log(("u32PhysAddrData=%#x\n", pTaskState->CommandControlBlockGuest.u32PhysAddrData));
1211 Log(("cbData=%u\n", pTaskState->CommandControlBlockGuest.cbData));
1212 Log(("GCPhysAddrDataBase=0x%RGp\n", GCPhysAddrDataBase));
1213
1214 /* Copy the data into the guest memory. */
1215 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrDataBase, pTaskState->DataSeg.pvSeg, pTaskState->DataSeg.cbSeg);
1216 }
1217 }
1218
1219 RTMemFree(pTaskState->DataSeg.pvSeg);
1220 pTaskState->DataSeg.pvSeg = NULL;
1221 pTaskState->DataSeg.cbSeg = 0;
1222}
1223
1224/**
1225 * Free the sense buffer.
1226 *
1227 * @returns nothing.
1228 * @param pTaskState Pointer to the task state.
1229 * @param fCopy If sense data should be copied to guest memory.
1230 */
1231static void buslogicSenseBufferFree(PBUSLOGICTASKSTATE pTaskState, bool fCopy)
1232{
1233 PPDMDEVINS pDevIns = pTaskState->CTX_SUFF(pTargetDevice)->CTX_SUFF(pBusLogic)->CTX_SUFF(pDevIns);
1234 RTGCPHYS GCPhysAddrSenseBuffer = (RTGCPHYS)pTaskState->CommandControlBlockGuest.u32PhysAddrSenseData;
1235 uint32_t cbSenseBuffer = pTaskState->CommandControlBlockGuest.cbSenseData;
1236
1237 /* Copy into guest memory. */
1238 if (fCopy)
1239 PDMDevHlpPhysWrite(pDevIns, GCPhysAddrSenseBuffer, pTaskState->pbSenseBuffer, cbSenseBuffer);
1240
1241 RTMemFree(pTaskState->pbSenseBuffer);
1242 pTaskState->pbSenseBuffer = NULL;
1243}
1244
1245/**
1246 * Alloc the sense buffer.
1247 *
1248 * @returns VBox status code.
1249 * @param pTaskState Pointer to the task state.
1250 * @note Current assumption is that the sense buffer is not scattered and does not cross a page boundary.
1251 */
1252static int buslogicSenseBufferAlloc(PBUSLOGICTASKSTATE pTaskState)
1253{
1254 PPDMDEVINS pDevIns = pTaskState->CTX_SUFF(pTargetDevice)->CTX_SUFF(pBusLogic)->CTX_SUFF(pDevIns);
1255 uint32_t cbSenseBuffer = pTaskState->CommandControlBlockGuest.cbSenseData;
1256
1257 pTaskState->pbSenseBuffer = (uint8_t *)RTMemAllocZ(cbSenseBuffer);
1258 if (!pTaskState->pbSenseBuffer)
1259 return VERR_NO_MEMORY;
1260
1261 return VINF_SUCCESS;
1262}
1263#endif /* IN_RING3 */
1264
1265/**
1266 * Parses the command buffer and executes it.
1267 *
1268 * @returns VBox status code.
1269 * @param pBusLogic Pointer to the BusLogic device instance.
1270 */
1271static int buslogicProcessCommand(PBUSLOGIC pBusLogic)
1272{
1273 int rc = VINF_SUCCESS;
1274
1275 LogFlowFunc(("pBusLogic=%#p\n", pBusLogic));
1276 AssertMsg(pBusLogic->uOperationCode != 0xff, ("There is no command to execute\n"));
1277
1278 switch (pBusLogic->uOperationCode)
1279 {
1280 case BUSLOGICCOMMAND_INQUIRE_PCI_HOST_ADAPTER_INFORMATION:
1281 {
1282 PReplyInquirePCIHostAdapterInformation pReply = (PReplyInquirePCIHostAdapterInformation)pBusLogic->aReplyBuffer;
1283 memset(pReply, 0, sizeof(ReplyInquirePCIHostAdapterInformation));
1284
1285 /* It seems VMware does not provide valid information here too, lets do the same :) */
1286 pReply->InformationIsValid = 0;
1287 pReply->IsaIOPort = 0xff; /* Make it invalid. */
1288 pBusLogic->cbReplyParametersLeft = sizeof(ReplyInquirePCIHostAdapterInformation);
1289 break;
1290 }
1291 case BUSLOGICCOMMAND_MODIFY_IO_ADDRESS:
1292 {
1293 pBusLogic->cbReplyParametersLeft = 0;
1294 if (pBusLogic->aCommandBuffer[0] == 0x06)
1295 {
1296 Log(("Disabling ISA I/O ports.\n"));
1297 pBusLogic->fISAEnabled = false;
1298 }
1299 break;
1300 }
1301 case BUSLOGICCOMMAND_INQUIRE_BOARD_ID:
1302 {
1303 pBusLogic->aReplyBuffer[0] = '0'; /* @todo figure out what to write here. */
1304 pBusLogic->aReplyBuffer[1] = '1'; /* @todo figure out what to write here - can't be '0' or 'B'. */
1305
1306 /* We report version 5.07B. This reply will provide the first two digits. */
1307 pBusLogic->aReplyBuffer[2] = '5'; /* Major version 5 */
1308 pBusLogic->aReplyBuffer[3] = '0'; /* Minor version 0 */
1309 pBusLogic->cbReplyParametersLeft = 4; /* Reply is 4 bytes long */
1310 break;
1311 }
1312 case BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_3RD_LETTER:
1313 {
1314 pBusLogic->aReplyBuffer[0] = '7';
1315 pBusLogic->cbReplyParametersLeft = 1;
1316 break;
1317 }
1318 case BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_LETTER:
1319 {
1320 pBusLogic->aReplyBuffer[0] = 'B';
1321 pBusLogic->cbReplyParametersLeft = 1;
1322 break;
1323 }
1324 case BUSLOGICCOMMAND_INQUIRE_HOST_ADAPTER_MODEL_NUMBER:
1325 {
1326 /* The reply length is set by the guest and is found in the first byte of the command buffer. */
1327 pBusLogic->cbReplyParametersLeft = pBusLogic->aCommandBuffer[0];
1328 memset(pBusLogic->aReplyBuffer, 0, pBusLogic->cbReplyParametersLeft);
1329 const char aModelName[] = "958";
1330 int cCharsToTransfer = (pBusLogic->cbReplyParametersLeft <= sizeof(aModelName))
1331 ? pBusLogic->cbReplyParametersLeft
1332 : sizeof(aModelName);
1333
1334 for (int i = 0; i < cCharsToTransfer; i++)
1335 pBusLogic->aReplyBuffer[i] = aModelName[i];
1336
1337 break;
1338 }
1339 case BUSLOGICCOMMAND_INQUIRE_CONFIGURATION:
1340 {
1341 pBusLogic->cbReplyParametersLeft = sizeof(ReplyInquireConfiguration);
1342 PReplyInquireConfiguration pReply = (PReplyInquireConfiguration)pBusLogic->aReplyBuffer;
1343 memset(pReply, 0, sizeof(ReplyInquireConfiguration));
1344
1345 pReply->uHostAdapterId = 7; /* The controller has always 7 as ID. */
1346 /*
1347 * The rest of this reply only applies for ISA adapters.
1348 * This is a PCI adapter so they are not important and are skipped.
1349 */
1350 break;
1351 }
1352 case BUSLOGICCOMMAND_INQUIRE_EXTENDED_SETUP_INFORMATION:
1353 {
1354 /* The reply length is set by the guest and is found in the first byte of the command buffer. */
1355 pBusLogic->cbReplyParametersLeft = pBusLogic->aCommandBuffer[0];
1356 PReplyInquireExtendedSetupInformation pReply = (PReplyInquireExtendedSetupInformation)pBusLogic->aReplyBuffer;
1357 memset(pReply, 0, sizeof(ReplyInquireExtendedSetupInformation));
1358
1359 pReply->fHostWideSCSI = true;
1360 pReply->fHostUltraSCSI = true;
1361 pReply->u16ScatterGatherLimit = 8192;
1362 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_INITIALIZATION_REQUIRED;
1363
1364 break;
1365 }
1366 case BUSLOGICCOMMAND_INQUIRE_SETUP_INFORMATION:
1367 {
1368 /* The reply length is set by the guest and is found in the first byte of the command buffer. */
1369 pBusLogic->cbReplyParametersLeft = pBusLogic->aCommandBuffer[0];
1370 PReplyInquireSetupInformation pReply = (PReplyInquireSetupInformation)pBusLogic->aReplyBuffer;
1371 memset(pReply, 0, sizeof(ReplyInquireSetupInformation));
1372 break;
1373 }
1374 case BUSLOGICCOMMAND_FETCH_HOST_ADAPTER_LOCAL_RAM:
1375 {
1376 /*
1377 * First element in the command buffer contains start offset to read from
1378 * and second one the number of bytes to read.
1379 */
1380 uint8_t uOffset = pBusLogic->aCommandBuffer[0];
1381 pBusLogic->cbReplyParametersLeft = pBusLogic->aCommandBuffer[1];
1382
1383 pBusLogic->fUseLocalRam = true;
1384 pBusLogic->iReply = uOffset;
1385 break;
1386 }
1387 case BUSLOGICCOMMAND_INITIALIZE_EXTENDED_MAILBOX:
1388 {
1389 PRequestInitializeExtendedMailbox pRequest = (PRequestInitializeExtendedMailbox)pBusLogic->aCommandBuffer;
1390
1391 pBusLogic->cMailbox = pRequest->cMailbox;
1392 pBusLogic->GCPhysAddrMailboxOutgoingBase = (RTGCPHYS)pRequest->uMailboxBaseAddress;
1393 /* The area for incoming mailboxes is right after the last entry of outgoing mailboxes. */
1394 pBusLogic->GCPhysAddrMailboxIncomingBase = (RTGCPHYS)pRequest->uMailboxBaseAddress + (pBusLogic->cMailbox * sizeof(Mailbox));
1395
1396 Log(("GCPhysAddrMailboxOutgoingBase=%RGp\n", pBusLogic->GCPhysAddrMailboxOutgoingBase));
1397 Log(("GCPhysAddrMailboxOutgoingBase=%RGp\n", pBusLogic->GCPhysAddrMailboxIncomingBase));
1398 Log(("cMailboxes=%u\n", pBusLogic->cMailbox));
1399
1400 pBusLogic->cbReplyParametersLeft = 0;
1401 break;
1402 }
1403 case BUSLOGICCOMMAND_ENABLE_STRICT_ROUND_ROBIN_MODE:
1404 {
1405 if (pBusLogic->aCommandBuffer[0] == 0)
1406 pBusLogic->fStrictRoundRobinMode = false;
1407 else if (pBusLogic->aCommandBuffer[0] == 1)
1408 pBusLogic->fStrictRoundRobinMode = true;
1409 else
1410 AssertMsgFailed(("Invalid round robin mode %d\n", pBusLogic->aCommandBuffer[0]));
1411
1412 pBusLogic->cbReplyParametersLeft = 0;
1413 break;
1414 }
1415 case BUSLOGICCOMMAND_SET_CCB_FORMAT:
1416 {
1417 if (pBusLogic->aCommandBuffer[0] == 0)
1418 pBusLogic->fExtendedLunCCBFormat = false;
1419 else if (pBusLogic->aCommandBuffer[0] == 1)
1420 pBusLogic->fExtendedLunCCBFormat = true;
1421 else
1422 AssertMsgFailed(("Invalid CCB format %d\n", pBusLogic->aCommandBuffer[0]));
1423
1424 pBusLogic->cbReplyParametersLeft = 0;
1425 break;
1426 }
1427 case BUSLOGICCOMMAND_INQUIRE_TARGET_DEVICES:
1428 {
1429 /* Each bit which is set in the 16bit wide variable means a present device. */
1430 uint16_t u16TargetsPresentMask = 0;
1431
1432 for (uint8_t i = 0; i < RT_ELEMENTS(pBusLogic->aDeviceStates); i++)
1433 {
1434 if (pBusLogic->aDeviceStates[i].fPresent)
1435 u16TargetsPresentMask |= (1 << i);
1436 }
1437 pBusLogic->aReplyBuffer[0] = (uint8_t)u16TargetsPresentMask;
1438 pBusLogic->aReplyBuffer[1] = (uint8_t)(u16TargetsPresentMask >> 8);
1439 pBusLogic->cbReplyParametersLeft = 2;
1440 break;
1441 }
1442 case BUSLOGICCOMMAND_INQUIRE_SYNCHRONOUS_PERIOD:
1443 {
1444 pBusLogic->cbReplyParametersLeft = pBusLogic->aCommandBuffer[0];
1445
1446 for (uint8_t i = 0; i < pBusLogic->cbReplyParametersLeft; i++)
1447 pBusLogic->aReplyBuffer[i] = 0; /* @todo Figure if we need something other here. It's not needed for the linux driver */
1448
1449 break;
1450 }
1451 case BUSLOGICCOMMAND_DISABLE_HOST_ADAPTER_INTERRUPT:
1452 {
1453 if (pBusLogic->aCommandBuffer[0] == 0)
1454 pBusLogic->fIRQEnabled = false;
1455 else
1456 pBusLogic->fIRQEnabled = true;
1457 break;
1458 }
1459 case BUSLOGICCOMMAND_ECHO_COMMAND_DATA:
1460 {
1461 pBusLogic->aReplyBuffer[0] = pBusLogic->aCommandBuffer[0];
1462 pBusLogic->cbReplyParametersLeft = 1;
1463 break;
1464 }
1465 case BUSLOGICCOMMAND_EXECUTE_MAILBOX_COMMAND: /* Should be handled already. */
1466 default:
1467 AssertMsgFailed(("Invalid command %#x\n", pBusLogic->uOperationCode));
1468 }
1469
1470 Log(("cbReplyParametersLeft=%d\n", pBusLogic->cbReplyParametersLeft));
1471
1472 /* Set the data in ready bit in the status register in case the command has a reply. */
1473 if (pBusLogic->cbReplyParametersLeft)
1474 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_DATA_IN_REGISTER_READY;
1475 else
1476 buslogicCommandComplete(pBusLogic);
1477
1478 return rc;
1479}
1480
1481/**
1482 * Read a register from the BusLogic adapter.
1483 *
1484 * @returns VBox status code.
1485 * @param pBusLogic Pointer to the BusLogic instance data.
1486 * @param iRegister The index of the register to read.
1487 * @param pu32 Where to store the register content.
1488 */
1489static int buslogicRegisterRead(PBUSLOGIC pBusLogic, unsigned iRegister, uint32_t *pu32)
1490{
1491 int rc = VINF_SUCCESS;
1492
1493 switch (iRegister)
1494 {
1495 case BUSLOGIC_REGISTER_STATUS:
1496 {
1497 *pu32 = pBusLogic->regStatus;
1498 /*
1499 * If the diagnostic active bit is set we are in a hard reset initiated from the guest.
1500 * The guest reads the status register and waits that the host adapter ready bit is set.
1501 */
1502 if (pBusLogic->regStatus & BUSLOGIC_REGISTER_STATUS_DIAGNOSTIC_ACTIVE)
1503 {
1504 pBusLogic->regStatus &= ~BUSLOGIC_REGISTER_STATUS_DIAGNOSTIC_ACTIVE;
1505 pBusLogic->regStatus |= BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY;
1506 }
1507 break;
1508 }
1509 case BUSLOGIC_REGISTER_DATAIN:
1510 {
1511 if (pBusLogic->fUseLocalRam)
1512 *pu32 = pBusLogic->LocalRam.u8View[pBusLogic->iReply];
1513 else
1514 *pu32 = pBusLogic->aReplyBuffer[pBusLogic->iReply];
1515
1516 pBusLogic->iReply++;
1517 pBusLogic->cbReplyParametersLeft--;
1518
1519 LogFlowFunc(("cbReplyParametersLeft=%u\n", pBusLogic->cbReplyParametersLeft));
1520 if (!pBusLogic->cbReplyParametersLeft)
1521 {
1522 /*
1523 * Reply finished, set command complete bit, unset data in ready bit and
1524 * interrupt the guest if enabled.
1525 */
1526 buslogicCommandComplete(pBusLogic);
1527 }
1528 break;
1529 }
1530 case BUSLOGIC_REGISTER_INTERRUPT:
1531 {
1532 *pu32 = pBusLogic->regInterrupt;
1533 break;
1534 }
1535 case BUSLOGIC_REGISTER_GEOMETRY:
1536 {
1537 *pu32 = pBusLogic->regGeometry;
1538 break;
1539 }
1540 default:
1541 *pu32 = UINT32_C(0xffffffff);
1542 }
1543
1544 Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n",
1545 __FUNCTION__, pu32, 1, pu32, iRegister, rc));
1546
1547 return rc;
1548}
1549
1550/**
1551 * Write a value to a register.
1552 *
1553 * @returns VBox status code.
1554 * @param pBusLogic Pointer to the BusLogic instance data.
1555 * @param iRegister The index of the register to read.
1556 * @param uVal The value to write.
1557 */
1558static int buslogicRegisterWrite(PBUSLOGIC pBusLogic, unsigned iRegister, uint8_t uVal)
1559{
1560 int rc = VINF_SUCCESS;
1561
1562 switch (iRegister)
1563 {
1564 case BUSLOGIC_REGISTER_CONTROL:
1565 {
1566 rc = PDMCritSectEnter(&pBusLogic->CritSectIntr, VINF_IOM_HC_IOPORT_WRITE);
1567 if (rc != VINF_SUCCESS)
1568 return rc;
1569
1570 if (uVal & BUSLOGIC_REGISTER_CONTROL_INTERRUPT_RESET)
1571 {
1572 buslogicClearInterrupt(pBusLogic);
1573 /*
1574 * Clear the flag in case it is set
1575 * to avoid confusing other guests.
1576 * SCO OpenServer doesn't need it anymore to be set.
1577 */
1578 pBusLogic->regStatus &= ~BUSLOGIC_REGISTER_STATUS_INITIALIZATION_REQUIRED;
1579 }
1580
1581 PDMCritSectLeave(&pBusLogic->CritSectIntr);
1582
1583 if ((uVal & BUSLOGIC_REGISTER_CONTROL_HARD_RESET) || (uVal & BUSLOGIC_REGISTER_CONTROL_SOFT_RESET))
1584 {
1585#ifdef IN_RING3
1586 buslogicIntiateHardReset(pBusLogic);
1587#else
1588 rc = VINF_IOM_HC_IOPORT_WRITE;
1589#endif
1590 }
1591
1592 break;
1593 }
1594 case BUSLOGIC_REGISTER_COMMAND:
1595 {
1596 /* Fast path for mailbox execution command. */
1597 if ((uVal == BUSLOGICCOMMAND_EXECUTE_MAILBOX_COMMAND) && (pBusLogic->uOperationCode == 0xff))
1598 {
1599 ASMAtomicIncU32(&pBusLogic->cMailboxesReady);
1600 if (!ASMAtomicXchgBool(&pBusLogic->fNotificationSend, true))
1601 {
1602 /* Send new notification to the queue. */
1603 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pBusLogic->CTX_SUFF(pNotifierQueue));
1604 AssertMsg(pItem, ("Allocating item for queue failed\n"));
1605 PDMQueueInsert(pBusLogic->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
1606 }
1607
1608 return rc;
1609 }
1610
1611 /*
1612 * Check if we are already fetch command parameters from the guest.
1613 * If not we initialize executing a new command.
1614 */
1615 if (pBusLogic->uOperationCode == 0xff)
1616 {
1617 pBusLogic->uOperationCode = uVal;
1618 pBusLogic->iParameter = 0;
1619
1620 /* Mark host adapter as busy. */
1621 pBusLogic->regStatus &= ~BUSLOGIC_REGISTER_STATUS_HOST_ADAPTER_READY;
1622
1623 /* Get the number of bytes for parameters from the command code. */
1624 switch (pBusLogic->uOperationCode)
1625 {
1626 case BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_LETTER:
1627 case BUSLOGICCOMMAND_INQUIRE_BOARD_ID:
1628 case BUSLOGICCOMMAND_INQUIRE_FIRMWARE_VERSION_3RD_LETTER:
1629 case BUSLOGICCOMMAND_INQUIRE_PCI_HOST_ADAPTER_INFORMATION:
1630 case BUSLOGICCOMMAND_INQUIRE_CONFIGURATION:
1631 case BUSLOGICCOMMAND_INQUIRE_TARGET_DEVICES:
1632 pBusLogic->cbCommandParametersLeft = 0;
1633 break;
1634 case BUSLOGICCOMMAND_MODIFY_IO_ADDRESS:
1635 case BUSLOGICCOMMAND_INQUIRE_EXTENDED_SETUP_INFORMATION:
1636 case BUSLOGICCOMMAND_INQUIRE_SETUP_INFORMATION:
1637 case BUSLOGICCOMMAND_INQUIRE_HOST_ADAPTER_MODEL_NUMBER:
1638 case BUSLOGICCOMMAND_ENABLE_STRICT_ROUND_ROBIN_MODE:
1639 case BUSLOGICCOMMAND_SET_CCB_FORMAT:
1640 case BUSLOGICCOMMAND_INQUIRE_SYNCHRONOUS_PERIOD:
1641 case BUSLOGICCOMMAND_DISABLE_HOST_ADAPTER_INTERRUPT:
1642 case BUSLOGICCOMMAND_ECHO_COMMAND_DATA:
1643 pBusLogic->cbCommandParametersLeft = 1;
1644 break;
1645 case BUSLOGICCOMMAND_FETCH_HOST_ADAPTER_LOCAL_RAM:
1646 pBusLogic->cbCommandParametersLeft = 2;
1647 break;
1648 case BUSLOGICCOMMAND_INITIALIZE_EXTENDED_MAILBOX:
1649 pBusLogic->cbCommandParametersLeft = sizeof(RequestInitializeExtendedMailbox);
1650 break;
1651 case BUSLOGICCOMMAND_EXECUTE_MAILBOX_COMMAND: /* Should not come here anymore. */
1652 default:
1653 AssertMsgFailed(("Invalid operation code %#x\n", uVal));
1654 }
1655 }
1656 else
1657 {
1658 /*
1659 * The real adapter would set the Command register busy bit in the status register.
1660 * The guest has to wait until it is unset.
1661 * We don't need to do it because the guest does not continue execution while we are in this
1662 * function.
1663 */
1664 pBusLogic->aCommandBuffer[pBusLogic->iParameter] = uVal;
1665 pBusLogic->iParameter++;
1666 pBusLogic->cbCommandParametersLeft--;
1667 }
1668
1669 /* Start execution of command if there are no parameters left. */
1670 if (!pBusLogic->cbCommandParametersLeft)
1671 {
1672 rc = buslogicProcessCommand(pBusLogic);
1673 AssertMsgRC(rc, ("Processing command failed rc=%Rrc\n", rc));
1674 }
1675 break;
1676 }
1677 default:
1678 AssertMsgFailed(("Register not available\n"));
1679 rc = VERR_IOM_IOPORT_UNUSED;
1680 }
1681
1682 return rc;
1683}
1684
1685/**
1686 * Memory mapped I/O Handler for read operations.
1687 *
1688 * @returns VBox status code.
1689 *
1690 * @param pDevIns The device instance.
1691 * @param pvUser User argument.
1692 * @param GCPhysAddr Physical address (in GC) where the read starts.
1693 * @param pv Where to store the result.
1694 * @param cb Number of bytes read.
1695 */
1696PDMBOTHCBDECL(int) buslogicMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1697 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1698{
1699 /* the linux driver does not make use of the MMIO area. */
1700 AssertMsgFailed(("MMIO Read\n"));
1701 return VINF_SUCCESS;
1702}
1703
1704/**
1705 * Memory mapped I/O Handler for write operations.
1706 *
1707 * @returns VBox status code.
1708 *
1709 * @param pDevIns The device instance.
1710 * @param pvUser User argument.
1711 * @param GCPhysAddr Physical address (in GC) where the read starts.
1712 * @param pv Where to fetch the result.
1713 * @param cb Number of bytes to write.
1714 */
1715PDMBOTHCBDECL(int) buslogicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1716 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
1717{
1718 /* the linux driver does not make use of the MMIO area. */
1719 AssertMsgFailed(("MMIO Write\n"));
1720 return VINF_SUCCESS;
1721}
1722
1723/**
1724 * Port I/O Handler for IN operations.
1725 *
1726 * @returns VBox status code.
1727 *
1728 * @param pDevIns The device instance.
1729 * @param pvUser User argument.
1730 * @param uPort Port number used for the IN operation.
1731 * @param pu32 Where to store the result.
1732 * @param cb Number of bytes read.
1733 */
1734PDMBOTHCBDECL(int) buslogicIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
1735 RTIOPORT Port, uint32_t *pu32, unsigned cb)
1736{
1737 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);;
1738 unsigned iRegister = Port - pBusLogic->IOPortBase;
1739
1740 Assert(cb == 1);
1741
1742 return buslogicRegisterRead(pBusLogic, iRegister, pu32);
1743}
1744
1745/**
1746 * Port I/O Handler for OUT operations.
1747 *
1748 * @returns VBox status code.
1749 *
1750 * @param pDevIns The device instance.
1751 * @param pvUser User argument.
1752 * @param uPort Port number used for the IN operation.
1753 * @param u32 The value to output.
1754 * @param cb The value size in bytes.
1755 */
1756PDMBOTHCBDECL(int) buslogicIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
1757 RTIOPORT Port, uint32_t u32, unsigned cb)
1758{
1759 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1760 int rc = VINF_SUCCESS;
1761 unsigned iRegister = Port - pBusLogic->IOPortBase;
1762 uint8_t uVal = (uint8_t)u32;
1763
1764 Assert(cb == 1);
1765
1766 rc = buslogicRegisterWrite(pBusLogic, iRegister, (uint8_t)uVal);
1767
1768 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x rc=%Rrc\n",
1769 pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port, rc));
1770
1771 return rc;
1772}
1773
1774#ifdef IN_RING3
1775/**
1776 * Port I/O Handler for IN operations - legacy port.
1777 *
1778 * @returns VBox status code.
1779 *
1780 * @param pDevIns The device instance.
1781 * @param pvUser User argument.
1782 * @param uPort Port number used for the IN operation.
1783 * @param pu32 Where to store the result.
1784 * @param cb Number of bytes read.
1785 */
1786static int buslogicIsaIOPortRead (PPDMDEVINS pDevIns, void *pvUser,
1787 RTIOPORT Port, uint32_t *pu32, unsigned cb)
1788{
1789 int rc;
1790 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1791
1792 Assert(cb == 1);
1793
1794 if (!pBusLogic->fISAEnabled)
1795 return VINF_SUCCESS;
1796
1797 rc = vboxscsiReadRegister(&pBusLogic->VBoxSCSI, (Port - BUSLOGIC_ISA_IO_PORT), pu32);
1798
1799 //Log2(("%s: pu32=%p:{%.*Rhxs} iRegister=%d rc=%Rrc\n",
1800 // __FUNCTION__, pu32, 1, pu32, (Port - BUSLOGIC_ISA_IO_PORT), rc));
1801
1802 return rc;
1803}
1804
1805static int buslogicPrepareBIOSSCSIRequest(PBUSLOGIC pBusLogic)
1806{
1807 int rc;
1808 PBUSLOGICTASKSTATE pTaskState;
1809 uint32_t uTargetDevice;
1810
1811 rc = RTMemCacheAllocEx(pBusLogic->hTaskCache, (void **)&pTaskState);
1812 AssertMsgRCReturn(rc, ("Getting task from cache failed rc=%Rrc\n", rc), rc);
1813
1814 pTaskState->fBIOS = true;
1815
1816 rc = vboxscsiSetupRequest(&pBusLogic->VBoxSCSI, &pTaskState->PDMScsiRequest, &uTargetDevice);
1817 AssertMsgRCReturn(rc, ("Setting up SCSI request failed rc=%Rrc\n", rc), rc);
1818
1819 pTaskState->PDMScsiRequest.pvUser = pTaskState;
1820
1821 pTaskState->CTX_SUFF(pTargetDevice) = &pBusLogic->aDeviceStates[uTargetDevice];
1822
1823 if (!pTaskState->CTX_SUFF(pTargetDevice)->fPresent)
1824 {
1825 /* Device is not present. */
1826 AssertMsg(pTaskState->PDMScsiRequest.pbCDB[0] == SCSI_INQUIRY,
1827 ("Device is not present but command is not inquiry\n"));
1828
1829 SCSIINQUIRYDATA ScsiInquiryData;
1830
1831 memset(&ScsiInquiryData, 0, sizeof(SCSIINQUIRYDATA));
1832 ScsiInquiryData.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN;
1833 ScsiInquiryData.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED;
1834
1835 memcpy(pBusLogic->VBoxSCSI.pBuf, &ScsiInquiryData, 5);
1836
1837 rc = vboxscsiRequestFinished(&pBusLogic->VBoxSCSI, &pTaskState->PDMScsiRequest);
1838 AssertMsgRCReturn(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc), rc);
1839
1840 RTMemCacheFree(pBusLogic->hTaskCache, pTaskState);
1841 }
1842 else
1843 {
1844 LogFlowFunc(("before increment %u\n", pTaskState->CTX_SUFF(pTargetDevice)->cOutstandingRequests));
1845 ASMAtomicIncU32(&pTaskState->CTX_SUFF(pTargetDevice)->cOutstandingRequests);
1846 LogFlowFunc(("after increment %u\n", pTaskState->CTX_SUFF(pTargetDevice)->cOutstandingRequests));
1847
1848 rc = pTaskState->CTX_SUFF(pTargetDevice)->pDrvSCSIConnector->pfnSCSIRequestSend(pTaskState->CTX_SUFF(pTargetDevice)->pDrvSCSIConnector,
1849 &pTaskState->PDMScsiRequest);
1850 AssertMsgRCReturn(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc), rc);
1851 }
1852
1853 return rc;
1854}
1855
1856/**
1857 * Port I/O Handler for OUT operations - legacy port.
1858 *
1859 * @returns VBox status code.
1860 *
1861 * @param pDevIns The device instance.
1862 * @param pvUser User argument.
1863 * @param uPort Port number used for the IN operation.
1864 * @param u32 The value to output.
1865 * @param cb The value size in bytes.
1866 */
1867static int buslogicIsaIOPortWrite (PPDMDEVINS pDevIns, void *pvUser,
1868 RTIOPORT Port, uint32_t u32, unsigned cb)
1869{
1870 int rc;
1871 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1872
1873 Log2(("#%d %s: pvUser=%#p cb=%d u32=%#x Port=%#x\n",
1874 pDevIns->iInstance, __FUNCTION__, pvUser, cb, u32, Port));
1875
1876 Assert(cb == 1);
1877
1878 if (!pBusLogic->fISAEnabled)
1879 return VINF_SUCCESS;
1880
1881 rc = vboxscsiWriteRegister(&pBusLogic->VBoxSCSI, (Port - BUSLOGIC_ISA_IO_PORT), (uint8_t)u32);
1882 if (rc == VERR_MORE_DATA)
1883 {
1884 rc = buslogicPrepareBIOSSCSIRequest(pBusLogic);
1885 AssertRC(rc);
1886 }
1887 else if (RT_FAILURE(rc))
1888 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
1889
1890 return VINF_SUCCESS;
1891}
1892
1893/**
1894 * Port I/O Handler for primary port range OUT string operations.
1895 * @see FNIOMIOPORTOUTSTRING for details.
1896 */
1897static DECLCALLBACK(int) buslogicIsaIOPortWriteStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrSrc, PRTGCUINTREG pcTransfer, unsigned cb)
1898{
1899 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1900 int rc;
1901
1902 Log2(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
1903 pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
1904
1905 rc = vboxscsiWriteString(pDevIns, &pBusLogic->VBoxSCSI, (Port - BUSLOGIC_ISA_IO_PORT),
1906 pGCPtrSrc, pcTransfer, cb);
1907 if (rc == VERR_MORE_DATA)
1908 {
1909 rc = buslogicPrepareBIOSSCSIRequest(pBusLogic);
1910 AssertRC(rc);
1911 }
1912 else if (RT_FAILURE(rc))
1913 AssertMsgFailed(("Writing BIOS register failed %Rrc\n", rc));
1914
1915 return rc;
1916}
1917
1918/**
1919 * Port I/O Handler for primary port range IN string operations.
1920 * @see FNIOMIOPORTINSTRING for details.
1921 */
1922static DECLCALLBACK(int) buslogicIsaIOPortReadStr(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, RTGCPTR *pGCPtrDst, PRTGCUINTREG pcTransfer, unsigned cb)
1923{
1924 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1925
1926 LogFlowFunc(("#%d %s: pvUser=%#p cb=%d Port=%#x\n",
1927 pDevIns->iInstance, __FUNCTION__, pvUser, cb, Port));
1928
1929 return vboxscsiReadString(pDevIns, &pBusLogic->VBoxSCSI, (Port - BUSLOGIC_ISA_IO_PORT),
1930 pGCPtrDst, pcTransfer, cb);
1931}
1932
1933static DECLCALLBACK(int) buslogicMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
1934 RTGCPHYS GCPhysAddress, uint32_t cb,
1935 PCIADDRESSSPACE enmType)
1936{
1937 PPDMDEVINS pDevIns = pPciDev->pDevIns;
1938 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
1939 int rc = VINF_SUCCESS;
1940
1941 Log2(("%s: registering MMIO area at GCPhysAddr=%RGp cb=%u\n", __FUNCTION__, GCPhysAddress, cb));
1942
1943 Assert(cb >= 32);
1944
1945 if (enmType == PCI_ADDRESS_SPACE_MEM)
1946 {
1947 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
1948 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL,
1949 buslogicMMIOWrite, buslogicMMIORead, NULL, "BusLogic");
1950 if (RT_FAILURE(rc))
1951 return rc;
1952
1953 if (pThis->fR0Enabled)
1954 {
1955 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, 0,
1956 "buslogicMMIOWrite", "buslogicMMIORead", NULL);
1957 if (RT_FAILURE(rc))
1958 return rc;
1959 }
1960
1961 if (pThis->fGCEnabled)
1962 {
1963 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, 0,
1964 "buslogicMMIOWrite", "buslogicMMIORead", NULL);
1965 if (RT_FAILURE(rc))
1966 return rc;
1967 }
1968
1969 pThis->MMIOBase = GCPhysAddress;
1970 }
1971 else if (enmType == PCI_ADDRESS_SPACE_IO)
1972 {
1973 rc = PDMDevHlpIOPortRegister(pDevIns, (RTIOPORT)GCPhysAddress, 32,
1974 NULL, buslogicIOPortWrite, buslogicIOPortRead, NULL, NULL, "BusLogic");
1975 if (RT_FAILURE(rc))
1976 return rc;
1977
1978 if (pThis->fR0Enabled)
1979 {
1980 rc = PDMDevHlpIOPortRegisterR0(pDevIns, (RTIOPORT)GCPhysAddress, 32,
1981 0, "buslogicIOPortWrite", "buslogicIOPortRead", NULL, NULL, "BusLogic");
1982 if (RT_FAILURE(rc))
1983 return rc;
1984 }
1985
1986 if (pThis->fGCEnabled)
1987 {
1988 rc = PDMDevHlpIOPortRegisterRC(pDevIns, (RTIOPORT)GCPhysAddress, 32,
1989 0, "buslogicIOPortWrite", "buslogicIOPortRead", NULL, NULL, "BusLogic");
1990 if (RT_FAILURE(rc))
1991 return rc;
1992 }
1993
1994 pThis->IOPortBase = (RTIOPORT)GCPhysAddress;
1995 }
1996 else
1997 AssertMsgFailed(("Invalid enmType=%d\n", enmType));
1998
1999 return rc;
2000}
2001
2002static DECLCALLBACK(int) buslogicDeviceSCSIRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest, int rcCompletion)
2003{
2004 int rc;
2005 PBUSLOGICTASKSTATE pTaskState = (PBUSLOGICTASKSTATE)pSCSIRequest->pvUser;
2006 PBUSLOGICDEVICE pBusLogicDevice = pTaskState->CTX_SUFF(pTargetDevice);
2007 PBUSLOGIC pBusLogic = pBusLogicDevice->CTX_SUFF(pBusLogic);
2008
2009 LogFlowFunc(("before decrement %u\n", pBusLogicDevice->cOutstandingRequests));
2010 ASMAtomicDecU32(&pBusLogicDevice->cOutstandingRequests);
2011 LogFlowFunc(("after decrement %u\n", pBusLogicDevice->cOutstandingRequests));
2012
2013 if (pTaskState->fBIOS)
2014 {
2015 rc = vboxscsiRequestFinished(&pBusLogic->VBoxSCSI, pSCSIRequest);
2016 AssertMsgRC(rc, ("Finishing BIOS SCSI request failed rc=%Rrc\n", rc));
2017 }
2018 else
2019 {
2020 buslogicDataBufferFree(pTaskState);
2021
2022 if (pTaskState->pbSenseBuffer)
2023 buslogicSenseBufferFree(pTaskState, (rcCompletion != SCSI_STATUS_OK));
2024
2025 buslogicSendIncomingMailbox(pBusLogic, pTaskState,
2026 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_CMD_COMPLETED,
2027 BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_OPERATION_GOOD,
2028 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITHOUT_ERROR);
2029 }
2030
2031 /* Add task to the cache. */
2032 RTMemCacheFree(pBusLogic->hTaskCache, pTaskState);
2033
2034 if (pBusLogicDevice->cOutstandingRequests == 0 && pBusLogic->fSignalIdle)
2035 PDMDevHlpAsyncNotificationCompleted(pBusLogic->pDevInsR3);
2036
2037 return VINF_SUCCESS;
2038}
2039
2040/**
2041 * Read mailbox from the guest and execute command.
2042 *
2043 * @returns VBox status code.
2044 * @param pBusLogic Pointer to the BusLogic instance data.
2045 */
2046static int buslogicProcessMailboxNext(PBUSLOGIC pBusLogic)
2047{
2048 PBUSLOGICTASKSTATE pTaskState = NULL;
2049 RTGCPHYS GCPhysAddrMailboxCurrent;
2050 int rc;
2051
2052 rc = RTMemCacheAllocEx(pBusLogic->hTaskCache, (void **)&pTaskState);
2053 AssertMsgReturn(RT_SUCCESS(rc) && (pTaskState != NULL), ("Failed to get task state from cache\n"), rc);
2054
2055 pTaskState->fBIOS = false;
2056
2057 if (!pBusLogic->fStrictRoundRobinMode)
2058 {
2059 /* Search for a filled mailbox. */
2060 do
2061 {
2062 /* Fetch mailbox from guest memory. */
2063 GCPhysAddrMailboxCurrent = pBusLogic->GCPhysAddrMailboxOutgoingBase + (pBusLogic->uMailboxOutgoingPositionCurrent * sizeof(Mailbox));
2064
2065 PDMDevHlpPhysRead(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxCurrent,
2066 &pTaskState->MailboxGuest, sizeof(Mailbox));
2067
2068 pBusLogic->uMailboxOutgoingPositionCurrent++;
2069
2070 /* Check if we reached the end and start from the beginning if so. */
2071 if (pBusLogic->uMailboxOutgoingPositionCurrent >= pBusLogic->cMailbox)
2072 pBusLogic->uMailboxOutgoingPositionCurrent = 0;
2073 } while (pTaskState->MailboxGuest.u.out.uActionCode == BUSLOGIC_MAILBOX_OUTGOING_ACTION_FREE);
2074 }
2075 else
2076 {
2077 /* Fetch mailbox from guest memory. */
2078 GCPhysAddrMailboxCurrent = pBusLogic->GCPhysAddrMailboxOutgoingBase + (pBusLogic->uMailboxOutgoingPositionCurrent * sizeof(Mailbox));
2079
2080 PDMDevHlpPhysRead(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxCurrent,
2081 &pTaskState->MailboxGuest, sizeof(Mailbox));
2082 }
2083
2084#ifdef DEBUG
2085 buslogicDumpMailboxInfo(&pTaskState->MailboxGuest, true);
2086#endif
2087
2088 if (pTaskState->MailboxGuest.u.out.uActionCode == BUSLOGIC_MAILBOX_OUTGOING_ACTION_START_COMMAND)
2089 {
2090 /* Fetch CCB now. */
2091 RTGCPHYS GCPhysAddrCCB = (RTGCPHYS)pTaskState->MailboxGuest.u32PhysAddrCCB;
2092 PDMDevHlpPhysRead(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrCCB,
2093 &pTaskState->CommandControlBlockGuest, sizeof(CommandControlBlock));
2094
2095 PBUSLOGICDEVICE pTargetDevice = &pBusLogic->aDeviceStates[pTaskState->CommandControlBlockGuest.uTargetId];
2096 pTaskState->CTX_SUFF(pTargetDevice) = pTargetDevice;
2097
2098#ifdef DEBUG
2099 buslogicDumpCCBInfo(&pTaskState->CommandControlBlockGuest);
2100#endif
2101
2102 /* Alloc required buffers. */
2103 rc = buslogicDataBufferAlloc(pTaskState);
2104 AssertMsgRC(rc, ("Alloc failed rc=%Rrc\n", rc));
2105
2106 if (pTaskState->CommandControlBlockGuest.cbSenseData)
2107 {
2108 rc = buslogicSenseBufferAlloc(pTaskState);
2109 AssertMsgRC(rc, ("Mapping sense buffer failed rc=%Rrc\n", rc));
2110 }
2111
2112 /* Check if device is present on bus. If not return error immediately and don't process this further. */
2113 if (!pBusLogic->aDeviceStates[pTaskState->CommandControlBlockGuest.uTargetId].fPresent)
2114 {
2115 buslogicDataBufferFree(pTaskState);
2116
2117 if (pTaskState->pbSenseBuffer)
2118 buslogicSenseBufferFree(pTaskState, true);
2119
2120 buslogicSendIncomingMailbox(pBusLogic, pTaskState,
2121 BUSLOGIC_MAILBOX_INCOMING_ADAPTER_STATUS_SCSI_SELECTION_TIMEOUT,
2122 BUSLOGIC_MAILBOX_INCOMING_DEVICE_STATUS_OPERATION_GOOD,
2123 BUSLOGIC_MAILBOX_INCOMING_COMPLETION_WITH_ERROR);
2124
2125 RTMemCacheFree(pBusLogic->hTaskCache, pTaskState);
2126 }
2127 else
2128 {
2129 /* Setup SCSI request. */
2130 pTaskState->PDMScsiRequest.uLogicalUnit = pTaskState->CommandControlBlockGuest.uLogicalUnit;
2131
2132 if (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_UNKNOWN)
2133 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_UNKNOWN;
2134 else if (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_IN)
2135 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_FROM_DEVICE;
2136 else if (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_OUT)
2137 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_TO_DEVICE;
2138 else if (pTaskState->CommandControlBlockGuest.uDataDirection == BUSLOGIC_CCB_DIRECTION_NO_DATA)
2139 pTaskState->PDMScsiRequest.uDataDirection = PDMSCSIREQUESTTXDIR_NONE;
2140 else
2141 AssertMsgFailed(("Invalid data direction type %d\n", pTaskState->CommandControlBlockGuest.uDataDirection));
2142
2143 pTaskState->PDMScsiRequest.cbCDB = pTaskState->CommandControlBlockGuest.cbCDB;
2144 pTaskState->PDMScsiRequest.pbCDB = pTaskState->CommandControlBlockGuest.aCDB;
2145 if (pTaskState->DataSeg.cbSeg)
2146 {
2147 pTaskState->PDMScsiRequest.cbScatterGather = pTaskState->DataSeg.cbSeg;
2148 pTaskState->PDMScsiRequest.cScatterGatherEntries = 1;
2149 pTaskState->PDMScsiRequest.paScatterGatherHead = &pTaskState->DataSeg;
2150 }
2151 else
2152 {
2153 pTaskState->PDMScsiRequest.cbScatterGather = 0;
2154 pTaskState->PDMScsiRequest.cScatterGatherEntries = 0;
2155 pTaskState->PDMScsiRequest.paScatterGatherHead = NULL;
2156 }
2157 pTaskState->PDMScsiRequest.cbSenseBuffer = pTaskState->CommandControlBlockGuest.cbSenseData;
2158 pTaskState->PDMScsiRequest.pbSenseBuffer = pTaskState->pbSenseBuffer;
2159 pTaskState->PDMScsiRequest.pvUser = pTaskState;
2160
2161 LogFlowFunc(("before increment %u\n", pTargetDevice->cOutstandingRequests));
2162 ASMAtomicIncU32(&pTargetDevice->cOutstandingRequests);
2163 LogFlowFunc(("after increment %u\n", pTargetDevice->cOutstandingRequests));
2164 rc = pTargetDevice->pDrvSCSIConnector->pfnSCSIRequestSend(pTargetDevice->pDrvSCSIConnector, &pTaskState->PDMScsiRequest);
2165 AssertMsgRC(rc, ("Sending request to SCSI layer failed rc=%Rrc\n", rc));
2166 }
2167 }
2168 else if (pTaskState->MailboxGuest.u.out.uActionCode == BUSLOGIC_MAILBOX_OUTGOING_ACTION_ABORT_COMMAND)
2169 {
2170 AssertMsgFailed(("Not implemented yet\n"));
2171 }
2172 else
2173 AssertMsgFailed(("Invalid outgoing mailbox action code %u\n", pTaskState->MailboxGuest.u.out.uActionCode));
2174
2175 /* We got the mailbox, mark it as free in the guest. */
2176 pTaskState->MailboxGuest.u.out.uActionCode = BUSLOGIC_MAILBOX_OUTGOING_ACTION_FREE;
2177 PDMDevHlpPhysWrite(pBusLogic->CTX_SUFF(pDevIns), GCPhysAddrMailboxCurrent, &pTaskState->MailboxGuest, sizeof(Mailbox));
2178
2179 if (pBusLogic->fStrictRoundRobinMode)
2180 {
2181 pBusLogic->uMailboxOutgoingPositionCurrent++;
2182
2183 /* Check if we reached the end and start from the beginning if so. */
2184 if (pBusLogic->uMailboxOutgoingPositionCurrent >= pBusLogic->cMailbox)
2185 pBusLogic->uMailboxOutgoingPositionCurrent = 0;
2186 }
2187
2188 return rc;
2189}
2190
2191/**
2192 * Transmit queue consumer
2193 * Queue a new async task.
2194 *
2195 * @returns Success indicator.
2196 * If false the item will not be removed and the flushing will stop.
2197 * @param pDevIns The device instance.
2198 * @param pItem The item to consume. Upon return this item will be freed.
2199 */
2200static DECLCALLBACK(bool) buslogicNotifyQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
2201{
2202 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2203
2204 AssertMsg(pBusLogic->cMailboxesReady > 0, ("Got notification without any mailboxes ready\n"));
2205
2206 /* Reset notification send flag now. */
2207 ASMAtomicXchgBool(&pBusLogic->fNotificationSend, false);
2208
2209 /* Process mailboxes. */
2210 do
2211 {
2212 int rc;
2213
2214 rc = buslogicProcessMailboxNext(pBusLogic);
2215 AssertMsgRC(rc, ("Processing mailbox failed rc=%Rrc\n", rc));
2216 } while (ASMAtomicDecU32(&pBusLogic->cMailboxesReady) > 0);
2217
2218 return true;
2219}
2220
2221static DECLCALLBACK(int) buslogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2222{
2223 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2224
2225 /* Save the device config. */
2226 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aDeviceStates); i++)
2227 SSMR3PutBool(pSSM, pThis->aDeviceStates[i].fPresent);
2228
2229 return VINF_SSM_DONT_CALL_AGAIN;
2230}
2231
2232static DECLCALLBACK(int) buslogicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2233{
2234 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2235
2236 /* Every device first. */
2237 for (unsigned i = 0; i < RT_ELEMENTS(pBusLogic->aDeviceStates); i++)
2238 {
2239 PBUSLOGICDEVICE pDevice = &pBusLogic->aDeviceStates[i];
2240
2241 AssertMsg(!pDevice->cOutstandingRequests,
2242 ("There are still outstanding requests on this device\n"));
2243 SSMR3PutBool(pSSM, pDevice->fPresent);
2244 SSMR3PutU32(pSSM, pDevice->cOutstandingRequests);
2245 }
2246 /* Now the main device state. */
2247 SSMR3PutU8 (pSSM, pBusLogic->regStatus);
2248 SSMR3PutU8 (pSSM, pBusLogic->regInterrupt);
2249 SSMR3PutU8 (pSSM, pBusLogic->regGeometry);
2250 SSMR3PutMem (pSSM, &pBusLogic->LocalRam, sizeof(pBusLogic->LocalRam));
2251 SSMR3PutU8 (pSSM, pBusLogic->uOperationCode);
2252 SSMR3PutMem (pSSM, &pBusLogic->aCommandBuffer, sizeof(pBusLogic->aCommandBuffer));
2253 SSMR3PutU8 (pSSM, pBusLogic->iParameter);
2254 SSMR3PutU8 (pSSM, pBusLogic->cbCommandParametersLeft);
2255 SSMR3PutBool (pSSM, pBusLogic->fUseLocalRam);
2256 SSMR3PutMem (pSSM, pBusLogic->aReplyBuffer, sizeof(pBusLogic->aReplyBuffer));
2257 SSMR3PutU8 (pSSM, pBusLogic->iReply);
2258 SSMR3PutU8 (pSSM, pBusLogic->cbReplyParametersLeft);
2259 SSMR3PutBool (pSSM, pBusLogic->fIRQEnabled);
2260 SSMR3PutBool (pSSM, pBusLogic->fISAEnabled);
2261 SSMR3PutU32 (pSSM, pBusLogic->cMailbox);
2262 SSMR3PutGCPhys(pSSM, pBusLogic->GCPhysAddrMailboxOutgoingBase);
2263 SSMR3PutU32 (pSSM, pBusLogic->uMailboxOutgoingPositionCurrent);
2264 SSMR3PutU32 (pSSM, pBusLogic->cMailboxesReady);
2265 SSMR3PutBool (pSSM, pBusLogic->fNotificationSend);
2266 SSMR3PutGCPhys(pSSM, pBusLogic->GCPhysAddrMailboxIncomingBase);
2267 SSMR3PutU32 (pSSM, pBusLogic->uMailboxIncomingPositionCurrent);
2268 SSMR3PutBool (pSSM, pBusLogic->fStrictRoundRobinMode);
2269 SSMR3PutBool (pSSM, pBusLogic->fExtendedLunCCBFormat);
2270 /* Now the data for the BIOS interface. */
2271 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.regIdentify);
2272 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.uTargetDevice);
2273 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.uTxDir);
2274 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.cbCDB);
2275 SSMR3PutMem (pSSM, pBusLogic->VBoxSCSI.aCDB, sizeof(pBusLogic->VBoxSCSI.aCDB));
2276 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.iCDB);
2277 SSMR3PutU32 (pSSM, pBusLogic->VBoxSCSI.cbBuf);
2278 SSMR3PutU32 (pSSM, pBusLogic->VBoxSCSI.iBuf);
2279 SSMR3PutBool (pSSM, pBusLogic->VBoxSCSI.fBusy);
2280 SSMR3PutU8 (pSSM, pBusLogic->VBoxSCSI.enmState);
2281 if (pBusLogic->VBoxSCSI.cbCDB)
2282 SSMR3PutMem(pSSM, pBusLogic->VBoxSCSI.pBuf, pBusLogic->VBoxSCSI.cbBuf);
2283
2284 return SSMR3PutU32(pSSM, ~0);
2285}
2286
2287static DECLCALLBACK(int) buslogicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2288{
2289 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2290 int rc;
2291
2292 /* We support saved states only from this and older versions. */
2293 if (uVersion > BUSLOGIC_SAVED_STATE_MINOR_VERSION)
2294 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2295
2296 /* Every device first. */
2297 for (unsigned i = 0; i < RT_ELEMENTS(pBusLogic->aDeviceStates); i++)
2298 {
2299 PBUSLOGICDEVICE pDevice = &pBusLogic->aDeviceStates[i];
2300
2301 AssertMsg(!pDevice->cOutstandingRequests,
2302 ("There are still outstanding requests on this device\n"));
2303 bool fPresent;
2304 rc = SSMR3GetBool(pSSM, &fPresent);
2305 AssertRCReturn(rc, rc);
2306 if (pDevice->fPresent != fPresent)
2307 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Target %u config mismatch: config=%RTbool state=%RTbool"), i, pDevice->fPresent, fPresent);
2308
2309 if (uPass == SSM_PASS_FINAL)
2310 SSMR3GetU32(pSSM, (uint32_t *)&pDevice->cOutstandingRequests);
2311 }
2312
2313 if (uPass != SSM_PASS_FINAL)
2314 return VINF_SUCCESS;
2315
2316 /* Now the main device state. */
2317 SSMR3GetU8 (pSSM, (uint8_t *)&pBusLogic->regStatus);
2318 SSMR3GetU8 (pSSM, (uint8_t *)&pBusLogic->regInterrupt);
2319 SSMR3GetU8 (pSSM, (uint8_t *)&pBusLogic->regGeometry);
2320 SSMR3GetMem (pSSM, &pBusLogic->LocalRam, sizeof(pBusLogic->LocalRam));
2321 SSMR3GetU8 (pSSM, &pBusLogic->uOperationCode);
2322 SSMR3GetMem (pSSM, &pBusLogic->aCommandBuffer, sizeof(pBusLogic->aCommandBuffer));
2323 SSMR3GetU8 (pSSM, &pBusLogic->iParameter);
2324 SSMR3GetU8 (pSSM, &pBusLogic->cbCommandParametersLeft);
2325 SSMR3GetBool (pSSM, &pBusLogic->fUseLocalRam);
2326 SSMR3GetMem (pSSM, pBusLogic->aReplyBuffer, sizeof(pBusLogic->aReplyBuffer));
2327 SSMR3GetU8 (pSSM, &pBusLogic->iReply);
2328 SSMR3GetU8 (pSSM, &pBusLogic->cbReplyParametersLeft);
2329 SSMR3GetBool (pSSM, &pBusLogic->fIRQEnabled);
2330 SSMR3GetBool (pSSM, &pBusLogic->fISAEnabled);
2331 SSMR3GetU32 (pSSM, &pBusLogic->cMailbox);
2332 SSMR3GetGCPhys(pSSM, &pBusLogic->GCPhysAddrMailboxOutgoingBase);
2333 SSMR3GetU32 (pSSM, &pBusLogic->uMailboxOutgoingPositionCurrent);
2334 SSMR3GetU32 (pSSM, (uint32_t *)&pBusLogic->cMailboxesReady);
2335 SSMR3GetBool (pSSM, (bool *)&pBusLogic->fNotificationSend);
2336 SSMR3GetGCPhys(pSSM, &pBusLogic->GCPhysAddrMailboxIncomingBase);
2337 SSMR3GetU32 (pSSM, &pBusLogic->uMailboxIncomingPositionCurrent);
2338 SSMR3GetBool (pSSM, &pBusLogic->fStrictRoundRobinMode);
2339 SSMR3GetBool (pSSM, &pBusLogic->fExtendedLunCCBFormat);
2340 /* Now the data for the BIOS interface. */
2341 SSMR3GetU8 (pSSM, &pBusLogic->VBoxSCSI.regIdentify);
2342 SSMR3GetU8 (pSSM, &pBusLogic->VBoxSCSI.uTargetDevice);
2343 SSMR3GetU8 (pSSM, &pBusLogic->VBoxSCSI.uTxDir);
2344 SSMR3GetU8 (pSSM, &pBusLogic->VBoxSCSI.cbCDB);
2345 SSMR3GetMem (pSSM, pBusLogic->VBoxSCSI.aCDB, sizeof(pBusLogic->VBoxSCSI.aCDB));
2346 SSMR3GetU8 (pSSM, &pBusLogic->VBoxSCSI.iCDB);
2347 SSMR3GetU32 (pSSM, &pBusLogic->VBoxSCSI.cbBuf);
2348 SSMR3GetU32 (pSSM, &pBusLogic->VBoxSCSI.iBuf);
2349 SSMR3GetBool(pSSM, (bool *)&pBusLogic->VBoxSCSI.fBusy);
2350 SSMR3GetU8 (pSSM, (uint8_t *)&pBusLogic->VBoxSCSI.enmState);
2351 if (pBusLogic->VBoxSCSI.cbCDB)
2352 {
2353 pBusLogic->VBoxSCSI.pBuf = (uint8_t *)RTMemAllocZ(pBusLogic->VBoxSCSI.cbCDB);
2354 if (!pBusLogic->VBoxSCSI.pBuf)
2355 {
2356 LogRel(("BusLogic: Out of memory during restore.\n"));
2357 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
2358 N_("BusLogic: Out of memory during restore\n"));
2359 }
2360 SSMR3GetMem(pSSM, pBusLogic->VBoxSCSI.pBuf, pBusLogic->VBoxSCSI.cbBuf);
2361 }
2362
2363 uint32_t u32;
2364 rc = SSMR3GetU32(pSSM, &u32);
2365 if (RT_FAILURE(rc))
2366 return rc;
2367 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2368
2369 return VINF_SUCCESS;
2370}
2371
2372/**
2373 * Gets the pointer to the status LED of a device - called from the SCSi driver.
2374 *
2375 * @returns VBox status code.
2376 * @param pInterface Pointer to the interface structure containing the called function pointer.
2377 * @param iLUN The unit which status LED we desire. Always 0 here as the driver
2378 * doesn't know about other LUN's.
2379 * @param ppLed Where to store the LED pointer.
2380 */
2381static DECLCALLBACK(int) buslogicDeviceQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2382{
2383 PBUSLOGICDEVICE pDevice = PDMILEDPORTS_2_PBUSLOGICDEVICE(pInterface);
2384 if (iLUN == 0)
2385 {
2386 *ppLed = &pDevice->Led;
2387 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2388 return VINF_SUCCESS;
2389 }
2390 return VERR_PDM_LUN_NOT_FOUND;
2391}
2392
2393/**
2394 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2395 */
2396static DECLCALLBACK(void *) buslogicDeviceQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2397{
2398 PBUSLOGICDEVICE pDevice = PDMIBASE_2_PBUSLOGICDEVICE(pInterface);
2399 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevice->IBase);
2400 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pDevice->ISCSIPort);
2401 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pDevice->ILed);
2402 return NULL;
2403}
2404
2405/**
2406 * Gets the pointer to the status LED of a unit.
2407 *
2408 * @returns VBox status code.
2409 * @param pInterface Pointer to the interface structure containing the called function pointer.
2410 * @param iLUN The unit which status LED we desire.
2411 * @param ppLed Where to store the LED pointer.
2412 */
2413static DECLCALLBACK(int) buslogicStatusQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2414{
2415 PBUSLOGIC pBusLogic = PDMILEDPORTS_2_PBUSLOGIC(pInterface);
2416 if (iLUN < BUSLOGIC_MAX_DEVICES)
2417 {
2418 *ppLed = &pBusLogic->aDeviceStates[iLUN].Led;
2419 Assert((*ppLed)->u32Magic == PDMLED_MAGIC);
2420 return VINF_SUCCESS;
2421 }
2422 return VERR_PDM_LUN_NOT_FOUND;
2423}
2424
2425/**
2426 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2427 */
2428static DECLCALLBACK(void *) buslogicStatusQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2429{
2430 PBUSLOGIC pThis = PDMIBASE_2_PBUSLOGIC(pInterface);
2431 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2432 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->ILeds);
2433 return NULL;
2434}
2435
2436/* -=-=-=-=- Helper -=-=-=-=- */
2437
2438 /**
2439 * Checks if all asynchronous I/O is finished.
2440 *
2441 * Used by lsilogicReset, lsilogicSuspend and lsilogicPowerOff.
2442 *
2443 * @returns true if quiesced, false if busy.
2444 * @param pDevIns The device instance.
2445 */
2446static bool buslogicR3AllAsyncIOIsFinished(PPDMDEVINS pDevIns)
2447{
2448 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2449
2450 for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aDeviceStates); i++)
2451 {
2452 PBUSLOGICDEVICE pThisDevice = &pThis->aDeviceStates[i];
2453 if (pThisDevice->pDrvBase)
2454 {
2455 if (pThisDevice->cOutstandingRequests != 0)
2456 return false;
2457 }
2458 }
2459
2460 return true;
2461}
2462
2463/**
2464 * Callback employed by lsilogicR3Suspend and lsilogicR3PowerOff..
2465 *
2466 * @returns true if we've quiesced, false if we're still working.
2467 * @param pDevIns The device instance.
2468 */
2469static DECLCALLBACK(bool) buslogicR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
2470{
2471 if (!buslogicR3AllAsyncIOIsFinished(pDevIns))
2472 return false;
2473
2474 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2475 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2476 return true;
2477}
2478
2479/**
2480 * Common worker for ahciR3Suspend and ahciR3PowerOff.
2481 */
2482static void buslogicR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
2483{
2484 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2485
2486 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
2487 if (!buslogicR3AllAsyncIOIsFinished(pDevIns))
2488 PDMDevHlpSetAsyncNotification(pDevIns, buslogicR3IsAsyncSuspendOrPowerOffDone);
2489 else
2490 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2491}
2492
2493/**
2494 * Suspend notification.
2495 *
2496 * @param pDevIns The device instance data.
2497 */
2498static DECLCALLBACK(void) buslogicSuspend(PPDMDEVINS pDevIns)
2499{
2500 Log(("buslogicSuspend\n"));
2501 buslogicR3SuspendOrPowerOff(pDevIns);
2502}
2503
2504/**
2505 * Detach notification.
2506 *
2507 * One harddisk at one port has been unplugged.
2508 * The VM is suspended at this point.
2509 *
2510 * @param pDevIns The device instance.
2511 * @param iLUN The logical unit which is being detached.
2512 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2513 */
2514static DECLCALLBACK(void) buslogicDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2515{
2516 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2517 PBUSLOGICDEVICE pDevice = &pThis->aDeviceStates[iLUN];
2518
2519 Log(("%s:\n", __FUNCTION__));
2520
2521 AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2522 ("BusLogic: Device does not support hotplugging\n"));
2523
2524 /*
2525 * Zero some important members.
2526 */
2527 pDevice->pDrvBase = NULL;
2528 pDevice->fPresent = false;
2529 pDevice->pDrvSCSIConnector = NULL;
2530}
2531
2532/**
2533 * Attach command.
2534 *
2535 * This is called when we change block driver.
2536 *
2537 * @returns VBox status code.
2538 * @param pDevIns The device instance.
2539 * @param iLUN The logical unit which is being detached.
2540 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2541 */
2542static DECLCALLBACK(int) buslogicAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2543{
2544 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2545 PBUSLOGICDEVICE pDevice = &pThis->aDeviceStates[iLUN];
2546 int rc;
2547
2548 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2549 ("BusLogic: Device does not support hotplugging\n"),
2550 VERR_INVALID_PARAMETER);
2551
2552 /* the usual paranoia */
2553 AssertRelease(!pDevice->pDrvBase);
2554 AssertRelease(!pDevice->pDrvSCSIConnector);
2555 Assert(pDevice->iLUN == iLUN);
2556
2557 /*
2558 * Try attach the block device and get the interfaces,
2559 * required as well as optional.
2560 */
2561 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, NULL);
2562 if (RT_SUCCESS(rc))
2563 {
2564 /* Get SCSI connector interface. */
2565 pDevice->pDrvSCSIConnector = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMISCSICONNECTOR);
2566 AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
2567 pDevice->fPresent = true;
2568 }
2569 else
2570 AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pDevice->iLUN, rc));
2571
2572 if (RT_FAILURE(rc))
2573 {
2574 pDevice->pDrvBase = NULL;
2575 pDevice->pDrvSCSIConnector = NULL;
2576 }
2577 return rc;
2578}
2579
2580/**
2581 * Callback employed by buslogicR3Reset.
2582 *
2583 * @returns true if we've quiesced, false if we're still working.
2584 * @param pDevIns The device instance.
2585 */
2586static DECLCALLBACK(bool) buslogicR3IsAsyncResetDone(PPDMDEVINS pDevIns)
2587{
2588 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2589
2590 if (!buslogicR3AllAsyncIOIsFinished(pDevIns))
2591 return false;
2592 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2593
2594 buslogicHwReset(pThis);
2595 return true;
2596}
2597
2598/**
2599 * @copydoc FNPDMDEVRESET
2600 */
2601static DECLCALLBACK(void) buslogicReset(PPDMDEVINS pDevIns)
2602{
2603 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2604
2605 ASMAtomicWriteBool(&pThis->fSignalIdle, true);
2606 if (!buslogicR3AllAsyncIOIsFinished(pDevIns))
2607 PDMDevHlpSetAsyncNotification(pDevIns, buslogicR3IsAsyncResetDone);
2608 else
2609 {
2610 ASMAtomicWriteBool(&pThis->fSignalIdle, false);
2611 buslogicHwReset(pThis);
2612 }
2613}
2614
2615static DECLCALLBACK(void) buslogicRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2616{
2617 uint32_t i;
2618 PBUSLOGIC pBusLogic = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2619
2620 pBusLogic->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2621 pBusLogic->pNotifierQueueRC = PDMQueueRCPtr(pBusLogic->pNotifierQueueR3);
2622
2623 for (i = 0; i < BUSLOGIC_MAX_DEVICES; i++)
2624 {
2625 PBUSLOGICDEVICE pDevice = &pBusLogic->aDeviceStates[i];
2626
2627 pDevice->pBusLogicRC = PDMINS_2_DATA_RCPTR(pDevIns);
2628 }
2629
2630}
2631
2632/**
2633 * Poweroff notification.
2634 *
2635 * @param pDevIns Pointer to the device instance
2636 */
2637static DECLCALLBACK(void) buslogicPowerOff(PPDMDEVINS pDevIns)
2638{
2639 Log(("buslogicPowerOff\n"));
2640 buslogicR3SuspendOrPowerOff(pDevIns);
2641}
2642
2643/**
2644 * Destroy a driver instance.
2645 *
2646 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
2647 * resources can be freed correctly.
2648 *
2649 * @param pDevIns The device instance data.
2650 */
2651static DECLCALLBACK(int) buslogicDestruct(PPDMDEVINS pDevIns)
2652{
2653 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2654 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
2655
2656 PDMR3CritSectDelete(&pThis->CritSectIntr);
2657
2658 int rc = RTMemCacheDestroy(pThis->hTaskCache);
2659 AssertMsgRC(rc, ("Destroying task cache failed rc=%Rrc\n", rc));
2660
2661 return rc;
2662}
2663
2664/**
2665 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2666 */
2667static DECLCALLBACK(int) buslogicConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2668{
2669 PBUSLOGIC pThis = PDMINS_2_DATA(pDevIns, PBUSLOGIC);
2670 int rc = VINF_SUCCESS;
2671 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2672
2673 /*
2674 * Validate and read configuration.
2675 */
2676 if (!CFGMR3AreValuesValid(pCfg,
2677 "GCEnabled\0"
2678 "R0Enabled\0"))
2679 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2680 N_("BusLogic configuration error: unknown option specified"));
2681
2682 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
2683 if (RT_FAILURE(rc))
2684 return PDMDEV_SET_ERROR(pDevIns, rc,
2685 N_("BusLogic configuration error: failed to read GCEnabled as boolean"));
2686 Log(("%s: fGCEnabled=%d\n", __FUNCTION__, pThis->fGCEnabled));
2687
2688 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
2689 if (RT_FAILURE(rc))
2690 return PDMDEV_SET_ERROR(pDevIns, rc,
2691 N_("BusLogic configuration error: failed to read R0Enabled as boolean"));
2692 Log(("%s: fR0Enabled=%d\n", __FUNCTION__, pThis->fR0Enabled));
2693
2694
2695 pThis->pDevInsR3 = pDevIns;
2696 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2697 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2698 pThis->IBase.pfnQueryInterface = buslogicStatusQueryInterface;
2699 pThis->ILeds.pfnQueryStatusLed = buslogicStatusQueryStatusLed;
2700
2701 PCIDevSetVendorId (&pThis->dev, 0x104b); /* BusLogic */
2702 PCIDevSetDeviceId (&pThis->dev, 0x1040); /* BT-958 */
2703 PCIDevSetCommand (&pThis->dev, 0x0003);
2704 PCIDevSetRevisionId (&pThis->dev, 0x01);
2705 PCIDevSetClassProg (&pThis->dev, 0x00); /* SCSI */
2706 PCIDevSetClassSub (&pThis->dev, 0x00); /* SCSI */
2707 PCIDevSetClassBase (&pThis->dev, 0x01); /* Mass storage */
2708 PCIDevSetBaseAddress (&pThis->dev, 0, true /*IO*/, false /*Pref*/, false /*64-bit*/, 0x00000000);
2709 PCIDevSetBaseAddress (&pThis->dev, 1, false /*IO*/, false /*Pref*/, false /*64-bit*/, 0x00000000);
2710 PCIDevSetSubSystemVendorId(&pThis->dev, 0x104b);
2711 PCIDevSetSubSystemId (&pThis->dev, 0x1040);
2712 PCIDevSetInterruptLine (&pThis->dev, 0x00);
2713 PCIDevSetInterruptPin (&pThis->dev, 0x01);
2714
2715 /*
2716 * Register the PCI device, it's I/O regions.
2717 */
2718 rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev);
2719 if (RT_FAILURE(rc))
2720 return rc;
2721
2722 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 32, PCI_ADDRESS_SPACE_IO, buslogicMMIOMap);
2723 if (RT_FAILURE(rc))
2724 return rc;
2725
2726 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 32, PCI_ADDRESS_SPACE_MEM, buslogicMMIOMap);
2727 if (RT_FAILURE(rc))
2728 return rc;
2729
2730 /* Register I/O port space in ISA region for BIOS access. */
2731 rc = PDMDevHlpIOPortRegister(pDevIns, BUSLOGIC_ISA_IO_PORT, 3, NULL,
2732 buslogicIsaIOPortWrite, buslogicIsaIOPortRead,
2733 buslogicIsaIOPortWriteStr, buslogicIsaIOPortReadStr,
2734 "BusLogic BIOS");
2735 if (RT_FAILURE(rc))
2736 return PDMDEV_SET_ERROR(pDevIns, rc, N_("BusLogic cannot register legacy I/O handlers"));
2737
2738 /* Initialize task cache. */
2739 rc = RTMemCacheCreate(&pThis->hTaskCache, sizeof(BUSLOGICTASKSTATE), 0, UINT32_MAX,
2740 NULL, NULL, NULL, 0);
2741 if (RT_FAILURE(rc))
2742 return PDMDEV_SET_ERROR(pDevIns, rc,
2743 N_("BusLogic: Failed to initialize task cache\n"));
2744
2745 /* Intialize task queue. */
2746 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 5, 0,
2747 buslogicNotifyQueueConsumer, true, "BugLogicTask", &pThis->pNotifierQueueR3);
2748 if (RT_FAILURE(rc))
2749 return rc;
2750 pThis->pNotifierQueueR0 = PDMQueueR0Ptr(pThis->pNotifierQueueR3);
2751 pThis->pNotifierQueueRC = PDMQueueRCPtr(pThis->pNotifierQueueR3);
2752
2753 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSectIntr, RT_SRC_POS, "BusLogic-Intr");
2754 if (RT_FAILURE(rc))
2755 return PDMDEV_SET_ERROR(pDevIns, rc,
2756 N_("BusLogic: cannot create critical section"));
2757
2758 /* Initialize per device state. */
2759 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aDeviceStates); i++)
2760 {
2761 char szName[24];
2762 PBUSLOGICDEVICE pDevice = &pThis->aDeviceStates[i];
2763
2764 RTStrPrintf(szName, sizeof(szName), "Device%d", i);
2765
2766 /* Initialize static parts of the device. */
2767 pDevice->iLUN = i;
2768 pDevice->pBusLogicR3 = pThis;
2769 pDevice->pBusLogicR0 = PDMINS_2_DATA_R0PTR(pDevIns);
2770 pDevice->pBusLogicRC = PDMINS_2_DATA_RCPTR(pDevIns);
2771 pDevice->Led.u32Magic = PDMLED_MAGIC;
2772 pDevice->IBase.pfnQueryInterface = buslogicDeviceQueryInterface;
2773 pDevice->ISCSIPort.pfnSCSIRequestCompleted = buslogicDeviceSCSIRequestCompleted;
2774 pDevice->ILed.pfnQueryStatusLed = buslogicDeviceQueryStatusLed;
2775
2776 /* Attach SCSI driver. */
2777 rc = PDMDevHlpDriverAttach(pDevIns, pDevice->iLUN, &pDevice->IBase, &pDevice->pDrvBase, szName);
2778 if (RT_SUCCESS(rc))
2779 {
2780 /* Get SCSI connector interface. */
2781 pDevice->pDrvSCSIConnector = PDMIBASE_QUERY_INTERFACE(pDevice->pDrvBase, PDMISCSICONNECTOR);
2782 AssertMsgReturn(pDevice->pDrvSCSIConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
2783
2784 pDevice->fPresent = true;
2785 }
2786 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2787 {
2788 pDevice->pDrvBase = NULL;
2789 pDevice->fPresent = false;
2790 rc = VINF_SUCCESS;
2791 Log(("BusLogic: no driver attached to device %s\n", szName));
2792 }
2793 else
2794 {
2795 AssertLogRelMsgFailed(("BusLogic: Failed to attach %s\n", szName));
2796 return rc;
2797 }
2798 }
2799
2800 /*
2801 * Attach status driver (optional).
2802 */
2803 PPDMIBASE pBase;
2804 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
2805 if (RT_SUCCESS(rc))
2806 pThis->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
2807 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2808 {
2809 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
2810 return PDMDEV_SET_ERROR(pDevIns, rc, N_("BusLogic cannot attach to status driver"));
2811 }
2812
2813 rc = PDMDevHlpSSMRegister3(pDevIns, BUSLOGIC_SAVED_STATE_MINOR_VERSION, sizeof(*pThis),
2814 buslogicLiveExec, buslogicSaveExec, buslogicLoadExec);
2815 if (RT_FAILURE(rc))
2816 return PDMDEV_SET_ERROR(pDevIns, rc, N_("BusLogic cannot register save state handlers"));
2817
2818 rc = buslogicHwReset(pThis);
2819 AssertMsgRC(rc, ("hardware reset of BusLogic host adapter failed rc=%Rrc\n", rc));
2820
2821 return rc;
2822}
2823
2824/**
2825 * The device registration structure.
2826 */
2827const PDMDEVREG g_DeviceBusLogic =
2828{
2829 /* u32Version */
2830 PDM_DEVREG_VERSION,
2831 /* szName */
2832 "buslogic",
2833 /* szRCMod */
2834 "VBoxDDGC.gc",
2835 /* szR0Mod */
2836 "VBoxDDR0.r0",
2837 /* pszDescription */
2838 "BusLogic BT-958 SCSI host adapter.\n",
2839 /* fFlags */
2840 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0 |
2841 PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION,
2842 /* fClass */
2843 PDM_DEVREG_CLASS_STORAGE,
2844 /* cMaxInstances */
2845 ~0,
2846 /* cbInstance */
2847 sizeof(BUSLOGIC),
2848 /* pfnConstruct */
2849 buslogicConstruct,
2850 /* pfnDestruct */
2851 buslogicDestruct,
2852 /* pfnRelocate */
2853 buslogicRelocate,
2854 /* pfnIOCtl */
2855 NULL,
2856 /* pfnPowerOn */
2857 NULL,
2858 /* pfnReset */
2859 buslogicReset,
2860 /* pfnSuspend */
2861 buslogicSuspend,
2862 /* pfnResume */
2863 NULL,
2864 /* pfnAttach */
2865 buslogicAttach,
2866 /* pfnDetach */
2867 buslogicDetach,
2868 /* pfnQueryInterface. */
2869 NULL,
2870 /* pfnInitComplete */
2871 NULL,
2872 /* pfnPowerOff */
2873 buslogicPowerOff,
2874 /* pfnSoftReset */
2875 NULL,
2876 /* u32VersionEnd */
2877 PDM_DEVREG_VERSION
2878};
2879
2880#endif /* IN_RING3 */
2881#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2882
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