VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use