VirtualBox

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

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

BusLogic,SCSI: Don't propagate VINF_VD_ASYNC_IO_FINISHED to the caller

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