VirtualBox

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

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

BusLogic: Fix race leading to I/O hang

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

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