VirtualBox

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

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

BusLogic: Make sure that there are no tasks pending during suspend

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