VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/BIOS/lsilogic.c@ 89330

Last change on this file since 89330 was 89267, checked in by vboxsync, 4 years ago

PC/BIOS/buslogic: Use the EXECUTE SCSI command instead of the mailbox interface to not interfer with guest drivers using it, bugref:4841

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

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