Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Written by Julian Elischer (julian@tfs.com) | |
3 | * for TRW Financial Systems for use under the MACH(2.5) operating system. | |
4 | * | |
5 | * TRW Financial Systems, in accordance with their agreement with Carnegie | |
6 | * Mellon University, makes this software available to CMU to distribute | |
7 | * or use in any manner that they see fit as long as this message is kept with | |
8 | * the software. For this reason TFS also grants any other persons or | |
9 | * organisations permission to use or modify this software. | |
10 | * | |
11 | * TFS supplies this software to be publicly redistributed | |
12 | * on the understanding that TFS is not responsible for the correct | |
13 | * functioning of this software in any circumstances. | |
14 | * | |
78ed81a3 | 15 | * $Id: bt742a.c,v 1.7 1993/08/28 03:07:42 rgrimes Exp $ |
15637ed4 RG |
16 | */ |
17 | ||
18 | /* | |
78ed81a3 | 19 | * bt742a SCSI driver |
15637ed4 RG |
20 | */ |
21 | ||
22 | #include <sys/types.h> | |
23 | #include <bt.h> | |
24 | ||
25 | #include <sys/param.h> | |
26 | #include <sys/systm.h> | |
27 | #include <sys/errno.h> | |
28 | #include <sys/ioctl.h> | |
29 | #include <sys/buf.h> | |
30 | #include <sys/proc.h> | |
31 | #include <sys/user.h> | |
32 | ||
33 | #ifdef MACH /* EITHER CMU OR OSF */ | |
34 | #include <i386/ipl.h> | |
35 | #include <i386at/scsi.h> | |
36 | #include <i386at/scsiconf.h> | |
37 | ||
38 | #ifdef OSF /* OSF ONLY */ | |
39 | #include <sys/table.h> | |
40 | #include <i386/handler.h> | |
41 | #include <i386/dispatcher.h> | |
42 | #include <i386/AT386/atbus.h> | |
43 | ||
44 | #else OSF /* CMU ONLY */ | |
45 | #include <i386at/atbus.h> | |
46 | #include <i386/pio.h> | |
47 | #endif OSF | |
48 | #endif MACH /* end of MACH specific */ | |
49 | ||
50 | #ifdef __386BSD__ /* 386BSD specific */ | |
51 | #define isa_dev isa_device | |
52 | #define dev_unit id_unit | |
53 | #define dev_addr id_iobase | |
54 | ||
55 | #include <i386/isa/isa_device.h> | |
56 | #include <scsi/scsi_all.h> | |
57 | #include <scsi/scsiconf.h> | |
58 | #endif __386BSD__ | |
59 | ||
60 | ||
61 | #ifdef __386BSD__ | |
62 | #include "ddb.h" | |
63 | #if NDDB > 0 | |
64 | int Debugger(); | |
65 | #else NDDB | |
78ed81a3 | 66 | #define Debugger() panic("should call debugger here (bt742a.c)") |
15637ed4 RG |
67 | #endif NDDB |
68 | #endif __386BSD__ | |
69 | ||
70 | #ifdef MACH | |
71 | int Debugger(); | |
72 | #endif MACH | |
73 | ||
78ed81a3 | 74 | extern int hz; |
15637ed4 RG |
75 | extern int delaycount; /* from clock setup code */ |
76 | typedef unsigned long int physaddr; | |
77 | ||
78 | /* | |
79 | * I/O Port Interface | |
80 | */ | |
81 | ||
82 | #define BT_BASE bt_base[unit] | |
83 | #define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ | |
84 | #define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ | |
85 | #define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ | |
86 | ||
87 | /* | |
88 | * BT_CTRL_STAT bits (write) | |
89 | */ | |
90 | ||
91 | #define BT_HRST 0x80 /* Hardware reset */ | |
92 | #define BT_SRST 0x40 /* Software reset */ | |
93 | #define BT_IRST 0x20 /* Interrupt reset */ | |
94 | #define BT_SCRST 0x10 /* SCSI bus reset */ | |
95 | ||
96 | /* | |
97 | * BT_CTRL_STAT bits (read) | |
98 | */ | |
99 | ||
100 | #define BT_STST 0x80 /* Self test in Progress */ | |
101 | #define BT_DIAGF 0x40 /* Diagnostic Failure */ | |
102 | #define BT_INIT 0x20 /* Mbx Init required */ | |
103 | #define BT_IDLE 0x10 /* Host Adapter Idle */ | |
104 | #define BT_CDF 0x08 /* cmd/data out port full */ | |
105 | #define BT_DF 0x04 /* Data in port full */ | |
106 | #define BT_INVDCMD 0x01 /* Invalid command */ | |
107 | ||
108 | /* | |
109 | * BT_CMD_DATA bits (write) | |
110 | */ | |
111 | ||
112 | #define BT_NOP 0x00 /* No operation */ | |
113 | #define BT_MBX_INIT 0x01 /* Mbx initialization */ | |
114 | #define BT_START_SCSI 0x02 /* start scsi command */ | |
115 | #define BT_START_BIOS 0x03 /* start bios command */ | |
116 | #define BT_INQUIRE 0x04 /* Adapter Inquiry */ | |
117 | #define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */ | |
118 | #define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */ | |
119 | #define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */ | |
120 | #define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */ | |
121 | #define BT_SPEED_SET 0x09 /* set transfer speed */ | |
122 | #define BT_DEV_GET 0x0a /* return installed devices */ | |
123 | #define BT_CONF_GET 0x0b /* return configuration data */ | |
124 | #define BT_TARGET_EN 0x0c /* enable target mode */ | |
125 | #define BT_SETUP_GET 0x0d /* return setup data */ | |
126 | #define BT_WRITE_CH2 0x1a /* write channel 2 buffer */ | |
127 | #define BT_READ_CH2 0x1b /* read channel 2 buffer */ | |
128 | #define BT_WRITE_FIFO 0x1c /* write fifo buffer */ | |
129 | #define BT_READ_FIFO 0x1d /* read fifo buffer */ | |
130 | #define BT_ECHO 0x1e /* Echo command data */ | |
131 | #define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ | |
132 | #define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ | |
133 | ||
78ed81a3 | 134 | /* Follows command appeared at FirmWare 3.31 */ |
135 | #define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ | |
136 | #define BT_DISABLE 0x00 /* Parameter value for Disable */ | |
137 | #define BT_ENABLE 0x01 /* Parameter value for Enable */ | |
138 | ||
15637ed4 RG |
139 | struct bt_cmd_buf { |
140 | u_char byte[16]; | |
141 | }; | |
142 | ||
143 | /* | |
144 | * BT_INTR_PORT bits (read) | |
145 | */ | |
146 | ||
78ed81a3 | 147 | #define BT_ANY_INTR 0x80 /* Any interrupt */ |
15637ed4 RG |
148 | #define BT_SCRD 0x08 /* SCSI reset detected */ |
149 | #define BT_HACC 0x04 /* Command complete */ | |
150 | #define BT_MBOA 0x02 /* MBX out empty */ | |
151 | #define BT_MBIF 0x01 /* MBX in full */ | |
152 | ||
153 | /* | |
154 | * Mail box defs | |
155 | */ | |
156 | ||
78ed81a3 | 157 | #define BT_MBX_SIZE 255 /* mail box size (MAX 255 MBxs) */ |
158 | #define BT_CCB_SIZE 32 /* store up to 32CCBs at any one time */ | |
159 | /* in bt742a H/W ( Not MAX ? ) */ | |
160 | ||
161 | #define bt_nextmbx( wmb, mbx, mbio ) \ | |
162 | if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) { \ | |
163 | (wmb) = &((mbx)->mbio[0]); \ | |
164 | } else { \ | |
165 | (wmb)++; \ | |
166 | } | |
167 | ||
168 | ||
169 | typedef struct bt_mbx_out { | |
170 | physaddr ccb_addr; | |
171 | unsigned char dummy[3]; | |
172 | unsigned char cmd; | |
173 | } BT_MBO; | |
174 | ||
175 | typedef struct bt_mbx_in{ | |
176 | physaddr ccb_addr; | |
177 | unsigned char btstat; | |
178 | unsigned char sdstat; | |
179 | unsigned char dummy; | |
180 | unsigned char stat; | |
181 | } BT_MBI; | |
15637ed4 RG |
182 | |
183 | struct bt_mbx | |
184 | { | |
78ed81a3 | 185 | BT_MBO mbo[BT_MBX_SIZE]; |
186 | BT_MBI mbi[BT_MBX_SIZE]; | |
187 | BT_MBO *tmbo; /* Target Mail Box out */ | |
188 | BT_MBI *tmbi; /* Target Mail Box in */ | |
15637ed4 RG |
189 | }; |
190 | ||
191 | /* | |
192 | * mbo.cmd values | |
193 | */ | |
194 | ||
195 | #define BT_MBO_FREE 0x0 /* MBO entry is free */ | |
196 | #define BT_MBO_START 0x1 /* MBO activate entry */ | |
197 | #define BT_MBO_ABORT 0x2 /* MBO abort entry */ | |
198 | ||
199 | #define BT_MBI_FREE 0x0 /* MBI entry is free */ | |
200 | #define BT_MBI_OK 0x1 /* completed without error */ | |
201 | #define BT_MBI_ABORT 0x2 /* aborted ccb */ | |
202 | #define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ | |
203 | #define BT_MBI_ERROR 0x4 /* Completed with error */ | |
204 | ||
205 | extern struct bt_mbx bt_mbx[]; | |
206 | ||
207 | #if defined(BIG_DMA) | |
208 | /* #define BT_NSEG 8192 /* Number of scatter gather segments - to much vm */ | |
209 | #define BT_NSEG 512 | |
210 | #else | |
211 | #define BT_NSEG 33 | |
212 | #endif /* BIG_DMA */ | |
213 | struct bt_scat_gath | |
214 | { | |
215 | unsigned long seg_len; | |
216 | physaddr seg_addr; | |
217 | }; | |
218 | ||
219 | struct bt_ccb { | |
220 | unsigned char opcode; | |
221 | unsigned char :3,data_in:1,data_out:1,:3; | |
222 | unsigned char scsi_cmd_length; | |
223 | unsigned char req_sense_length; | |
224 | /*------------------------------------longword boundary */ | |
225 | unsigned long data_length; | |
226 | /*------------------------------------longword boundary */ | |
227 | physaddr data_addr; | |
228 | /*------------------------------------longword boundary */ | |
229 | unsigned char dummy[2]; | |
230 | unsigned char host_stat; | |
231 | unsigned char target_stat; | |
232 | /*------------------------------------longword boundary */ | |
233 | unsigned char target; | |
234 | unsigned char lun; | |
235 | unsigned char scsi_cmd[12]; /* 12 bytes (bytes only)*/ | |
236 | unsigned char dummy2[1]; | |
237 | unsigned char link_id; | |
238 | /*------------------------------------4 longword boundary */ | |
239 | physaddr link_addr; | |
240 | /*------------------------------------longword boundary */ | |
241 | physaddr sense_ptr; | |
242 | /*------------------------------------longword boundary */ | |
243 | struct scsi_sense_data scsi_sense; | |
244 | /*------------------------------------longword boundary */ | |
245 | struct bt_scat_gath scat_gath[BT_NSEG]; | |
246 | /*------------------------------------longword boundary */ | |
247 | struct bt_ccb *next; | |
248 | /*------------------------------------longword boundary */ | |
249 | struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ | |
250 | /*------------------------------------longword boundary */ | |
251 | struct bt_mbx_out *mbx; /* pointer to mail box */ | |
252 | /*------------------------------------longword boundary */ | |
15637ed4 RG |
253 | int flags; |
254 | #define CCB_FREE 0 | |
255 | #define CCB_ACTIVE 1 | |
256 | #define CCB_ABORTED 2 | |
257 | }; | |
258 | ||
15637ed4 RG |
259 | /* |
260 | * opcode fields | |
261 | */ | |
262 | ||
263 | #define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ | |
264 | #define BT_TARGET_CCB 0x01 /* SCSI Target CCB */ | |
265 | #define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ | |
266 | #define BT_RESET_CCB 0x81 /* SCSI Bus reset */ | |
267 | ||
268 | ||
269 | /* | |
270 | * bt_ccb.host_stat values | |
271 | */ | |
272 | ||
273 | #define BT_OK 0x00 /* cmd ok */ | |
274 | #define BT_LINK_OK 0x0a /* Link cmd ok */ | |
275 | #define BT_LINK_IT 0x0b /* Link cmd ok + int */ | |
276 | #define BT_SEL_TIMEOUT 0x11 /* Selection time out */ | |
277 | #define BT_OVER_UNDER 0x12 /* Data over/under run */ | |
278 | #define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */ | |
279 | #define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */ | |
280 | #define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */ | |
281 | #define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */ | |
282 | #define BT_BAD_LINK 0x17 /* Not same values of LUN for links */ | |
283 | #define BT_INV_TARGET 0x18 /* Invalid target direction */ | |
284 | #define BT_CCB_DUP 0x19 /* Duplicate CCB received */ | |
285 | #define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ | |
286 | #define BT_ABORTED 42 /* pseudo value from driver */ | |
287 | ||
78ed81a3 | 288 | struct bt_boardID |
289 | { | |
290 | u_char board_type; | |
291 | u_char custom_feture; | |
292 | char firm_revision; | |
293 | u_char firm_version; | |
294 | }; | |
15637ed4 RG |
295 | |
296 | struct bt_setup | |
297 | { | |
298 | u_char sync_neg:1; | |
299 | u_char parity:1; | |
300 | u_char :6; | |
301 | u_char speed; | |
302 | u_char bus_on; | |
303 | u_char bus_off; | |
304 | u_char num_mbx; | |
78ed81a3 | 305 | u_char mbx[3]; |
306 | struct { | |
15637ed4 RG |
307 | u_char offset:4; |
308 | u_char period:3; | |
309 | u_char valid:1; | |
310 | }sync[8]; | |
311 | u_char disc_sts; | |
312 | }; | |
313 | ||
314 | struct bt_config | |
315 | { | |
316 | u_char chan; | |
317 | u_char intr; | |
318 | u_char scsi_dev:3; | |
319 | u_char :5; | |
320 | }; | |
321 | ||
322 | #define INT9 0x01 | |
323 | #define INT10 0x02 | |
324 | #define INT11 0x04 | |
325 | #define INT12 0x08 | |
326 | #define INT14 0x20 | |
327 | #define INT15 0x40 | |
328 | ||
329 | #define EISADMA 0x00 | |
330 | #define CHAN0 0x01 | |
331 | #define CHAN5 0x20 | |
332 | #define CHAN6 0x40 | |
333 | #define CHAN7 0x80 | |
334 | ||
335 | ||
336 | ||
337 | ||
338 | #ifdef MACH | |
339 | extern physaddr kvtophys(); | |
340 | #define PHYSTOKV(x) phystokv(x) | |
341 | #define KVTOPHYS(x) kvtophys(x) | |
342 | #endif MACH | |
343 | ||
344 | #ifdef __386BSD__ | |
15637ed4 RG |
345 | #define KVTOPHYS(x) vtophys(x) |
346 | #endif __386BSD__ | |
347 | ||
348 | ||
349 | ||
350 | #define PAGESIZ 4096 | |
351 | #define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } | |
352 | ||
353 | ||
354 | u_char bt_scratch_buf[256]; | |
355 | #ifdef MACH | |
356 | caddr_t bt_base[NBT]; /* base port for each board */ | |
357 | #else MACH | |
358 | short bt_base[NBT]; /* base port for each board */ | |
359 | #endif MACH | |
360 | struct bt_mbx bt_mbx[NBT]; | |
361 | struct bt_ccb *bt_ccb_free[NBT]; | |
78ed81a3 | 362 | struct bt_ccb bt_ccb[NBT][BT_CCB_SIZE]; |
15637ed4 RG |
363 | struct scsi_xfer bt_scsi_xfer[NBT]; |
364 | struct isa_dev *btinfo[NBT]; | |
365 | struct bt_ccb *bt_get_ccb(); | |
366 | int bt_int[NBT]; | |
367 | int bt_dma[NBT]; | |
368 | int bt_scsi_dev[NBT]; | |
369 | int bt_initialized[NBT]; | |
370 | #if defined(OSF) | |
371 | int bt_attached[NBT]; | |
372 | #endif /* defined(OSF) */ | |
373 | ||
374 | /***********debug values *************/ | |
375 | #define BT_SHOWCCBS 0x01 | |
376 | #define BT_SHOWINTS 0x02 | |
377 | #define BT_SHOWCMDS 0x04 | |
378 | #define BT_SHOWMISC 0x08 | |
379 | int bt_debug = 0; | |
380 | ||
381 | ||
382 | int btprobe(), btattach(); | |
383 | int btintr(); | |
384 | ||
385 | #ifdef MACH | |
386 | struct isa_driver btdriver = { btprobe, 0, btattach, "bt", 0, 0, 0}; | |
387 | int (*btintrs[])() = {btintr, 0}; | |
388 | #endif MACH | |
389 | ||
390 | #ifdef __386BSD__ | |
391 | struct isa_driver btdriver = { btprobe, btattach, "bt"}; | |
392 | #endif __386BSD__ | |
393 | ||
394 | static int btunit = 0; | |
395 | ||
15637ed4 RG |
396 | int bt_scsi_cmd(); |
397 | int bt_timeout(); | |
398 | void btminphys(); | |
399 | long int bt_adapter_info(); | |
400 | ||
401 | struct scsi_switch bt_switch = | |
402 | { | |
403 | bt_scsi_cmd, | |
404 | btminphys, | |
405 | 0, | |
406 | 0, | |
407 | bt_adapter_info, | |
78ed81a3 | 408 | "bt", |
409 | 0,0 | |
15637ed4 RG |
410 | }; |
411 | #define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ | |
412 | #define BT_RESET_TIMEOUT 1000000 | |
413 | #define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ | |
414 | ||
415 | ||
416 | /***********************************************************************\ | |
417 | * bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args) * | |
418 | * Activate Adapter command * | |
419 | * icnt: number of args (outbound bytes written after opcode) * | |
420 | * ocnt: number of expected returned bytes * | |
421 | * wait: number of seconds to wait for response * | |
422 | * retval: buffer where to place returned bytes * | |
423 | * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... * | |
424 | * args: parameters * | |
425 | * * | |
426 | * Performs an adapter command through the ports. Not to be confused * | |
427 | * with a scsi command, which is read in via the dma * | |
428 | * One of the adapter commands tells it to read in a scsi command * | |
429 | \***********************************************************************/ | |
430 | bt_cmd(unit,icnt, ocnt, wait,retval, opcode, args) | |
431 | ||
432 | u_char *retval; | |
433 | unsigned opcode; | |
434 | u_char args; | |
435 | { | |
436 | unsigned *ic = &opcode; | |
437 | u_char oc; | |
438 | register i; | |
439 | int sts; | |
440 | ||
441 | /*******************************************************\ | |
442 | * multiply the wait argument by a big constant * | |
443 | * zero defaults to 1 * | |
444 | \*******************************************************/ | |
445 | if(!wait) | |
446 | wait = BT_CMD_TIMEOUT_FUDGE * delaycount; | |
447 | else | |
448 | wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; | |
449 | /*******************************************************\ | |
450 | * Wait for the adapter to go idle, unless it's one of * | |
451 | * the commands which don't need this * | |
452 | \*******************************************************/ | |
453 | if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) | |
454 | { | |
455 | i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ | |
456 | while (--i) | |
457 | { | |
458 | sts = inb(BT_CTRL_STAT_PORT); | |
459 | if (sts & BT_IDLE) | |
460 | { | |
461 | break; | |
462 | } | |
463 | } | |
464 | if (!i) | |
465 | { | |
78ed81a3 | 466 | printf("bt%d: bt_cmd, host not idle(0x%x)\n",unit,sts); |
15637ed4 RG |
467 | return(ENXIO); |
468 | } | |
469 | } | |
470 | /*******************************************************\ | |
471 | * Now that it is idle, if we expect output, preflush the* | |
472 | * queue feeding to us. * | |
473 | \*******************************************************/ | |
474 | if (ocnt) | |
475 | { | |
476 | while((inb(BT_CTRL_STAT_PORT)) & BT_DF) | |
477 | inb(BT_CMD_DATA_PORT); | |
478 | } | |
479 | ||
480 | /*******************************************************\ | |
481 | * Output the command and the number of arguments given * | |
482 | * for each byte, first check the port is empty. * | |
483 | \*******************************************************/ | |
484 | icnt++; /* include the command */ | |
485 | while (icnt--) | |
486 | { | |
487 | sts = inb(BT_CTRL_STAT_PORT); | |
488 | for (i=0; i< wait; i++) | |
489 | { | |
490 | sts = inb(BT_CTRL_STAT_PORT); | |
491 | if (!(sts & BT_CDF)) | |
492 | break; | |
493 | } | |
494 | if (i >= wait) | |
495 | { | |
78ed81a3 | 496 | printf("bt%d: bt_cmd, cmd/data port full\n",unit); |
15637ed4 RG |
497 | outb(BT_CTRL_STAT_PORT, BT_SRST); |
498 | return(ENXIO); | |
499 | } | |
500 | outb(BT_CMD_DATA_PORT, (u_char)(*ic++)); | |
501 | } | |
502 | /*******************************************************\ | |
503 | * If we expect input, loop that many times, each time, * | |
504 | * looking for the data register to have valid data * | |
505 | \*******************************************************/ | |
506 | while (ocnt--) | |
507 | { | |
508 | sts = inb(BT_CTRL_STAT_PORT); | |
509 | for (i=0; i< wait; i++) | |
510 | { | |
511 | sts = inb(BT_CTRL_STAT_PORT); | |
512 | if (sts & BT_DF) | |
513 | break; | |
514 | } | |
515 | if (i >= wait) | |
516 | { | |
78ed81a3 | 517 | printf("bt%d: bt_cmd, cmd/data port empty %d\n", |
518 | unit,ocnt); | |
15637ed4 RG |
519 | return(ENXIO); |
520 | } | |
521 | oc = inb(BT_CMD_DATA_PORT); | |
522 | if (retval) | |
523 | *retval++ = oc; | |
524 | } | |
525 | /*******************************************************\ | |
526 | * Wait for the board to report a finised instruction * | |
527 | \*******************************************************/ | |
528 | i=BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ | |
529 | while (--i) | |
530 | { | |
531 | sts = inb(BT_INTR_PORT); | |
532 | if (sts & BT_HACC) | |
533 | { | |
534 | break; | |
535 | } | |
536 | } | |
537 | if (!i) | |
538 | { | |
78ed81a3 | 539 | printf("bt%d: bt_cmd, host not finished(0x%x)\n",unit,sts); |
15637ed4 RG |
540 | return(ENXIO); |
541 | } | |
542 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
543 | return(0); | |
544 | } | |
545 | ||
546 | /*******************************************************\ | |
547 | * Check if the device can be found at the port given * | |
548 | * and if so, set it up ready for further work * | |
549 | * as an argument, takes the isa_dev structure from * | |
550 | * autoconf.c * | |
551 | \*******************************************************/ | |
552 | ||
553 | btprobe(dev) | |
554 | struct isa_dev *dev; | |
555 | { | |
556 | /***********************************************\ | |
557 | * find unit and check we have that many defined * | |
558 | \***********************************************/ | |
559 | int unit = btunit; | |
560 | #if defined(OSF) | |
561 | static ihandler_t bt_handler[NBT]; | |
562 | static ihandler_id_t *bt_handler_id[NBT]; | |
563 | register ihandler_t *chp = &bt_handler[unit];; | |
564 | #endif /* defined(OSF) */ | |
565 | ||
566 | dev->dev_unit = unit; | |
567 | bt_base[unit] = dev->dev_addr; | |
568 | if(unit >= NBT) | |
569 | { | |
78ed81a3 | 570 | printf("bt%d: unit number too high\n",unit); |
15637ed4 RG |
571 | return(0); |
572 | } | |
573 | /***********************************************\ | |
574 | * Try initialise a unit at this location * | |
575 | * sets up dma and bus speed, loads bt_int[unit]* | |
576 | \***********************************************/ | |
577 | if (bt_init(unit) != 0) | |
578 | { | |
579 | return(0); | |
580 | } | |
581 | ||
582 | /***********************************************\ | |
583 | * If it's there, put in it's interrupt vectors * | |
584 | \***********************************************/ | |
585 | #ifdef MACH | |
78ed81a3 | 586 | dev->dev_pic = bt_int[unit]; |
15637ed4 RG |
587 | #if defined(OSF) /* OSF */ |
588 | chp->ih_level = dev->dev_pic; | |
589 | chp->ih_handler = dev->dev_intr[0]; | |
590 | chp->ih_resolver = i386_resolver; | |
591 | chp->ih_rdev = dev; | |
592 | chp->ih_stats.intr_type = INTR_DEVICE; | |
593 | chp->ih_stats.intr_cnt = 0; | |
594 | chp->ih_hparam[0].intparam = unit; | |
595 | if ((bt_handler_id[unit] = handler_add(chp)) != NULL) | |
596 | handler_enable(bt_handler_id[unit]); | |
597 | else | |
598 | panic("Unable to add bt interrupt handler"); | |
599 | #else /* CMU */ | |
15637ed4 RG |
600 | take_dev_irq(dev); |
601 | #endif /* !defined(OSF) */ | |
602 | printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl); | |
603 | #endif MACH | |
604 | #ifdef __386BSD__ /* 386BSD */ | |
605 | dev->id_irq = (1 << bt_int[unit]); | |
606 | dev->id_drq = bt_dma[unit]; | |
15637ed4 RG |
607 | #endif __386BSD__ |
608 | ||
609 | btunit++; | |
610 | return(1); | |
611 | } | |
612 | ||
613 | /***********************************************\ | |
614 | * Attach all the sub-devices we can find * | |
615 | \***********************************************/ | |
616 | btattach(dev) | |
617 | struct isa_dev *dev; | |
618 | { | |
619 | int unit = dev->dev_unit; | |
620 | ||
621 | ||
15637ed4 RG |
622 | /***********************************************\ |
623 | * ask the adapter what subunits are present * | |
624 | \***********************************************/ | |
625 | scsi_attachdevs( unit, bt_scsi_dev[unit], &bt_switch); | |
626 | #if defined(OSF) | |
627 | bt_attached[unit]=1; | |
628 | #endif /* defined(OSF) */ | |
15637ed4 RG |
629 | return; |
630 | } | |
631 | ||
632 | /***********************************************\ | |
633 | * Return some information to the caller about * | |
634 | * the adapter and it's capabilities * | |
635 | \***********************************************/ | |
636 | long int bt_adapter_info(unit) | |
637 | int unit; | |
638 | { | |
639 | return(2); /* 2 outstanding requests at a time per device */ | |
640 | } | |
641 | ||
642 | /***********************************************\ | |
643 | * Catch an interrupt from the adaptor * | |
644 | \***********************************************/ | |
645 | btintr(unit) | |
646 | { | |
78ed81a3 | 647 | BT_MBI *wmbi; |
648 | struct bt_mbx *wmbx; | |
15637ed4 RG |
649 | struct bt_ccb *ccb; |
650 | unsigned char stat; | |
78ed81a3 | 651 | int i,wait; |
652 | int found = 0; | |
15637ed4 | 653 | |
78ed81a3 | 654 | #ifdef UTEST |
15637ed4 RG |
655 | if(scsi_debug & PRINTROUTINES) |
656 | printf("btintr "); | |
78ed81a3 | 657 | #endif |
15637ed4 RG |
658 | /***********************************************\ |
659 | * First acknowlege the interrupt, Then if it's * | |
660 | * not telling about a completed operation * | |
661 | * just return. * | |
662 | \***********************************************/ | |
663 | stat = inb(BT_INTR_PORT); | |
78ed81a3 | 664 | |
665 | /* Mail Box out empty ? */ | |
666 | if ( stat & BT_MBOA ) { | |
667 | printf("bt%d: Available Free mbo post\n",unit); | |
668 | /* Disable MBO available interrupt */ | |
669 | outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); | |
670 | wait = BT_CMD_TIMEOUT_FUDGE * delaycount; | |
671 | for (i=0; i< wait; i++) | |
672 | { | |
673 | if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) | |
674 | break; | |
675 | } | |
676 | if (i >= wait) | |
677 | { | |
678 | printf("bt%d: bt_intr, cmd/data port full\n",unit); | |
679 | outb(BT_CTRL_STAT_PORT, BT_SRST); | |
680 | return 1; | |
681 | } | |
682 | outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ | |
683 | wakeup(&bt_mbx[unit]); | |
684 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
15637ed4 | 685 | return 1; |
78ed81a3 | 686 | } |
687 | if (! (stat & BT_MBIF)) { | |
688 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
689 | return 1; | |
690 | } | |
15637ed4 RG |
691 | #if defined(OSF) |
692 | if (!bt_attached[unit]) | |
693 | { | |
694 | return(1); | |
695 | } | |
696 | #endif /* defined(OSF) */ | |
697 | /***********************************************\ | |
698 | * If it IS then process the competed operation * | |
699 | \***********************************************/ | |
78ed81a3 | 700 | wmbx = &bt_mbx[unit]; |
701 | wmbi = wmbx->tmbi; | |
702 | AGAIN: | |
703 | while ( wmbi->stat != BT_MBI_FREE ) { | |
704 | found++; | |
705 | ccb = (struct bt_ccb *)PHYSTOKV((wmbi->ccb_addr)); | |
706 | if((stat = wmbi->stat) != BT_MBI_OK) | |
15637ed4 | 707 | { |
78ed81a3 | 708 | switch(stat) |
15637ed4 | 709 | { |
78ed81a3 | 710 | case BT_MBI_ABORT: |
711 | #ifdef UTEST | |
712 | if(bt_debug & BT_SHOWMISC) | |
713 | printf("abort "); | |
714 | #endif | |
715 | ccb->host_stat = BT_ABORTED; | |
716 | break; | |
15637ed4 | 717 | |
78ed81a3 | 718 | case BT_MBI_UNKNOWN: |
719 | ccb = (struct bt_ccb *)0; | |
720 | #ifdef UTEST | |
721 | if(bt_debug & BT_SHOWMISC) | |
722 | printf("unknown ccb for abort"); | |
723 | #endif | |
724 | break; | |
15637ed4 | 725 | |
78ed81a3 | 726 | case BT_MBI_ERROR: |
727 | break; | |
15637ed4 | 728 | |
78ed81a3 | 729 | default: |
730 | panic("Impossible mbxi status"); | |
15637ed4 | 731 | |
15637ed4 | 732 | } |
78ed81a3 | 733 | #ifdef UTEST |
734 | if((bt_debug & BT_SHOWCMDS ) && ccb) | |
15637ed4 | 735 | { |
78ed81a3 | 736 | u_char *cp; |
737 | cp = ccb->scsi_cmd; | |
738 | printf("op=%x %x %x %x %x %x\n", | |
739 | cp[0], cp[1], cp[2], | |
740 | cp[3], cp[4], cp[5]); | |
741 | printf("stat %x for mbi addr = 0x%08x\n" | |
742 | , wmbi->stat, wmbi ); | |
743 | printf("addr = 0x%x\n", ccb); | |
744 | } | |
745 | #endif | |
746 | } | |
747 | wmbi->stat = BT_MBI_FREE; | |
748 | if(ccb) | |
749 | { | |
750 | untimeout(bt_timeout,ccb); | |
751 | bt_done(unit,ccb); | |
752 | } | |
753 | ||
754 | /* Set the IN mail Box pointer for next */ | |
755 | bt_nextmbx( wmbi, wmbx, mbi ); | |
756 | } | |
757 | if ( !found ) { | |
758 | for ( i = 0; i < BT_MBX_SIZE; i++) { | |
759 | if ( wmbi->stat != BT_MBI_FREE ) { | |
760 | found ++; | |
761 | break; | |
15637ed4 | 762 | } |
78ed81a3 | 763 | bt_nextmbx( wmbi, wmbx, mbi ); |
764 | } | |
765 | if ( !found ) { | |
766 | printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n", | |
767 | unit, wmbi, stat ); | |
768 | } else { | |
769 | found = 0; | |
770 | goto AGAIN; | |
15637ed4 RG |
771 | } |
772 | } | |
78ed81a3 | 773 | wmbx->tmbi = wmbi; |
774 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
15637ed4 RG |
775 | return(1); |
776 | } | |
777 | ||
778 | /***********************************************\ | |
779 | * A ccb (and hence a mbx-out is put onto the * | |
780 | * free list. * | |
781 | \***********************************************/ | |
782 | bt_free_ccb(unit,ccb, flags) | |
783 | struct bt_ccb *ccb; | |
784 | { | |
785 | unsigned int opri; | |
78ed81a3 | 786 | |
787 | #ifdef UTEST | |
15637ed4 RG |
788 | if(scsi_debug & PRINTROUTINES) |
789 | printf("ccb%d(0x%x)> ",unit,flags); | |
78ed81a3 | 790 | #endif |
15637ed4 RG |
791 | if (!(flags & SCSI_NOMASK)) |
792 | opri = splbio(); | |
793 | ||
794 | ccb->next = bt_ccb_free[unit]; | |
795 | bt_ccb_free[unit] = ccb; | |
796 | ccb->flags = CCB_FREE; | |
797 | /***********************************************\ | |
798 | * If there were none, wake abybody waiting for * | |
799 | * one to come free, starting with queued entries* | |
800 | \***********************************************/ | |
801 | if (!ccb->next) { | |
802 | wakeup(&bt_ccb_free[unit]); | |
803 | } | |
804 | if (!(flags & SCSI_NOMASK)) | |
805 | splx(opri); | |
806 | } | |
807 | ||
808 | /***********************************************\ | |
78ed81a3 | 809 | * Get a free ccb * |
15637ed4 RG |
810 | \***********************************************/ |
811 | struct bt_ccb * | |
812 | bt_get_ccb(unit,flags) | |
813 | { | |
78ed81a3 | 814 | unsigned opri; |
15637ed4 | 815 | struct bt_ccb *rc; |
78ed81a3 | 816 | struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ |
817 | BT_MBO *wmbo; /* Out Mail Box pointer */ | |
15637ed4 | 818 | |
78ed81a3 | 819 | #ifdef UTEST |
15637ed4 RG |
820 | if(scsi_debug & PRINTROUTINES) |
821 | printf("<ccb%d(0x%x) ",unit,flags); | |
78ed81a3 | 822 | #endif |
15637ed4 RG |
823 | if (!(flags & SCSI_NOMASK)) |
824 | opri = splbio(); | |
825 | /***********************************************\ | |
826 | * If we can and have to, sleep waiting for one * | |
827 | * to come free * | |
828 | \***********************************************/ | |
829 | while ((!(rc = bt_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP))) | |
830 | { | |
831 | sleep(&bt_ccb_free[unit], PRIBIO); | |
832 | } | |
833 | if (rc) | |
834 | { | |
78ed81a3 | 835 | /* Get CCB from from free list */ |
15637ed4 RG |
836 | bt_ccb_free[unit] = rc->next; |
837 | rc->flags = CCB_ACTIVE; | |
78ed81a3 | 838 | #ifdef HE |
839 | /* Get the Target OUT mail Box pointer */ | |
840 | wmbx = &bt_mbx[unit]; | |
841 | wmbo = wmbx->tmbo; | |
842 | while ( wmbo->cmd != BT_MBO_FREE ) { | |
843 | /* Enable MBO available interrupt */ | |
844 | outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); | |
845 | printf("Wait free mbo.."); /* AMURAI */ | |
846 | sleep( wmbx, PRIBIO); | |
847 | printf("Got free mbo\n"); /* AMURAI */ | |
848 | } | |
849 | ||
850 | /* Link CCB to the Mail Box */ | |
851 | rc->mbx = wmbo; | |
852 | wmbo->ccb_addr = KVTOPHYS(rc); | |
853 | ||
854 | /* Set the OUT mail Box pointer for next */ | |
855 | bt_nextmbx( wmbo, wmbx, mbo ); | |
856 | wmbx->tmbo = wmbo; | |
857 | #endif | |
15637ed4 RG |
858 | } |
859 | if (!(flags & SCSI_NOMASK)) | |
860 | splx(opri); | |
78ed81a3 | 861 | |
15637ed4 RG |
862 | return(rc); |
863 | } | |
78ed81a3 | 864 | /***********************************************\ |
865 | * Get a MBO and then Send it * | |
866 | \***********************************************/ | |
867 | BT_MBO *bt_send_mbo( int unit, | |
868 | int flags, | |
869 | int cmd, | |
870 | struct bt_ccb *ccb ) | |
871 | { | |
872 | unsigned opri; | |
873 | BT_MBO *wmbo; /* Mail Box Out pointer */ | |
874 | struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ | |
875 | int i, wait; | |
15637ed4 | 876 | |
78ed81a3 | 877 | wmbx = &bt_mbx[unit]; |
878 | ||
879 | if (!(flags & SCSI_NOMASK)) | |
880 | opri = splbio(); | |
881 | ||
882 | /* Get the Target OUT mail Box pointer and move to Next */ | |
883 | wmbo = wmbx->tmbo; | |
884 | wmbx->tmbo = ( wmbo == &( wmbx->mbo[BT_MBX_SIZE - 1 ] ) ? | |
885 | &(wmbx->mbo[0]) : wmbo + 1 ); | |
886 | ||
887 | /* | |
888 | * Check the outmail box is free or not | |
889 | * Note: Under the normal operation, it shuld NOT happen to wait. | |
890 | */ | |
891 | while ( wmbo->cmd != BT_MBO_FREE ) { | |
892 | ||
893 | wait = BT_CMD_TIMEOUT_FUDGE * delaycount; | |
894 | /* Enable MBO available interrupt */ | |
895 | outb(BT_CMD_DATA_PORT,BT_MBO_INTR_EN); | |
896 | for (i=0; i< wait; i++) | |
897 | { | |
898 | if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) | |
899 | break; | |
900 | } | |
901 | if (i >= wait) | |
902 | { | |
903 | printf("bt%d: bt_send_mbo, cmd/data port full\n",unit); | |
904 | outb(BT_CTRL_STAT_PORT, BT_SRST); | |
905 | return( (BT_MBO *)0 ); | |
906 | } | |
907 | outb(BT_CMD_DATA_PORT, 0x01); /* Enable */ | |
908 | sleep( wmbx, PRIBIO); | |
909 | } | |
910 | ||
911 | /* Link CCB to the Mail Box */ | |
912 | wmbo->ccb_addr = KVTOPHYS(ccb); | |
913 | ccb->mbx = wmbo; | |
914 | wmbo->cmd = cmd; | |
915 | ||
916 | /* Send it ! */ | |
917 | outb(BT_CMD_DATA_PORT, BT_START_SCSI); | |
918 | ||
919 | if (!(flags & SCSI_NOMASK)) | |
920 | splx(opri); | |
921 | ||
922 | return(wmbo); | |
923 | } | |
15637ed4 RG |
924 | /***********************************************\ |
925 | * We have a ccb which has been processed by the * | |
926 | * adaptor, now we look to see how the operation * | |
927 | * went. Wake up the owner if waiting * | |
928 | \***********************************************/ | |
929 | bt_done(unit,ccb) | |
930 | struct bt_ccb *ccb; | |
931 | { | |
932 | struct scsi_sense_data *s1,*s2; | |
933 | struct scsi_xfer *xs = ccb->xfer; | |
934 | ||
78ed81a3 | 935 | #ifdef UTEST |
15637ed4 RG |
936 | if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) |
937 | printf("bt_done "); | |
78ed81a3 | 938 | #endif |
15637ed4 RG |
939 | /***********************************************\ |
940 | * Otherwise, put the results of the operation * | |
941 | * into the xfer and call whoever started it * | |
942 | \***********************************************/ | |
943 | if ( ( ccb->host_stat != BT_OK | |
944 | || ccb->target_stat != SCSI_OK) | |
945 | && (!(xs->flags & SCSI_ERR_OK))) | |
946 | { | |
947 | ||
948 | s1 = &(ccb->scsi_sense); | |
949 | s2 = &(xs->sense); | |
950 | ||
951 | if(ccb->host_stat) | |
952 | { | |
953 | switch(ccb->host_stat) | |
954 | { | |
955 | case BT_ABORTED: /* No response */ | |
956 | case BT_SEL_TIMEOUT: /* No response */ | |
78ed81a3 | 957 | #ifdef UTEST |
15637ed4 RG |
958 | if (bt_debug & BT_SHOWMISC) |
959 | { | |
960 | printf("timeout reported back\n"); | |
961 | } | |
78ed81a3 | 962 | #endif |
15637ed4 RG |
963 | xs->error = XS_TIMEOUT; |
964 | break; | |
965 | default: /* Other scsi protocol messes */ | |
966 | xs->error = XS_DRIVER_STUFFUP; | |
78ed81a3 | 967 | #ifdef UTEST |
15637ed4 RG |
968 | if (bt_debug & BT_SHOWMISC) |
969 | { | |
970 | printf("unexpected host_stat: %x\n", | |
971 | ccb->host_stat); | |
972 | } | |
78ed81a3 | 973 | #endif |
15637ed4 RG |
974 | } |
975 | ||
976 | } | |
977 | else | |
978 | { | |
979 | switch(ccb->target_stat) | |
980 | { | |
981 | case 0x02: | |
982 | /* structure copy!!!!!*/ | |
983 | *s2=*s1; | |
984 | xs->error = XS_SENSE; | |
985 | break; | |
986 | case 0x08: | |
987 | xs->error = XS_BUSY; | |
988 | break; | |
989 | default: | |
78ed81a3 | 990 | #ifdef UTEST |
15637ed4 RG |
991 | if (bt_debug & BT_SHOWMISC) |
992 | { | |
993 | printf("unexpected target_stat: %x\n", | |
994 | ccb->target_stat); | |
995 | } | |
78ed81a3 | 996 | #endif |
15637ed4 RG |
997 | xs->error = XS_DRIVER_STUFFUP; |
998 | } | |
999 | } | |
1000 | } | |
1001 | else /* All went correctly OR errors expected */ | |
1002 | { | |
1003 | xs->resid = 0; | |
1004 | } | |
1005 | xs->flags |= ITSDONE; | |
1006 | bt_free_ccb(unit,ccb, xs->flags); | |
1007 | if(xs->when_done) | |
1008 | (*(xs->when_done))(xs->done_arg,xs->done_arg2); | |
1009 | } | |
1010 | ||
1011 | /***********************************************\ | |
1012 | * Start the board, ready for normal operation * | |
1013 | \***********************************************/ | |
1014 | bt_init(unit) | |
1015 | int unit; | |
1016 | { | |
1017 | unsigned char ad[4]; | |
1018 | volatile int i,sts; | |
1019 | struct bt_config conf; | |
1020 | ||
1021 | /***********************************************\ | |
1022 | * reset board, If it doesn't respond, assume * | |
1023 | * that it's not there.. good for the probe * | |
1024 | \***********************************************/ | |
1025 | ||
1026 | outb(BT_CTRL_STAT_PORT, BT_HRST|BT_SRST); | |
1027 | ||
1028 | for (i=0; i < BT_RESET_TIMEOUT; i++) | |
1029 | { | |
1030 | sts = inb(BT_CTRL_STAT_PORT) ; | |
1031 | if ( sts == (BT_IDLE | BT_INIT)) | |
1032 | break; | |
1033 | } | |
1034 | if (i >= BT_RESET_TIMEOUT) | |
1035 | { | |
78ed81a3 | 1036 | #ifdef UTEST |
15637ed4 RG |
1037 | if (bt_debug & BT_SHOWMISC) |
1038 | printf("bt_init: No answer from bt742a board\n"); | |
78ed81a3 | 1039 | #endif |
15637ed4 RG |
1040 | return(ENXIO); |
1041 | } | |
1042 | ||
1043 | /***********************************************\ | |
1044 | * Assume we have a board at this stage * | |
1045 | * setup dma channel from jumpers and save int * | |
1046 | * level * | |
1047 | \***********************************************/ | |
1048 | #ifdef __386BSD__ | |
78ed81a3 | 1049 | printf("bt%d: reading board settings, ",unit); |
15637ed4 RG |
1050 | #else __386BSD__ |
1051 | printf("bt%d:",unit); | |
15637ed4 RG |
1052 | #endif __386BSD__ |
1053 | ||
1054 | bt_cmd(unit,0, sizeof(conf), 0 ,&conf, BT_CONF_GET); | |
1055 | switch(conf.chan) | |
1056 | { | |
1057 | case EISADMA: | |
1058 | bt_dma[unit] = -1; | |
15637ed4 RG |
1059 | break; |
1060 | case CHAN0: | |
1061 | outb(0x0b, 0x0c); | |
1062 | outb(0x0a, 0x00); | |
1063 | bt_dma[unit] = 0; | |
15637ed4 RG |
1064 | break; |
1065 | case CHAN5: | |
1066 | outb(0xd6, 0xc1); | |
1067 | outb(0xd4, 0x01); | |
1068 | bt_dma[unit] = 5; | |
15637ed4 RG |
1069 | break; |
1070 | case CHAN6: | |
1071 | outb(0xd6, 0xc2); | |
1072 | outb(0xd4, 0x02); | |
1073 | bt_dma[unit] = 6; | |
15637ed4 RG |
1074 | break; |
1075 | case CHAN7: | |
1076 | outb(0xd6, 0xc3); | |
1077 | outb(0xd4, 0x03); | |
1078 | bt_dma[unit] = 7; | |
15637ed4 RG |
1079 | break; |
1080 | default: | |
1081 | printf("illegal dma setting %x\n",conf.chan); | |
1082 | return(EIO); | |
1083 | } | |
78ed81a3 | 1084 | if (bt_dma[unit] == -1) |
1085 | printf("eisa dma, "); | |
1086 | else | |
1087 | printf("dma=%d, ",bt_dma[unit]); | |
1088 | ||
15637ed4 RG |
1089 | switch(conf.intr) |
1090 | { | |
1091 | case INT9: | |
1092 | bt_int[unit] = 9; | |
15637ed4 RG |
1093 | break; |
1094 | case INT10: | |
1095 | bt_int[unit] = 10; | |
15637ed4 RG |
1096 | break; |
1097 | case INT11: | |
1098 | bt_int[unit] = 11; | |
15637ed4 RG |
1099 | break; |
1100 | case INT12: | |
1101 | bt_int[unit] = 12; | |
15637ed4 RG |
1102 | break; |
1103 | case INT14: | |
1104 | bt_int[unit] = 14; | |
15637ed4 RG |
1105 | break; |
1106 | case INT15: | |
1107 | bt_int[unit] = 15; | |
15637ed4 RG |
1108 | break; |
1109 | default: | |
1110 | printf("illegal int setting\n"); | |
1111 | return(EIO); | |
1112 | } | |
78ed81a3 | 1113 | #ifdef __386BSD__ |
1114 | printf("int=%d\n",bt_int[unit]); | |
1115 | #else | |
1116 | printf("int=%d ",bt_int[unit]); | |
1117 | #endif __386BSD__ | |
1118 | ||
15637ed4 RG |
1119 | /* who are we on the scsi bus */ |
1120 | bt_scsi_dev[unit] = conf.scsi_dev; | |
1121 | /***********************************************\ | |
1122 | * Initialize mail box * | |
1123 | \***********************************************/ | |
15637ed4 RG |
1124 | *((physaddr *)ad) = KVTOPHYS(&bt_mbx[unit]); |
1125 | bt_cmd(unit,5, 0, 0, 0, BT_MBX_INIT_EXTENDED | |
1126 | , BT_MBX_SIZE | |
1127 | , ad[0] | |
1128 | , ad[1] | |
1129 | , ad[2] | |
1130 | , ad[3]); | |
1131 | ||
1132 | /***********************************************\ | |
78ed81a3 | 1133 | * Set Pointer chain null for just in case * |
1134 | * Link the ccb's into a free-list W/O mbox * | |
1135 | * Initilize Mail Box stat to Free * | |
15637ed4 | 1136 | \***********************************************/ |
78ed81a3 | 1137 | if ( bt_ccb_free[unit] != (struct bt_ccb *)0 ) { |
1138 | printf("bt%d: bt_ccb_free is NOT initialized but init here\n", | |
1139 | unit); | |
1140 | bt_ccb_free[unit] = (struct bt_ccb *)0; | |
1141 | } | |
1142 | for (i=0; i < BT_CCB_SIZE; i++) { | |
1143 | bt_ccb[unit][i].next = bt_ccb_free[unit]; | |
1144 | bt_ccb_free[unit] = &bt_ccb[unit][i]; | |
15637ed4 | 1145 | bt_ccb_free[unit]->flags = CCB_FREE; |
15637ed4 | 1146 | } |
78ed81a3 | 1147 | for (i=0; i < BT_MBX_SIZE; i++) { |
1148 | bt_mbx[unit].mbo[i].cmd = BT_MBO_FREE; | |
1149 | bt_mbx[unit].mbi[i].stat = BT_MBI_FREE; | |
1150 | } | |
1151 | ||
1152 | /***********************************************\ | |
1153 | * Set up Initial mail box for round-robin * | |
1154 | \***********************************************/ | |
1155 | bt_mbx[unit].tmbo = &bt_mbx[unit].mbo[0]; | |
1156 | bt_mbx[unit].tmbi = &bt_mbx[unit].mbi[0]; | |
1157 | bt_inquire_setup_information( unit ); | |
1158 | ||
1159 | /* Enable round-robin scheme - appeared at FirmWare 3.31 */ | |
1160 | bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE ); | |
15637ed4 RG |
1161 | |
1162 | /***********************************************\ | |
1163 | * Note that we are going and return (to probe) * | |
1164 | \***********************************************/ | |
1165 | bt_initialized[unit]++; | |
1166 | return( 0 ); | |
1167 | } | |
78ed81a3 | 1168 | bt_inquire_setup_information( unit ) |
1169 | int unit; | |
1170 | { | |
1171 | struct bt_setup setup; | |
1172 | struct bt_boardID bID; | |
1173 | int i; | |
1174 | ||
1175 | /* Inquire Board ID to Bt742 for FirmWare Version */ | |
1176 | bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE ); | |
1177 | printf("bt%d: version %c.%c, ", | |
1178 | unit, bID.firm_revision, bID.firm_version ); | |
1179 | ||
1180 | /* Ask setup information to Bt742 */ | |
1181 | bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup) ); | |
1182 | ||
1183 | if ( setup.sync_neg ) { | |
1184 | printf("sync, "); | |
1185 | } else { | |
1186 | printf("async, "); | |
1187 | } | |
1188 | ||
1189 | if ( setup.parity ) { | |
1190 | printf("parity, "); | |
1191 | } else { | |
1192 | printf("no parity, "); | |
1193 | } | |
1194 | ||
1195 | printf("%d mbxs, %d ccbs\n", setup.num_mbx, | |
1196 | sizeof(bt_ccb)/(sizeof(struct bt_ccb) * NBT) ); | |
1197 | ||
1198 | for ( i = 0; i < 8; i++ ) { | |
1199 | if( !setup.sync[i].offset && | |
1200 | !setup.sync[i].period && | |
1201 | !setup.sync[i].valid ) | |
1202 | continue; | |
1203 | ||
1204 | printf("bt%d: dev%02d Offset=%d,Transfer period=%d, Synchronous? %s", | |
1205 | unit, i, | |
1206 | setup.sync[i].offset, setup.sync[i].period, | |
1207 | setup.sync[i].valid ? "Yes" : "No" ); | |
1208 | } | |
1209 | ||
1210 | } | |
15637ed4 RG |
1211 | |
1212 | ||
1213 | #ifndef min | |
1214 | #define min(x,y) (x < y ? x : y) | |
1215 | #endif min | |
1216 | ||
1217 | ||
1218 | void btminphys(bp) | |
1219 | struct buf *bp; | |
1220 | { | |
1221 | #ifdef MACH | |
1222 | #if !defined(OSF) | |
1223 | bp->b_flags |= B_NPAGES; /* can support scat/gather */ | |
1224 | #endif /* defined(OSF) */ | |
1225 | #endif MACH | |
1226 | if(bp->b_bcount > ((BT_NSEG-1) * PAGESIZ)) | |
1227 | { | |
1228 | bp->b_bcount = ((BT_NSEG-1) * PAGESIZ); | |
1229 | } | |
1230 | } | |
1231 | ||
1232 | /***********************************************\ | |
1233 | * start a scsi operation given the command and * | |
1234 | * the data address. Also needs the unit, target * | |
1235 | * and lu * | |
1236 | \***********************************************/ | |
1237 | int bt_scsi_cmd(xs) | |
1238 | struct scsi_xfer *xs; | |
1239 | { | |
1240 | struct scsi_sense_data *s1,*s2; | |
1241 | struct bt_ccb *ccb; | |
1242 | struct bt_scat_gath *sg; | |
1243 | int seg; /* scatter gather seg being worked on */ | |
1244 | int i = 0; | |
1245 | int rc = 0; | |
1246 | int thiskv; | |
1247 | physaddr thisphys,nextphys; | |
1248 | int unit =xs->adapter; | |
1249 | int bytes_this_seg,bytes_this_page,datalen,flags; | |
1250 | struct iovec *iovp; | |
78ed81a3 | 1251 | BT_MBO *mbo; |
15637ed4 | 1252 | |
78ed81a3 | 1253 | #ifdef UTEST |
15637ed4 RG |
1254 | if(scsi_debug & PRINTROUTINES) |
1255 | printf("bt_scsi_cmd "); | |
78ed81a3 | 1256 | #endif |
15637ed4 RG |
1257 | /***********************************************\ |
1258 | * get a ccb (mbox-out) to use. If the transfer * | |
1259 | * is from a buf (possibly from interrupt time) * | |
1260 | * then we can't allow it to sleep * | |
1261 | \***********************************************/ | |
1262 | flags = xs->flags; | |
1263 | if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ | |
1264 | if(flags & ITSDONE) | |
1265 | { | |
78ed81a3 | 1266 | printf("bt%d: Already done?\n",unit); |
15637ed4 RG |
1267 | xs->flags &= ~ITSDONE; |
1268 | } | |
1269 | if(!(flags & INUSE)) | |
1270 | { | |
78ed81a3 | 1271 | printf("bt%d: Not in use?\n",unit); |
15637ed4 RG |
1272 | xs->flags |= INUSE; |
1273 | } | |
1274 | if (!(ccb = bt_get_ccb(unit,flags))) | |
1275 | { | |
1276 | xs->error = XS_DRIVER_STUFFUP; | |
1277 | return(TRY_AGAIN_LATER); | |
1278 | } | |
78ed81a3 | 1279 | #ifdef UTEST |
15637ed4 RG |
1280 | if(bt_debug & BT_SHOWCCBS) |
1281 | printf("<start ccb(%x)>",ccb); | |
78ed81a3 | 1282 | #endif |
15637ed4 RG |
1283 | /***********************************************\ |
1284 | * Put all the arguments for the xfer in the ccb * | |
1285 | \***********************************************/ | |
1286 | ccb->xfer = xs; | |
1287 | if(flags & SCSI_RESET) | |
1288 | { | |
1289 | ccb->opcode = BT_RESET_CCB; | |
1290 | } | |
1291 | else | |
1292 | { | |
1293 | /* can't use S/G if zero length */ | |
1294 | ccb->opcode = (xs->datalen? | |
1295 | BT_INIT_SCAT_GATH_CCB | |
1296 | :BT_INITIATOR_CCB); | |
1297 | } | |
1298 | ccb->target = xs->targ;; | |
1299 | ccb->data_out = 0; | |
1300 | ccb->data_in = 0; | |
1301 | ccb->lun = xs->lu; | |
1302 | ccb->scsi_cmd_length = xs->cmdlen; | |
1303 | ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); | |
1304 | ccb->req_sense_length = sizeof(ccb->scsi_sense); | |
1305 | ||
1306 | if((xs->datalen) && (!(flags & SCSI_RESET))) | |
1307 | { /* can use S/G only if not zero length */ | |
1308 | ccb->data_addr = KVTOPHYS(ccb->scat_gath); | |
1309 | sg = ccb->scat_gath ; | |
1310 | seg = 0; | |
1311 | if(flags & SCSI_DATA_UIO) | |
1312 | { | |
1313 | iovp = ((struct uio *)xs->data)->uio_iov; | |
1314 | datalen = ((struct uio *)xs->data)->uio_iovcnt; | |
1315 | xs->datalen = 0; | |
1316 | while ((datalen) && (seg < BT_NSEG)) | |
1317 | { | |
1318 | sg->seg_addr = (physaddr)iovp->iov_base; | |
1319 | xs->datalen += sg->seg_len = iovp->iov_len; | |
78ed81a3 | 1320 | #ifdef UTEST |
15637ed4 RG |
1321 | if(scsi_debug & SHOWSCATGATH) |
1322 | printf("(0x%x@0x%x)" | |
1323 | ,iovp->iov_len | |
1324 | ,iovp->iov_base); | |
78ed81a3 | 1325 | #endif |
15637ed4 RG |
1326 | sg++; |
1327 | iovp++; | |
1328 | seg++; | |
1329 | datalen--; | |
1330 | } | |
1331 | } | |
1332 | else | |
1333 | { | |
1334 | /***********************************************\ | |
1335 | * Set up the scatter gather block * | |
1336 | \***********************************************/ | |
1337 | ||
78ed81a3 | 1338 | #ifdef UTEST |
15637ed4 RG |
1339 | if(scsi_debug & SHOWSCATGATH) |
1340 | printf("%d @0x%x:- ",xs->datalen,xs->data); | |
78ed81a3 | 1341 | #endif |
15637ed4 RG |
1342 | datalen = xs->datalen; |
1343 | thiskv = (int)xs->data; | |
1344 | thisphys = KVTOPHYS(thiskv); | |
1345 | ||
1346 | while ((datalen) && (seg < BT_NSEG)) | |
1347 | { | |
1348 | bytes_this_seg = 0; | |
1349 | ||
1350 | /* put in the base address */ | |
1351 | sg->seg_addr = thisphys; | |
1352 | ||
78ed81a3 | 1353 | #ifdef UTEST |
15637ed4 RG |
1354 | if(scsi_debug & SHOWSCATGATH) |
1355 | printf("0x%x",thisphys); | |
78ed81a3 | 1356 | #endif |
15637ed4 RG |
1357 | |
1358 | /* do it at least once */ | |
1359 | nextphys = thisphys; | |
1360 | while ((datalen) && (thisphys == nextphys)) | |
1361 | /*********************************************\ | |
1362 | * This page is contiguous (physically) with * | |
1363 | * the the last, just extend the length * | |
1364 | \*********************************************/ | |
1365 | { | |
1366 | /* how far to the end of the page */ | |
1367 | nextphys= (thisphys & (~(PAGESIZ - 1))) | |
1368 | + PAGESIZ; | |
1369 | bytes_this_page = nextphys - thisphys; | |
1370 | /**** or the data ****/ | |
1371 | bytes_this_page = min(bytes_this_page | |
1372 | ,datalen); | |
1373 | bytes_this_seg += bytes_this_page; | |
1374 | datalen -= bytes_this_page; | |
1375 | ||
1376 | /* get more ready for the next page */ | |
1377 | thiskv = (thiskv & (~(PAGESIZ - 1))) | |
1378 | + PAGESIZ; | |
1379 | if(datalen) | |
1380 | thisphys = KVTOPHYS(thiskv); | |
1381 | } | |
1382 | /********************************************\ | |
1383 | * next page isn't contiguous, finish the seg * | |
1384 | \********************************************/ | |
78ed81a3 | 1385 | #ifdef UTEST |
15637ed4 RG |
1386 | if(scsi_debug & SHOWSCATGATH) |
1387 | printf("(0x%x)",bytes_this_seg); | |
78ed81a3 | 1388 | #endif |
15637ed4 RG |
1389 | sg->seg_len = bytes_this_seg; |
1390 | sg++; | |
1391 | seg++; | |
1392 | } | |
1393 | } /*end of iov/kv decision */ | |
1394 | ccb->data_length = seg * sizeof(struct bt_scat_gath); | |
78ed81a3 | 1395 | #ifdef UTEST |
15637ed4 RG |
1396 | if(scsi_debug & SHOWSCATGATH) |
1397 | printf("\n"); | |
78ed81a3 | 1398 | #endif |
15637ed4 RG |
1399 | if (datalen) |
1400 | { /* there's still data, must have run out of segs! */ | |
78ed81a3 | 1401 | printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n", |
15637ed4 RG |
1402 | unit,BT_NSEG); |
1403 | xs->error = XS_DRIVER_STUFFUP; | |
1404 | bt_free_ccb(unit,ccb,flags); | |
1405 | return(HAD_ERROR); | |
1406 | } | |
1407 | ||
1408 | } | |
1409 | else | |
1410 | { /* No data xfer, use non S/G values */ | |
1411 | ccb->data_addr = (physaddr)0; | |
1412 | ccb->data_length = 0; | |
1413 | } | |
1414 | ccb->link_id = 0; | |
1415 | ccb->link_addr = (physaddr)0; | |
1416 | /***********************************************\ | |
1417 | * Put the scsi command in the ccb and start it * | |
1418 | \***********************************************/ | |
1419 | if(!(flags & SCSI_RESET)) | |
1420 | { | |
1421 | bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); | |
1422 | } | |
78ed81a3 | 1423 | #ifdef UTEST |
15637ed4 RG |
1424 | if(scsi_debug & SHOWCOMMANDS) |
1425 | { | |
1426 | u_char *b = ccb->scsi_cmd; | |
1427 | if(!(flags & SCSI_RESET)) | |
1428 | { | |
1429 | int i = 0; | |
1430 | printf("bt%d:%d:%d-" | |
1431 | ,unit | |
1432 | ,ccb->target | |
1433 | ,ccb->lun); | |
1434 | while(i < ccb->scsi_cmd_length ) | |
1435 | { | |
1436 | if(i) printf(","); | |
1437 | printf("%x",b[i++]); | |
1438 | } | |
1439 | printf("-\n"); | |
1440 | } | |
1441 | else | |
1442 | { | |
1443 | printf("bt%d:%d:%d-RESET- " | |
1444 | ,unit | |
1445 | ,ccb->target | |
1446 | ,ccb->lun | |
1447 | ); | |
1448 | } | |
1449 | } | |
78ed81a3 | 1450 | #endif |
1451 | if ( bt_send_mbo( unit, flags, BT_MBO_START, ccb ) == (BT_MBO *)0 ) | |
1452 | { | |
1453 | xs->error = XS_DRIVER_STUFFUP; | |
1454 | bt_free_ccb(unit,ccb,flags); | |
1455 | return(TRY_AGAIN_LATER); | |
1456 | } | |
15637ed4 RG |
1457 | /***********************************************\ |
1458 | * Usually return SUCCESSFULLY QUEUED * | |
1459 | \***********************************************/ | |
78ed81a3 | 1460 | #ifdef UTEST |
15637ed4 RG |
1461 | if(scsi_debug & TRACEINTERRUPTS) |
1462 | printf("cmd_sent "); | |
78ed81a3 | 1463 | #endif |
15637ed4 RG |
1464 | if (!(flags & SCSI_NOMASK)) |
1465 | { | |
78ed81a3 | 1466 | timeout(bt_timeout,ccb,(xs->timeout * hz) / 1000); |
15637ed4 | 1467 | return(SUCCESSFULLY_QUEUED); |
78ed81a3 | 1468 | } else |
15637ed4 RG |
1469 | /***********************************************\ |
1470 | * If we can't use interrupts, poll on completion* | |
1471 | \***********************************************/ | |
1472 | { | |
1473 | int done = 0; | |
1474 | int count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE; | |
78ed81a3 | 1475 | struct bt_mbx *wmbx = &bt_mbx[unit]; |
1476 | BT_MBI *wmbi = wmbx->tmbi; | |
1477 | unsigned char stat; | |
1478 | #ifdef UTEST | |
15637ed4 RG |
1479 | if(scsi_debug & TRACEINTERRUPTS) |
1480 | printf("wait "); | |
78ed81a3 | 1481 | #endif |
15637ed4 RG |
1482 | while((!done) && count) |
1483 | { | |
78ed81a3 | 1484 | stat = inb(BT_INTR_PORT) & (BT_ANY_INTR | BT_MBIF ); |
1485 | if ( !( stat & BT_ANY_INTR ) || | |
1486 | ( wmbi->stat == BT_MBI_FREE )|| | |
1487 | (PHYSTOKV(wmbi->ccb_addr) | |
1488 | != (int)ccb ) ) { | |
1489 | count--; | |
1490 | continue; | |
15637ed4 | 1491 | } |
78ed81a3 | 1492 | wmbi->stat = BT_MBI_FREE; |
1493 | bt_done(unit,ccb); | |
1494 | done ++; | |
1495 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
1496 | /* Set the IN mail Box pointer for next */ | |
1497 | bt_nextmbx( wmbi, wmbx, mbi ); | |
1498 | wmbx->tmbi = wmbi; | |
15637ed4 | 1499 | } |
78ed81a3 | 1500 | if (!count && !done) |
15637ed4 | 1501 | { |
78ed81a3 | 1502 | #ifdef UTEST |
15637ed4 RG |
1503 | if (!(xs->flags & SCSI_SILENT)) |
1504 | printf("cmd fail\n"); | |
78ed81a3 | 1505 | #endif |
1506 | bt_send_mbo( unit, flags, BT_MBO_ABORT, ccb ); | |
15637ed4 RG |
1507 | count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE; |
1508 | while((!done) && count) | |
1509 | { | |
78ed81a3 | 1510 | if ( !( stat & BT_ANY_INTR ) || |
1511 | ( wmbi->stat == BT_MBI_FREE )|| | |
1512 | ( PHYSTOKV(wmbi->ccb_addr ) | |
1513 | != (int)ccb ) ) { | |
1514 | count--; | |
1515 | continue; | |
15637ed4 | 1516 | } |
78ed81a3 | 1517 | wmbi->stat = BT_MBI_FREE; |
1518 | bt_done(unit,ccb); | |
1519 | done ++; | |
1520 | outb(BT_CTRL_STAT_PORT, BT_IRST); | |
1521 | /* Set the IN mail Box pointer for next */ | |
1522 | bt_nextmbx( wmbi, wmbx, mbi ); | |
1523 | wmbx->tmbi = wmbi; | |
15637ed4 | 1524 | } |
78ed81a3 | 1525 | if(!count && !done) |
15637ed4 | 1526 | { |
78ed81a3 | 1527 | printf("bt%d: abort failed in wait\n", unit); |
15637ed4 RG |
1528 | ccb->mbx->cmd = BT_MBO_FREE; |
1529 | } | |
1530 | bt_free_ccb(unit,ccb,flags); | |
15637ed4 RG |
1531 | xs->error = XS_DRIVER_STUFFUP; |
1532 | return(HAD_ERROR); | |
1533 | } | |
15637ed4 RG |
1534 | if(xs->error) return(HAD_ERROR); |
1535 | return(COMPLETE); | |
15637ed4 | 1536 | } |
15637ed4 RG |
1537 | } |
1538 | ||
1539 | ||
78ed81a3 | 1540 | bt_timeout(struct bt_ccb *ccb) |
15637ed4 | 1541 | { |
15637ed4 RG |
1542 | int unit; |
1543 | int s = splbio(); | |
1544 | ||
78ed81a3 | 1545 | unit = ccb->xfer->adapter; |
1546 | printf("bt%d: %d device timed out\n",unit | |
1547 | ,ccb->xfer->targ); | |
1548 | #ifdef UTEST | |
1549 | if(bt_debug & BT_SHOWCCBS) | |
1550 | bt_print_active_ccbs(unit); | |
1551 | #endif | |
1552 | ||
1553 | /***************************************\ | |
1554 | * If The ccb's mbx is not free, then * | |
1555 | * the board has gone Far East ? * | |
1556 | \***************************************/ | |
1557 | if((struct bt_ccb *)PHYSTOKV(ccb->mbx->ccb_addr)==ccb && | |
1558 | ccb->mbx->cmd != BT_MBO_FREE ) | |
15637ed4 | 1559 | { |
78ed81a3 | 1560 | printf("bt%d: not taking commands!\n" |
1561 | ,unit); | |
1562 | Debugger(); | |
1563 | } | |
1564 | /***************************************\ | |
1565 | * If it has been through before, then * | |
1566 | * a previous abort has failed, don't * | |
1567 | * try abort again * | |
1568 | \***************************************/ | |
1569 | if(ccb->flags == CCB_ABORTED) /* abort timed out */ | |
1570 | { | |
1571 | printf("bt%d: Abort Operation has timed out\n",unit); | |
1572 | ccb->xfer->retries = 0; /* I MEAN IT ! */ | |
1573 | ccb->host_stat = BT_ABORTED; | |
1574 | bt_done(unit,ccb); | |
1575 | } | |
1576 | else /* abort the operation that has timed out */ | |
1577 | { | |
1578 | printf("bt%d: Try to abort\n",unit); | |
1579 | bt_send_mbo( unit, ~SCSI_NOMASK, | |
1580 | BT_MBO_ABORT, ccb ); | |
1581 | /* 2 secs for the abort */ | |
1582 | timeout(bt_timeout,ccb,2 * hz); | |
1583 | ccb->flags = CCB_ABORTED; | |
15637ed4 RG |
1584 | } |
1585 | splx(s); | |
15637ed4 RG |
1586 | } |
1587 | ||
78ed81a3 | 1588 | #ifdef UTEST |
1589 | bt_print_ccb(ccb) | |
15637ed4 RG |
1590 | struct bt_ccb *ccb; |
1591 | { | |
1592 | printf("ccb:%x op:%x cmdlen:%d senlen:%d\n" | |
1593 | ,ccb | |
1594 | ,ccb->opcode | |
1595 | ,ccb->scsi_cmd_length | |
1596 | ,ccb->req_sense_length); | |
78ed81a3 | 1597 | printf(" datlen:%d hstat:%x tstat:%x flags:%x\n" |
15637ed4 RG |
1598 | ,ccb->data_length |
1599 | ,ccb->host_stat | |
1600 | ,ccb->target_stat | |
15637ed4 RG |
1601 | ,ccb->flags); |
1602 | } | |
1603 | ||
78ed81a3 | 1604 | bt_print_active_ccbs(int unit) |
15637ed4 RG |
1605 | { |
1606 | struct bt_ccb *ccb; | |
78ed81a3 | 1607 | ccb = &(bt_ccb[unit][0]); |
1608 | int i = BT_CCB_SIZE; | |
15637ed4 | 1609 | |
78ed81a3 | 1610 | while(i--) |
15637ed4 | 1611 | { |
78ed81a3 | 1612 | if(ccb->flags != CCB_FREE) |
1613 | bt_print_ccb(ccb); | |
1614 | ccb++; | |
15637ed4 | 1615 | } |
15637ed4 | 1616 | } |
78ed81a3 | 1617 | #endif /*UTEST*/ |