VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/lsilogic.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: 18.0 KB
Line 
1/* $Id: lsilogic.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * LsiLogic 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_LSILOGIC 1
38#if DEBUG_LSILOGIC
39# define DBG_LSILOGIC(...) BX_INFO(__VA_ARGS__)
40#else
41# define DBG_LSILOGIC(...)
42#endif
43
44#define RT_BIT(bit) (1L << (bit))
45
46/**
47 * A simple SG element for a 32bit address.
48 */
49typedef struct MptSGEntrySimple32
50{
51 /** Length of the buffer this entry describes. */
52 uint32_t u24Length: 24;
53 /** Flag whether this element is the end of the list. */
54 uint32_t fEndOfList: 1;
55 /** Flag whether the address is 32bit or 64bits wide. */
56 uint32_t f64BitAddress: 1;
57 /** Flag whether this buffer contains data to be transferred or is the destination. */
58 uint32_t fBufferContainsData: 1;
59 /** Flag whether this is a local address or a system address. */
60 uint32_t fLocalAddress: 1;
61 /** Element type. */
62 uint32_t u2ElementType: 2;
63 /** Flag whether this is the last element of the buffer. */
64 uint32_t fEndOfBuffer: 1;
65 /** Flag whether this is the last element of the current segment. */
66 uint32_t fLastElement: 1;
67 /** Lower 32bits of the address of the data buffer. */
68 uint32_t u32DataBufferAddressLow: 32;
69} MptSGEntrySimple32, *PMptSGEntrySimple32;
70
71/** Defined function codes found in the message header. */
72#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST (0x00)
73#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT (0x02)
74
75/**
76 * SCSI IO Request
77 */
78typedef struct MptSCSIIORequest
79{
80 /** Target ID */
81 uint8_t u8TargetID;
82 /** Bus number */
83 uint8_t u8Bus;
84 /** Chain offset */
85 uint8_t u8ChainOffset;
86 /** Function number. */
87 uint8_t u8Function;
88 /** CDB length. */
89 uint8_t u8CDBLength;
90 /** Sense buffer length. */
91 uint8_t u8SenseBufferLength;
92 /** Reserved */
93 uint8_t u8Reserved;
94 /** Message flags. */
95 uint8_t u8MessageFlags;
96 /** Message context ID. */
97 uint32_t u32MessageContext;
98 /** LUN */
99 uint8_t au8LUN[8];
100 /** Control values. */
101 uint32_t u32Control;
102 /** The CDB. */
103 uint8_t au8CDB[16];
104 /** Data length. */
105 uint32_t u32DataLength;
106 /** Sense buffer low 32bit address. */
107 uint32_t u32SenseBufferLowAddress;
108} MptSCSIIORequest, *PMptSCSIIORequest;
109
110#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_NONE (0x0L)
111#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE (0x1L)
112#define MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ (0x2L)
113
114/**
115 * SCSI IO error reply.
116 */
117typedef struct MptSCSIIOErrorReply
118{
119 /** Target ID */
120 uint8_t u8TargetID;
121 /** Bus number */
122 uint8_t u8Bus;
123 /** Message length. */
124 uint8_t u8MessageLength;
125 /** Function number. */
126 uint8_t u8Function;
127 /** CDB length */
128 uint8_t u8CDBLength;
129 /** Sense buffer length */
130 uint8_t u8SenseBufferLength;
131 /** Reserved */
132 uint8_t u8Reserved;
133 /** Message flags */
134 uint8_t u8MessageFlags;
135 /** Message context ID */
136 uint32_t u32MessageContext;
137 /** SCSI status. */
138 uint8_t u8SCSIStatus;
139 /** SCSI state */
140 uint8_t u8SCSIState;
141 /** IO controller status */
142 uint16_t u16IOCStatus;
143 /** IO controller log information */
144 uint32_t u32IOCLogInfo;
145 /** Transfer count */
146 uint32_t u32TransferCount;
147 /** Sense count */
148 uint32_t u32SenseCount;
149 /** Response information */
150 uint32_t u32ResponseInfo;
151} MptSCSIIOErrorReply, *PMptSCSIIOErrorReply;
152
153/**
154 * IO controller init request.
155 */
156typedef struct MptIOCInitRequest
157{
158 /** Which system send this init request. */
159 uint8_t u8WhoInit;
160 /** Reserved */
161 uint8_t u8Reserved;
162 /** Chain offset in the SG list. */
163 uint8_t u8ChainOffset;
164 /** Function to execute. */
165 uint8_t u8Function;
166 /** Flags */
167 uint8_t u8Flags;
168 /** Maximum number of devices the driver can handle. */
169 uint8_t u8MaxDevices;
170 /** Maximum number of buses the driver can handle. */
171 uint8_t u8MaxBuses;
172 /** Message flags. */
173 uint8_t u8MessageFlags;
174 /** Message context ID. */
175 uint32_t u32MessageContext;
176 /** Reply frame size. */
177 uint16_t u16ReplyFrameSize;
178 /** Reserved */
179 uint16_t u16Reserved;
180 /** Upper 32bit part of the 64bit address the message frames are in.
181 * That means all frames must be in the same 4GB segment. */
182 uint32_t u32HostMfaHighAddr;
183 /** Upper 32bit of the sense buffer. */
184 uint32_t u32SenseBufferHighAddr;
185} MptIOCInitRequest, *PMptIOCInitRequest;
186
187#define LSILOGICWHOINIT_SYSTEM_BIOS 0x01
188
189
190/**
191 * IO controller init reply.
192 */
193typedef struct MptIOCInitReply
194{
195 /** Which subsystem send this init request. */
196 uint8_t u8WhoInit;
197 /** Reserved */
198 uint8_t u8Reserved;
199 /** Message length */
200 uint8_t u8MessageLength;
201 /** Function. */
202 uint8_t u8Function;
203 /** Flags */
204 uint8_t u8Flags;
205 /** Maximum number of devices the driver can handle. */
206 uint8_t u8MaxDevices;
207 /** Maximum number of busses the driver can handle. */
208 uint8_t u8MaxBuses;
209 /** Message flags. */
210 uint8_t u8MessageFlags;
211 /** Message context ID */
212 uint32_t u32MessageContext;
213 /** Reserved */
214 uint16_t u16Reserved;
215 /** IO controller status. */
216 uint16_t u16IOCStatus;
217 /** IO controller log information. */
218 uint32_t u32IOCLogInfo;
219} MptIOCInitReply, *PMptIOCInitReply;
220
221/**
222 * Doorbell register - Used to get the status of the controller and
223 * initialise it.
224 */
225#define LSILOGIC_REG_DOORBELL 0x00
226# define LSILOGIC_REG_DOORBELL_SET_STATE(enmState) (((enmState) & 0x0f) << 28)
227# define LSILOGIC_REG_DOORBELL_SET_USED(enmDoorbell) (((enmDoorbell != LSILOGICDOORBELLSTATE_NOT_IN_USE) ? 1 : 0) << 27)
228# define LSILOGIC_REG_DOORBELL_SET_WHOINIT(enmWhoInit) (((enmWhoInit) & 0x07) << 24)
229# define LSILOGIC_REG_DOORBELL_SET_FAULT_CODE(u16Code) (u16Code)
230# define LSILOGIC_REG_DOORBELL_GET_FUNCTION(x) (((x) & 0xff000000) >> 24)
231# define LSILOGIC_REG_DOORBELL_GET_SIZE(x) (((x) & 0x00ff0000) >> 16)
232
233/**
234 * Functions which can be passed through the system doorbell.
235 */
236#define LSILOGIC_DOORBELL_FUNCTION_IOC_MSG_UNIT_RESET 0x40L
237#define LSILOGIC_DOORBELL_FUNCTION_IO_UNIT_RESET 0x41L
238#define LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE 0x42L
239#define LSILOGIC_DOORBELL_FUNCTION_REPLY_FRAME_REMOVAL 0x43L
240
241/**
242 * Write sequence register for the diagnostic register.
243 */
244#define LSILOGIC_REG_WRITE_SEQUENCE 0x04
245
246/**
247 * Diagnostic register - used to reset the controller.
248 */
249#define LSILOGIC_REG_HOST_DIAGNOSTIC 0x08
250# define LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_MEM_ENABLE (RT_BIT(0))
251# define LSILOGIC_REG_HOST_DIAGNOSTIC_DISABLE_ARM (RT_BIT(1))
252# define LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER (RT_BIT(2))
253# define LSILOGIC_REG_HOST_DIAGNOSTIC_DIAG_RW_ENABLE (RT_BIT(4))
254# define LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_HISTORY (RT_BIT(5))
255# define LSILOGIC_REG_HOST_DIAGNOSTIC_FLASH_BAD_SIG (RT_BIT(6))
256# define LSILOGIC_REG_HOST_DIAGNOSTIC_DRWE (RT_BIT(7))
257# define LSILOGIC_REG_HOST_DIAGNOSTIC_PREVENT_IOC_BOOT (RT_BIT(9))
258# define LSILOGIC_REG_HOST_DIAGNOSTIC_CLEAR_FLASH_BAD_SIG (RT_BIT(10))
259
260#define LSILOGIC_REG_TEST_BASE_ADDRESS 0x0c
261#define LSILOGIC_REG_DIAG_RW_DATA 0x10
262#define LSILOGIC_REG_DIAG_RW_ADDRESS 0x14
263
264/**
265 * Interrupt status register.
266 */
267#define LSILOGIC_REG_HOST_INTR_STATUS 0x30
268# define LSILOGIC_REG_HOST_INTR_STATUS_W_MASK (RT_BIT(3))
269# define LSILOGIC_REG_HOST_INTR_STATUS_DOORBELL_STS (RT_BIT(31))
270# define LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR (RT_BIT(3))
271# define LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL (RT_BIT(0))
272
273/**
274 * Interrupt mask register.
275 */
276#define LSILOGIC_REG_HOST_INTR_MASK 0x34
277# define LSILOGIC_REG_HOST_INTR_MASK_W_MASK (RT_BIT(0) | RT_BIT(3) | RT_BIT(8) | RT_BIT(9))
278# define LSILOGIC_REG_HOST_INTR_MASK_IRQ_ROUTING (RT_BIT(8) | RT_BIT(9))
279# define LSILOGIC_REG_HOST_INTR_MASK_DOORBELL RT_BIT(0)
280# define LSILOGIC_REG_HOST_INTR_MASK_REPLY RT_BIT(3)
281
282/**
283 * Queue registers.
284 */
285#define LSILOGIC_REG_REQUEST_QUEUE 0x40
286#define LSILOGIC_REG_REPLY_QUEUE 0x44
287
288/**
289 * LsiLogic-SCSI controller data.
290 */
291typedef struct
292{
293 /** The SCSI I/O request structure. */
294 MptSCSIIORequest ScsiIoReq;
295 /** S/G elements being used, must come after the I/O request structure. */
296 MptSGEntrySimple32 Sge;
297 /** The reply frame used for address replies. */
298 uint8_t abReply[128];
299 /** I/O base of device. */
300 uint16_t u16IoBase;
301} lsilogic_t;
302
303/* The BusLogic specific data must fit into 1KB (statically allocated). */
304ct_assert(sizeof(lsilogic_t) <= 1024);
305
306#define VBOX_LSILOGIC_NO_DEVICE 0xffff
307
308/* Warning: Destroys high bits of EAX. */
309uint32_t inpd(uint16_t port);
310#pragma aux inpd = \
311 ".386" \
312 "in eax, dx" \
313 "mov dx, ax" \
314 "shr eax, 16" \
315 "xchg ax, dx" \
316 parm [dx] value [dx ax] modify nomemory;
317
318/* Warning: Destroys high bits of EAX. */
319void outpd(uint16_t port, uint32_t val);
320#pragma aux outpd = \
321 ".386" \
322 "xchg ax, cx" \
323 "shl eax, 16" \
324 "mov ax, cx" \
325 "out dx, eax" \
326 parm [dx] [cx ax] modify nomemory;
327
328/**
329 * Converts a segment:offset pair into a 32bit physical address.
330 */
331static uint32_t lsilogic_addr_to_phys(void __far *ptr)
332{
333 return ((uint32_t)FP_SEG(ptr) << 4) + FP_OFF(ptr);
334}
335
336static int lsilogic_cmd(lsilogic_t __far *lsilogic, const void __far *pvReq, uint16_t cbReq,
337 void __far *pvReply, uint16_t cbReply)
338{
339 uint16_t i;
340 const uint32_t __far *pu32Req = (const uint32_t __far *)pvReq;
341 uint16_t __far *pu16Reply = (uint16_t *)pvReply;
342 uint32_t cMsg = cbReq / sizeof(uint32_t);
343 uint16_t cReply = cbReply / sizeof(uint16_t);
344 uint32_t u32Fn = (LSILOGIC_DOORBELL_FUNCTION_HANDSHAKE << 24) | (cMsg << 16);
345
346 if ( cbReq % sizeof(uint32_t)
347 || cbReply % sizeof(uint16_t))
348 return 1;
349
350 outpd(lsilogic->u16IoBase + LSILOGIC_REG_DOORBELL, u32Fn);
351 for (i = 0; i < cMsg; i++)
352 outpd(lsilogic->u16IoBase + LSILOGIC_REG_DOORBELL, pu32Req[i]);
353
354 for (i = 0; i < cReply; i++)
355 {
356 /* Wait for the system doorbell interrupt status to be set. */
357 while (!(inpd(lsilogic->u16IoBase + LSILOGIC_REG_HOST_INTR_STATUS) & LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL));
358
359 pu16Reply[i] = (uint16_t)inpd(lsilogic->u16IoBase + LSILOGIC_REG_DOORBELL); /* The lower 16bits contain the reply data. */
360 outpd(lsilogic->u16IoBase + LSILOGIC_REG_HOST_INTR_STATUS, 1);
361 }
362
363 return 0;
364}
365
366static int lsilogic_scsi_cmd_exec(lsilogic_t __far *lsilogic)
367{
368 uint32_t u32Reply = 0;
369 uint32_t u32ReplyDummy = 0;
370
371 /* Send it off. */
372 outpd(lsilogic->u16IoBase + LSILOGIC_REG_REQUEST_QUEUE, lsilogic_addr_to_phys(&lsilogic->ScsiIoReq));
373
374 /* Wait for it to finish. */
375 while (!(inpd(lsilogic->u16IoBase + LSILOGIC_REG_HOST_INTR_STATUS) & LSILOGIC_REG_HOST_INTR_STATUS_REPLY_INTR));
376
377 outpd(lsilogic->u16IoBase + LSILOGIC_REG_HOST_INTR_STATUS, 1);
378
379 /* Read the reply queue. */
380 u32Reply = inpd(lsilogic->u16IoBase + LSILOGIC_REG_REPLY_QUEUE);
381 u32ReplyDummy = inpd(lsilogic->u16IoBase + LSILOGIC_REG_REPLY_QUEUE);
382 if (u32ReplyDummy != 0xffffffff)
383 return 5;
384 if (u32Reply & RT_BIT(31))
385 {
386 /*
387 * This is an address reply indicating a failed transaction, so just return an error without
388 * bothering to check the exact failure reason for now.
389 *
390 * Just provide the reply frame to the reply queue again.
391 */
392 outpd(lsilogic->u16IoBase + LSILOGIC_REG_REPLY_QUEUE, lsilogic_addr_to_phys(&lsilogic->abReply));
393 return 4;
394 }
395
396 if (u32Reply != 0xcafe) /* Getting a different context ID should never ever happen. */
397 return 3;
398
399 return 0;
400}
401
402int lsilogic_scsi_cmd_data_out(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
403 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
404{
405 lsilogic_t __far *lsilogic = (lsilogic_t __far *)pvHba;
406 int i;
407
408 _fmemset(&lsilogic->ScsiIoReq, 0, sizeof(lsilogic->ScsiIoReq));
409
410 lsilogic->ScsiIoReq.u8TargetID = idTgt;
411 lsilogic->ScsiIoReq.u8Bus = 0;
412 lsilogic->ScsiIoReq.u8ChainOffset = 0;
413 lsilogic->ScsiIoReq.u8Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
414 lsilogic->ScsiIoReq.u8CDBLength = cbCDB;
415 lsilogic->ScsiIoReq.u8SenseBufferLength = 0;
416 lsilogic->ScsiIoReq.u32MessageContext = 0xcafe;
417 lsilogic->ScsiIoReq.u32Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE << 24;
418 lsilogic->ScsiIoReq.u32DataLength = length;
419 for (i = 0; i < cbCDB; i++)
420 lsilogic->ScsiIoReq.au8CDB[i] = aCDB[i];
421
422 lsilogic->Sge.u24Length = length;
423 lsilogic->Sge.fEndOfList = 1;
424 lsilogic->Sge.f64BitAddress = 0;
425 lsilogic->Sge.fBufferContainsData = 0;
426 lsilogic->Sge.fLocalAddress = 0;
427 lsilogic->Sge.u2ElementType = 0x01; /* Simple type */
428 lsilogic->Sge.fEndOfBuffer = 1;
429 lsilogic->Sge.fLastElement = 1;
430 lsilogic->Sge.u32DataBufferAddressLow = lsilogic_addr_to_phys(buffer);
431
432 return lsilogic_scsi_cmd_exec(lsilogic);
433}
434
435int lsilogic_scsi_cmd_data_in(void __far *pvHba, uint8_t idTgt, uint8_t __far *aCDB,
436 uint8_t cbCDB, uint8_t __far *buffer, uint32_t length)
437{
438 lsilogic_t __far *lsilogic = (lsilogic_t __far *)pvHba;
439 int i;
440
441 _fmemset(&lsilogic->ScsiIoReq, 0, sizeof(lsilogic->ScsiIoReq));
442
443 lsilogic->ScsiIoReq.u8TargetID = idTgt;
444 lsilogic->ScsiIoReq.u8Bus = 0;
445 lsilogic->ScsiIoReq.u8ChainOffset = 0;
446 lsilogic->ScsiIoReq.u8Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST;
447 lsilogic->ScsiIoReq.u8CDBLength = cbCDB;
448 lsilogic->ScsiIoReq.u8SenseBufferLength = 0;
449 lsilogic->ScsiIoReq.u32MessageContext = 0xcafe;
450 lsilogic->ScsiIoReq.u32Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ << 24;
451 lsilogic->ScsiIoReq.u32DataLength = length;
452 for (i = 0; i < cbCDB; i++)
453 lsilogic->ScsiIoReq.au8CDB[i] = aCDB[i];
454
455 lsilogic->Sge.u24Length = length;
456 lsilogic->Sge.fEndOfList = 1;
457 lsilogic->Sge.f64BitAddress = 0;
458 lsilogic->Sge.fBufferContainsData = 0;
459 lsilogic->Sge.fLocalAddress = 0;
460 lsilogic->Sge.u2ElementType = 0x01; /* Simple type */
461 lsilogic->Sge.fEndOfBuffer = 1;
462 lsilogic->Sge.fLastElement = 1;
463 lsilogic->Sge.u32DataBufferAddressLow = lsilogic_addr_to_phys(buffer);
464
465 return lsilogic_scsi_cmd_exec(lsilogic);
466}
467
468/**
469 * Initializes the LsiLogic SCSI HBA and detects attached devices.
470 */
471static int lsilogic_scsi_hba_init(lsilogic_t __far *lsilogic)
472{
473 int rc;
474 MptIOCInitRequest IocInitReq;
475 MptIOCInitReply IocInitReply;
476
477 /*
478 * The following initialization sequence is stripped down to the point to work with
479 * our emulated LsiLogic controller, it will most certainly fail on real hardware.
480 */
481
482 /* Hard reset, write the sequence to enable the diagnostic access. */
483 outpd(lsilogic->u16IoBase + LSILOGIC_REG_WRITE_SEQUENCE, 0x04);
484 outpd(lsilogic->u16IoBase + LSILOGIC_REG_WRITE_SEQUENCE, 0x02);
485 outpd(lsilogic->u16IoBase + LSILOGIC_REG_WRITE_SEQUENCE, 0x07);
486 outpd(lsilogic->u16IoBase + LSILOGIC_REG_WRITE_SEQUENCE, 0x0d);
487 outpd(lsilogic->u16IoBase + LSILOGIC_REG_HOST_DIAGNOSTIC, LSILOGIC_REG_HOST_DIAGNOSTIC_RESET_ADAPTER);
488
489 IocInitReq.u8WhoInit = LSILOGICWHOINIT_SYSTEM_BIOS;
490 IocInitReq.u8Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT;
491 IocInitReq.u32HostMfaHighAddr = 0;
492 IocInitReq.u32SenseBufferHighAddr = 0;
493 IocInitReq.u8MaxBuses = 1;
494 IocInitReq.u8MaxDevices = 4;
495 IocInitReq.u16ReplyFrameSize = sizeof(lsilogic->abReply);
496 rc = lsilogic_cmd(lsilogic, &IocInitReq, sizeof(IocInitReq), &IocInitReply, sizeof(IocInitReply));
497 if (!rc)
498 {
499 /* Provide a single reply frame for SCSI I/O errors. */
500 outpd(lsilogic->u16IoBase + LSILOGIC_REG_REPLY_QUEUE, lsilogic_addr_to_phys(&lsilogic->abReply));
501 return 0;
502 }
503
504 return 1;
505}
506
507/**
508 * Init the LsiLogic SCSI driver and detect attached disks.
509 */
510int lsilogic_scsi_init(void __far *pvHba, uint8_t u8Bus, uint8_t u8DevFn)
511{
512 lsilogic_t __far *lsilogic = (lsilogic_t __far *)pvHba;
513 uint32_t u32Bar;
514
515 DBG_LSILOGIC("LsiLogic SCSI HBA at Bus %u DevFn 0x%x (raw 0x%x)\n", u8Bus, u8DevFn);
516
517 u32Bar = pci_read_config_dword(u8Bus, u8DevFn, 0x10);
518
519 DBG_LSILOGIC("BAR at 0x10 : 0x%x\n", u32Bar);
520
521 if ((u32Bar & 0x01) != 0)
522 {
523 uint16_t u16IoBase = (u32Bar & 0xfff0);
524
525 /* Enable PCI memory, I/O, bus mastering access in command register. */
526 pci_write_config_word(u8Bus, u8DevFn, 4, 0x7);
527
528 DBG_LSILOGIC("I/O base: 0x%x\n", u16IoBase);
529 lsilogic->u16IoBase = u16IoBase;
530 return lsilogic_scsi_hba_init(lsilogic);
531 }
532 else
533 DBG_LSILOGIC("BAR is MMIO\n");
534
535 return 1;
536}
537
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use