VirtualBox

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

Last change on this file was 101004, checked in by vboxsync, 8 months ago

BIOS: Added proper VDS S/G support to the LSI Logic driver.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use