VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/buslogic.c@ 92290

Last change on this file since 92290 was 89364, checked in by vboxsync, 4 years ago

Devices/PC/BIOS: Remove the skip_b,skip_a mechanism as it is unused now making the device drivers lss complex, bugref:4841

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.7 KB
Line 
1/* $Id: buslogic.c 89364 2021-05-28 15:44:38Z vboxsync $ */
2/** @file
3 * BusLogic SCSI host adapter driver to boot from disks.
4 */
5
6/*
7 * Copyright (C) 2021 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#include <stdint.h>
19#include <string.h>
20#include "biosint.h"
21#include "ebda.h"
22#include "inlines.h"
23#include "pciutil.h"
24#include "vds.h"
25#include "scsi.h"
26
27//#define DEBUG_BUSLOGIC 1
28#if DEBUG_BUSLOGIC
29# define DBG_BUSLOGIC(...) BX_INFO(__VA_ARGS__)
30#else
31# define DBG_BUSLOGIC(...)
32#endif
33
34#define BUSLOGICCOMMAND_DISABLE_HOST_ADAPTER_INTERRUPT 0x25
35#define BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND 0x83
36
37
38#define RT_BIT(bit) (1 << (bit))
39
40/** Register offsets in the I/O port space. */
41#define BUSLOGIC_REGISTER_CONTROL 0 /**< Writeonly */
42/** Fields for the control register. */
43# define BL_CTRL_RSBUS RT_BIT(4) /* Reset SCSI Bus. */
44# define BL_CTRL_RINT RT_BIT(5) /* Reset Interrupt. */
45# define BL_CTRL_RSOFT RT_BIT(6) /* Soft Reset. */
46# define BL_CTRL_RHARD RT_BIT(7) /* Hard Reset. */
47
48#define BUSLOGIC_REGISTER_STATUS 0 /**< Readonly */
49/** Fields for the status register. */
50# define BL_STAT_CMDINV RT_BIT(0) /* Command Invalid. */
51# define BL_STAT_DIRRDY RT_BIT(2) /* Data In Register Ready. */
52# define BL_STAT_CPRBSY RT_BIT(3) /* Command/Parameter Out Register Busy. */
53# define BL_STAT_HARDY RT_BIT(4) /* Host Adapter Ready. */
54# define BL_STAT_INREQ RT_BIT(5) /* Initialization Required. */
55# define BL_STAT_DFAIL RT_BIT(6) /* Diagnostic Failure. */
56# define BL_STAT_DACT RT_BIT(7) /* Diagnistic Active. */
57
58#define BUSLOGIC_REGISTER_COMMAND 1 /**< Writeonly */
59#define BUSLOGIC_REGISTER_DATAIN 1 /**< Readonly */
60#define BUSLOGIC_REGISTER_INTERRUPT 2 /**< Readonly */
61/** Fields for the interrupt register. */
62# define BL_INTR_IMBL RT_BIT(0) /* Incoming Mailbox Loaded. */
63# define BL_INTR_OMBR RT_BIT(1) /* Outgoing Mailbox Available. */
64# define BL_INTR_CMDC RT_BIT(2) /* Command Complete. */
65# define BL_INTR_RSTS RT_BIT(3) /* SCSI Bus Reset State. */
66# define BL_INTR_INTV RT_BIT(7) /* Interrupt Valid. */
67
68/**
69 * The structure for the "Execute SCSI Command" command.
70 */
71typedef struct ESCMD
72{
73 /** Data length. */
74 uint32_t cbData;
75 /** Data pointer. */
76 uint32_t u32PhysAddrData;
77 /** The device the request is sent to. */
78 uint8_t uTargetId;
79 /** The LUN in the device. */
80 uint8_t uLogicalUnit;
81 /** Reserved */
82 unsigned char uReserved1 : 3;
83 /** Data direction for the request. */
84 unsigned char uDataDirection : 2;
85 /** Reserved */
86 unsigned char uReserved2 : 3;
87 /** Length of the SCSI CDB. */
88 uint8_t cbCDB;
89 /** The SCSI CDB. (A CDB can be 12 bytes long.) */
90 uint8_t abCDB[16];
91} ESCMD, *PESCMD;
92
93/**
94 * BusLogic-SCSI controller data.
95 */
96typedef struct
97{
98 /** The execute SCSI command. */
99 ESCMD EsCmd;
100 /** I/O base of device. */
101 uint16_t u16IoBase;
102} buslogic_t;
103
104/* The BusLogic specific data must fit into 1KB (statically allocated). */
105ct_assert(sizeof(buslogic_t) <= 1024);
106
107/**
108 * Converts a segment:offset pair into a 32bit physical address.
109 */
110static uint32_t buslogic_addr_to_phys(void __far *ptr)
111{
112 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
113}
114
115static int buslogic_cmd(buslogic_t __far *buslogic, uint8_t uCmd, uint8_t __far *pbReq, uint16_t cbReq,
116 uint8_t __far *pbReply, uint16_t cbReply)
117{
118 uint16_t i;
119
120 outb(buslogic->u16IoBase + BUSLOGIC_REGISTER_COMMAND, uCmd);
121 for (i = 0; i < cbReq; i++)
122 outb(buslogic->u16IoBase + BUSLOGIC_REGISTER_COMMAND, *pbReq++);
123
124 /* Wait for the HBA to finish processing the command. */
125 if (cbReply)
126 {
127 while (!(inb(buslogic->u16IoBase + BUSLOGIC_REGISTER_STATUS) & BL_STAT_DIRRDY));
128 for (i = 0; i < cbReply; i++)
129 *pbReply++ = inb(buslogic->u16IoBase + BUSLOGIC_REGISTER_DATAIN);
130 }
131
132 while (!(inb(buslogic->u16IoBase + BUSLOGIC_REGISTER_STATUS) & BL_STAT_HARDY));
133
134 /* Clear interrupt status. */
135 outb(buslogic->u16IoBase + BUSLOGIC_REGISTER_CONTROL, BL_CTRL_RINT);
136
137 return 0;
138}
139
140int buslogic_scsi_cmd_data_out(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
141 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
142{
143 buslogic_t __far *buslogic = (buslogic_t __far *)pvHba;
144 uint8_t abReply[4];
145 int i;
146 int rc;
147
148 _fmemset(&buslogic->EsCmd, 0, sizeof(buslogic->EsCmd));
149 _fmemset(abReply, 0, sizeof(abReply));
150
151 buslogic->EsCmd.cbData = length;
152 buslogic->EsCmd.u32PhysAddrData = buslogic_addr_to_phys(buffer);
153 buslogic->EsCmd.uTargetId = idTgt;
154 buslogic->EsCmd.uLogicalUnit = 0;
155 buslogic->EsCmd.uDataDirection = 0;
156 buslogic->EsCmd.cbCDB = cbCDB;
157
158 for (i = 0; i < cbCDB; i++)
159 buslogic->EsCmd.abCDB[i] = aCDB[i];
160
161 rc = buslogic_cmd(buslogic, BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND, (uint8_t __far *)&buslogic->EsCmd,
162 sizeof(buslogic->EsCmd) - sizeof(buslogic->EsCmd.abCDB) + cbCDB, &abReply[0], sizeof(abReply));
163 if (!rc)
164 rc = abReply[2];
165
166 return rc;
167}
168
169int buslogic_scsi_cmd_data_in(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
170 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
171{
172 buslogic_t __far *buslogic = (buslogic_t __far *)pvHba;
173 uint8_t abReply[4];
174 int i;
175 int rc;
176
177 DBG_BUSLOGIC("buslogic_scsi_cmd_data_in:\n");
178
179 _fmemset(&buslogic->EsCmd, 0, sizeof(buslogic->EsCmd));
180 _fmemset(abReply, 0, sizeof(abReply));
181
182 buslogic->EsCmd.cbData = length;
183 buslogic->EsCmd.u32PhysAddrData = buslogic_addr_to_phys(buffer);
184 buslogic->EsCmd.uTargetId = idTgt;
185 buslogic->EsCmd.uLogicalUnit = 0;
186 buslogic->EsCmd.uDataDirection = 0;
187 buslogic->EsCmd.cbCDB = cbCDB;
188
189 for (i = 0; i < cbCDB; i++)
190 buslogic->EsCmd.abCDB[i] = aCDB[i];
191
192 rc = buslogic_cmd(buslogic, BUSLOGICCOMMAND_EXECUTE_SCSI_COMMAND, (uint8_t __far *)&buslogic->EsCmd,
193 sizeof(buslogic->EsCmd) - sizeof(buslogic->EsCmd.abCDB) + cbCDB, &abReply[0], sizeof(abReply));
194 if (!rc)
195 rc = abReply[2];
196
197 return rc;
198}
199
200/**
201 * Initializes the BusLogic SCSI HBA and detects attached devices.
202 */
203static int buslogic_scsi_hba_init(buslogic_t __far *buslogic)
204{
205 /* Hard reset. */
206 outb(buslogic->u16IoBase + BUSLOGIC_REGISTER_CONTROL, BL_CTRL_RHARD);
207 while (!(inb(buslogic->u16IoBase + BUSLOGIC_REGISTER_STATUS) & BL_STAT_HARDY));
208
209 return 0;
210}
211
212/**
213 * Init the BusLogic SCSI driver and detect attached disks.
214 */
215int buslogic_scsi_init(void __far *pvHba, uint8_t u8Bus, uint8_t u8DevFn)
216{
217 buslogic_t __far *buslogic = (buslogic_t __far *)pvHba;
218 uint32_t u32Bar;
219
220 DBG_BUSLOGIC("BusLogic SCSI HBA at Bus %u DevFn 0x%x (raw 0x%x)\n", u8Bus, u8DevFn);
221
222 u32Bar = pci_read_config_dword(u8Bus, u8DevFn, 0x10);
223
224 DBG_BUSLOGIC("BAR at 0x10 : 0x%x\n", u32Bar);
225
226 if ((u32Bar & 0x01) != 0)
227 {
228 uint16_t u16IoBase = (u32Bar & 0xfff0);
229
230 /* Enable PCI memory, I/O, bus mastering access in command register. */
231 pci_write_config_word(u8Bus, u8DevFn, 4, 0x7);
232
233 DBG_BUSLOGIC("I/O base: 0x%x\n", u16IoBase);
234 buslogic->u16IoBase = u16IoBase;
235 return buslogic_scsi_hba_init(buslogic);
236 }
237 else
238 DBG_BUSLOGIC("BAR is MMIO\n");
239
240 return 1;
241}
Note: See TracBrowser for help on using the repository browser.

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