VirtualBox

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

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

BusLogic: Missing case

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