VirtualBox

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

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

BusLogic: Fix

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

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