2
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
3
* of PCI-SCSI IO processors.
5
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
7
* This driver is derived from the Linux sym53c8xx driver.
8
* Copyright (C) 1998-2000 Gerard Roudier
10
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
11
* a port of the FreeBSD ncr driver to Linux-1.2.13.
13
* The original ncr driver has been written for 386bsd and FreeBSD by
14
* Wolfgang Stanglmeier <wolf@cologne.de>
15
* Stefan Esser <se@mi.Uni-Koeln.de>
16
* Copyright (C) 1994 Wolfgang Stanglmeier
18
* Other major contributions:
20
* NVRAM detection and reading.
21
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
23
*-----------------------------------------------------------------------------
25
* Redistribution and use in source and binary forms, with or without
26
* modification, are permitted provided that the following conditions
28
* 1. Redistributions of source code must retain the above copyright
29
* notice, this list of conditions and the following disclaimer.
30
* 2. The name of the author may not be used to endorse or promote products
31
* derived from this software without specific prior written permission.
33
* Where this Software is combined with software released under the terms of
34
* the GNU Public License ("GPL") and the terms of the GPL would require the
35
* combined work to also be released under the terms of the GPL, the terms
36
* and conditions of this License will apply in addition to those of the
37
* GPL with the exception of any terms or conditions of this License that
38
* conflict with, or are expressly prohibited by, the GPL.
40
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
41
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
44
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54
#include <dev/sym/sym_glue.h>
59
#ifdef SYM_OPT_HANDLE_IO_TIMEOUT
61
* Optional CCB timeout handling.
63
* This code is useful for O/Ses that allow or expect
64
* SIMs (low-level drivers) to handle SCSI IO timeouts.
65
* It uses a power-of-two based algorithm of my own:)
66
* that avoids scanning of lists, provided that:
68
* - The IO does complete in less than half the associated
70
* - The greatest delay between the queuing of the IO and
71
* its completion is less than
72
* (1<<(SYM_CONF_TIMEOUT_ORDER_MAX-1))/2 ticks.
74
* For example, if tick is 1 second and the max order is 8,
75
* any IO that is completed within less than 64 seconds will
76
* just be put into some list at queuing and be removed
77
* at completion without any additionnal overhead.
81
* Set a timeout condition on a CCB.
83
void sym_timeout_ccb(hcb_p np, ccb_p cp, u_int ticks)
85
sym_remque(&cp->tmo_linkq);
86
cp->tmo_clock = np->tmo_clock + ticks;
88
sym_insque_head(&cp->tmo_linkq, &np->tmo0_ccbq);
91
int i = SYM_CONF_TIMEOUT_ORDER_MAX - 1;
93
if (ticks >= (1<<(i+1)))
97
if (!(np->tmo_actq & (1<<i)))
98
i += SYM_CONF_TIMEOUT_ORDER_MAX;
99
sym_insque_head(&cp->tmo_linkq, &np->tmo_ccbq[i]);
104
* Walk a list of CCB and handle timeout conditions.
105
* Should never be called in normal situations.
107
static void sym_walk_ccb_tmo_list(hcb_p np, SYM_QUEHEAD *tmoq)
109
SYM_QUEHEAD qtmp, *qp;
112
sym_que_move(tmoq, &qtmp);
113
while ((qp = sym_remque_head(&qtmp)) != 0) {
114
sym_insque_head(qp, &np->tmo0_ccbq);
115
cp = sym_que_entry(qp, struct sym_ccb, tmo_linkq);
116
if (cp->tmo_clock != np->tmo_clock &&
117
cp->tmo_clock + 1 != np->tmo_clock)
118
sym_timeout_ccb(np, cp, cp->tmo_clock - np->tmo_clock);
120
sym_abort_ccb(np, cp, 1);
125
* Our clock handler called from the O/S specific side.
127
void sym_clock(hcb_p np)
133
tmp ^= (++np->tmo_clock);
135
for (i = 0; i < SYM_CONF_TIMEOUT_ORDER_MAX; i++, tmp >>= 1) {
139
if (np->tmo_actq & (1<<i))
140
j += SYM_CONF_TIMEOUT_ORDER_MAX;
142
if (!sym_que_empty(&np->tmo_ccbq[j])) {
143
sym_walk_ccb_tmo_list(np, &np->tmo_ccbq[j]);
145
np->tmo_actq ^= (1<<i);
148
#endif /* SYM_OPT_HANDLE_IO_TIMEOUT */
151
#ifdef SYM_OPT_ANNOUNCE_TRANSFER_RATE
153
* Announce transfer rate if anything changed since last announcement.
155
void sym_announce_transfer_rate(hcb_p np, int target)
157
tcb_p tp = &np->target[target];
159
#define __tprev tp->tinfo.prev
160
#define __tcurr tp->tinfo.curr
162
if (__tprev.options == __tcurr.options &&
163
__tprev.width == __tcurr.width &&
164
__tprev.offset == __tcurr.offset &&
165
!(__tprev.offset && __tprev.period != __tcurr.period))
168
__tprev.options = __tcurr.options;
169
__tprev.width = __tcurr.width;
170
__tprev.offset = __tcurr.offset;
171
__tprev.period = __tcurr.period;
173
if (__tcurr.offset && __tcurr.period) {
174
u_int period, f10, mb10;
177
period = f10 = mb10 = 0;
180
if (__tcurr.period <= 9) {
186
if (__tcurr.period <= 11) {
189
if (__tcurr.period == 11)
192
else if (__tcurr.period < 25) {
194
if (__tcurr.period == 12)
197
else if (__tcurr.period <= 50) {
201
period = 40 * __tcurr.period;
202
f10 = 100000 << (__tcurr.width ? 1 : 0);
203
mb10 = (f10 + period/2) / period;
206
"%s:%d: %s %sSCSI %d.%d MB/s %s (%d.%d ns, offset %d)\n",
207
sym_name(np), target, scsi, __tcurr.width? "WIDE " : "",
209
(__tcurr.options & PPR_OPT_DT) ? "DT" : "ST",
210
period/10, period%10, __tcurr.offset);
213
printf_info ("%s:%d: %sasynchronous.\n",
214
sym_name(np), target, __tcurr.width? "wide " : "");
218
#endif /* SYM_OPT_ANNOUNCE_TRANSFER_RATE */
221
#ifdef SYM_OPT_SNIFF_INQUIRY
223
* Update transfer settings according to user settings
224
* and bits sniffed out from INQUIRY response.
226
void sym_update_trans_settings(hcb_p np, tcb_p tp)
228
bcopy(&tp->tinfo.user, &tp->tinfo.goal, sizeof(tp->tinfo.goal));
230
if (tp->inq_version >= 4) {
231
switch(tp->inq_byte56 & INQ56_CLOCKING) {
233
tp->tinfo.goal.options = 0;
242
if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_WIDE16)) {
243
tp->tinfo.goal.width = 0;
244
tp->tinfo.goal.options = 0;
247
if (!((tp->inq_byte7 & tp->inq_byte7_valid) & INQ7_SYNC)) {
248
tp->tinfo.goal.offset = 0;
249
tp->tinfo.goal.options = 0;
252
if (tp->tinfo.goal.options & PPR_OPT_DT) {
253
if (tp->tinfo.goal.offset > np->maxoffs_dt)
254
tp->tinfo.goal.offset = np->maxoffs_dt;
257
if (tp->tinfo.goal.offset > np->maxoffs)
258
tp->tinfo.goal.offset = np->maxoffs;
263
* Snoop target capabilities from INQUIRY response.
264
* We only believe device versions >= SCSI-2 that use
265
* appropriate response data format (2). But it seems
266
* that some CCS devices also support SYNC (?).
269
__sym_sniff_inquiry(hcb_p np, u_char tn, u_char ln,
270
u_char *inq_data, int inq_len)
272
tcb_p tp = &np->target[tn];
277
if (!inq_data || inq_len < 2)
281
* Check device type and qualifier.
283
if ((inq_data[0] & 0xe0) == 0x60)
291
inq_version = inq_data[2] & 0x7;
294
* Get SYNC/WIDE16 capabilities.
296
inq_byte7 = tp->inq_byte7;
297
if (inq_version >= 2 && (inq_data[3] & 0xf) == 2) {
299
inq_byte7 = inq_data[7];
301
else if (inq_version == 1 && (inq_data[3] & 0xf) == 1)
302
inq_byte7 = INQ7_SYNC;
305
* Get Tagged Command Queuing capability.
307
if (inq_byte7 & INQ7_CMDQ)
308
sym_set_bit(tp->cmdq_map, ln);
310
sym_clr_bit(tp->cmdq_map, ln);
311
inq_byte7 &= ~INQ7_CMDQ;
314
* Get CLOCKING capability.
316
inq_byte56 = tp->inq_byte56;
317
if (inq_version >= 4 && inq_len > 56)
318
tp->inq_byte56 = inq_data[56];
320
printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n",
321
inq_len, inq_version, inq_byte7, inq_byte56);
324
* Trigger a negotiation if needed.
326
if (tp->inq_version != inq_version ||
327
tp->inq_byte7 != inq_byte7 ||
328
tp->inq_byte56 != inq_byte56) {
329
tp->inq_version = inq_version;
330
tp->inq_byte7 = inq_byte7;
331
tp->inq_byte56 = inq_byte56;
336
#endif /* SYM_OPT_SNIFF_INQUIRY */