VirtualBox

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

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

DevBusLogic: Don't just restore the fPresent flag, check it! Save fPresent in the first live pass.

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