VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use