Add big and ugly warning to users of lpa that
[unix-history] / sys / i386 / isa / aha1542.c
CommitLineData
15637ed4
RG
1/*
2 * (Mostly) 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 *
8387479d 15 * $Id: aha1542.c,v 1.22 1994/03/20 00:29:58 wollman Exp $
15637ed4
RG
16 */
17
18/*
19 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
20 */
21
15637ed4 22#include <sys/types.h>
519fb2b7 23#ifdef KERNEL /* don't laugh.. look for main() */
15637ed4
RG
24#include <aha.h>
25
26#include <sys/param.h>
27#include <sys/systm.h>
28#include <sys/errno.h>
29#include <sys/ioctl.h>
519fb2b7 30#include <sys/malloc.h>
15637ed4
RG
31#include <sys/buf.h>
32#include <sys/proc.h>
33#include <sys/user.h>
15637ed4 34#include <i386/isa/isa_device.h>
519fb2b7 35#endif /* KERNEL */
15637ed4
RG
36#include <scsi/scsi_all.h>
37#include <scsi/scsiconf.h>
15637ed4 38
519fb2b7 39#ifdef KERNEL
15637ed4 40#include "ddb.h"
fde1aeb2 41#include "kernel.h"
519fb2b7
RG
42#else /*KERNEL */
43#define NAHA 1
44#endif /*KERNEL */
15637ed4
RG
45
46/************************** board definitions *******************************/
519fb2b7 47
15637ed4
RG
48/*
49 * I/O Port Interface
50 */
51
519fb2b7 52#define AHA_BASE aha->aha_base
15637ed4
RG
53#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */
54#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */
55#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */
56
57/*
58 * AHA_CTRL_STAT bits (write)
59 */
60
61#define AHA_HRST 0x80 /* Hardware reset */
62#define AHA_SRST 0x40 /* Software reset */
63#define AHA_IRST 0x20 /* Interrupt reset */
64#define AHA_SCRST 0x10 /* SCSI bus reset */
65
66/*
67 * AHA_CTRL_STAT bits (read)
68 */
69
70#define AHA_STST 0x80 /* Self test in Progress */
71#define AHA_DIAGF 0x40 /* Diagnostic Failure */
72#define AHA_INIT 0x20 /* Mbx Init required */
73#define AHA_IDLE 0x10 /* Host Adapter Idle */
74#define AHA_CDF 0x08 /* cmd/data out port full */
75#define AHA_DF 0x04 /* Data in port full */
76#define AHA_INVDCMD 0x01 /* Invalid command */
77
78/*
79 * AHA_CMD_DATA bits (write)
80 */
81
82#define AHA_NOP 0x00 /* No operation */
83#define AHA_MBX_INIT 0x01 /* Mbx initialization */
84#define AHA_START_SCSI 0x02 /* start scsi command */
85#define AHA_START_BIOS 0x03 /* start bios command */
86#define AHA_INQUIRE 0x04 /* Adapter Inquiry */
87#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
88#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
89#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
90#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
91#define AHA_SPEED_SET 0x09 /* set transfer speed */
92#define AHA_DEV_GET 0x0a /* return installed devices */
93#define AHA_CONF_GET 0x0b /* return configuration data */
94#define AHA_TARGET_EN 0x0c /* enable target mode */
95#define AHA_SETUP_GET 0x0d /* return setup data */
96#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */
97#define AHA_READ_CH2 0x1b /* read channel 2 buffer */
98#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */
99#define AHA_READ_FIFO 0x1d /* read fifo buffer */
100#define AHA_ECHO 0x1e /* Echo command data */
b9f44595
RG
101#define AHA_EXT_BIOS 0x28 /* return extended bios info */
102#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */
15637ed4
RG
103
104struct aha_cmd_buf {
519fb2b7 105 u_char byte[16];
15637ed4
RG
106};
107
108/*
109 * AHA_INTR_PORT bits (read)
110 */
111
112#define AHA_ANY_INTR 0x80 /* Any interrupt */
113#define AHA_SCRD 0x08 /* SCSI reset detected */
114#define AHA_HACC 0x04 /* Command complete */
115#define AHA_MBOA 0x02 /* MBX out empty */
116#define AHA_MBIF 0x01 /* MBX in full */
117
118/*
119 * Mail box defs
120 */
121
122#define AHA_MBX_SIZE 16 /* mail box size */
123
124struct aha_mbx {
125 struct aha_mbx_out {
126 unsigned char cmd;
127 unsigned char ccb_addr[3];
519fb2b7
RG
128 } mbo[AHA_MBX_SIZE];
129 struct aha_mbx_in {
15637ed4
RG
130 unsigned char stat;
131 unsigned char ccb_addr[3];
132 } mbi[AHA_MBX_SIZE];
133};
134
135/*
136 * mbo.cmd values
137 */
138
139#define AHA_MBO_FREE 0x0 /* MBO entry is free */
140#define AHA_MBO_START 0x1 /* MBO activate entry */
141#define AHA_MBO_ABORT 0x2 /* MBO abort entry */
142
519fb2b7
RG
143/*
144 * mbi.stat values
145 */
146
15637ed4
RG
147#define AHA_MBI_FREE 0x0 /* MBI entry is free */
148#define AHA_MBI_OK 0x1 /* completed without error */
149#define AHA_MBI_ABORT 0x2 /* aborted ccb */
150#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
151#define AHA_MBI_ERROR 0x4 /* Completed with error */
152
15637ed4
RG
153/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
154#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
155 /* allow 64 K i/o (min) */
156
157struct aha_ccb {
519fb2b7
RG
158 unsigned char opcode;
159 unsigned char lun:3;
160 unsigned char data_in:1; /* must be 0 */
161 unsigned char data_out:1; /* must be 0 */
162 unsigned char target:3;
163 unsigned char scsi_cmd_length;
164 unsigned char req_sense_length;
165 unsigned char data_length[3];
166 unsigned char data_addr[3];
167 unsigned char link_addr[3];
168 unsigned char link_id;
169 unsigned char host_stat;
170 unsigned char target_stat;
171 unsigned char reserved[2];
172 struct scsi_generic scsi_cmd;
173 struct scsi_sense_data scsi_sense;
174 struct aha_scat_gath {
15637ed4
RG
175 unsigned char seg_len[3];
176 unsigned char seg_addr[3];
177 } scat_gath[AHA_NSEG];
519fb2b7
RG
178 struct aha_ccb *next;
179 struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
180 struct aha_mbx_out *mbx; /* pointer to mail box */
181 int flags;
15637ed4
RG
182#define CCB_FREE 0
183#define CCB_ACTIVE 1
184#define CCB_ABORTED 2
15637ed4
RG
185};
186
15637ed4
RG
187/*
188 * opcode fields
189 */
190
191#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
192#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */
519fb2b7 193#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */
15637ed4
RG
194#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */
195
15637ed4
RG
196/*
197 * aha_ccb.host_stat values
198 */
199
200#define AHA_OK 0x00 /* cmd ok */
201#define AHA_LINK_OK 0x0a /* Link cmd ok */
202#define AHA_LINK_IT 0x0b /* Link cmd ok + int */
203#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */
204#define AHA_OVER_UNDER 0x12 /* Data over/under run */
205#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
206#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
207#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
208#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
209#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */
210#define AHA_INV_TARGET 0x18 /* Invalid target direction */
211#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */
212#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */
213#define AHA_ABORTED 42
214
519fb2b7
RG
215struct aha_setup {
216 u_char sync_neg:1;
217 u_char parity:1;
218 u_char:6;
219 u_char speed;
220 u_char bus_on;
221 u_char bus_off;
222 u_char num_mbx;
223 u_char mbx[3];
224 struct {
225 u_char offset:4;
226 u_char period:3;
227 u_char valid:1;
228 } sync[8];
229 u_char disc_sts;
15637ed4
RG
230};
231
519fb2b7
RG
232struct aha_config {
233 u_char chan;
234 u_char intr;
235 u_char scsi_dev:3;
236 u_char:5;
15637ed4
RG
237};
238
b9f44595
RG
239struct aha_inquire
240{
241 u_char boardid; /* type of board */
242 /* 0x20 = BusLogic 545, but it gets
243 the command wrong, only returns
244 one byte */
245 /* 0x31 = AHA-1540 */
246 /* 0x41 = AHA-1540A/1542A/1542B */
247 /* 0x42 = AHA-1640 */
248 /* 0x43 = AHA-1542C */
249 /* 0x44 = AHA-1542CF */
03c8dd07 250 /* 0x45 = AHA-1542CF, BIOS v2.01 */
b9f44595
RG
251 u_char spec_opts; /* special options ID */
252 /* 0x41 = Board is standard model */
253 u_char revision_1; /* firmware revision [0-9A-Z] */
254 u_char revision_2; /* firmware revision [0-9A-Z] */
255};
256
257struct aha_extbios
258{
259 u_char flags; /* Bit 3 == 1 extended bios enabled */
260 u_char mailboxlock; /* mail box lock code to unlock it */
261};
262
15637ed4
RG
263#define INT9 0x01
264#define INT10 0x02
265#define INT11 0x04
266#define INT12 0x08
267#define INT14 0x20
268#define INT15 0x40
269
270#define CHAN0 0x01
271#define CHAN5 0x20
272#define CHAN6 0x40
273#define CHAN7 0x80
274
15637ed4
RG
275/*********************************** end of board definitions***************/
276
519fb2b7 277#define PHYSTOKV(x) (((long int)(x)) ^ aha->kv_phys_xor)
15637ed4 278#define KVTOPHYS(x) vtophys(x)
15637ed4
RG
279#define AHA_DMA_PAGES AHA_NSEG
280
281#define PAGESIZ 4096
282#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
283
519fb2b7 284u_char aha_scratch_buf[256];
b33502d5 285#ifdef AHADEBUG
519fb2b7
RG
286int aha_debug = 1;
287#endif /*AHADEBUG */
15637ed4 288
519fb2b7
RG
289struct aha_data {
290 short aha_base; /* base port for each board */
291 /*
292 * xor this with a physaddr to get a kv addr and visa versa
293 * for items in THIS STRUCT only.
294 * Used to get the CCD's physical and kv addresses from each
295 * other.
296 */
297 long int kv_phys_xor;
298 struct aha_mbx aha_mbx; /* all the mailboxes */
299 struct aha_ccb *aha_ccb_free; /* the next free ccb */
300 struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */
301 int aha_int; /* our irq level */
302 int aha_dma; /* out DMA req channel */
303 int aha_scsi_dev; /* ourscsi bus address */
304 struct scsi_link sc_link; /* prototype for subdevs */
305} *ahadata[NAHA];
306
307struct aha_ccb *aha_get_ccb();
308int ahaprobe();
309void aha_done();
310int ahaattach();
311int ahaintr();
312int32 aha_scsi_cmd();
4c45483e 313void aha_timeout(caddr_t, int);
519fb2b7
RG
314void ahaminphys();
315u_int32 aha_adapter_info();
316
317#ifdef KERNEL
318struct scsi_adapter aha_switch =
319{
320 aha_scsi_cmd,
321 ahaminphys,
322 0,
323 0,
324 aha_adapter_info,
325 "aha",
326 0, 0
327};
328
329/* the below structure is so we have a default dev struct for out link struct */
330struct scsi_device aha_dev =
331{
332 NULL, /* Use default error handler */
333 NULL, /* have a queue, served by this */
334 NULL, /* have no async handler */
335 NULL, /* Use default 'done' routine */
336 "aha",
337 0,
338 0, 0
339};
15637ed4 340
519fb2b7
RG
341struct isa_driver ahadriver =
342{
343 ahaprobe,
344 ahaattach,
345 "aha"
346};
347
348#endif /* KERNEL */
349
350static int ahaunit = 0;
15637ed4
RG
351
352#define aha_abortmbx(mbx) \
353 (mbx)->cmd = AHA_MBO_ABORT; \
354 outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
355#define aha_startmbx(mbx) \
356 (mbx)->cmd = AHA_MBO_START; \
357 outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
358
02aedfed 359#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
519fb2b7
RG
360#ifndef KERNEL
361main()
362{
363 printf("size of aha_data is %d\n", sizeof(struct aha_data));
364 printf("size of aha_ccb is %d\n", sizeof(struct aha_ccb));
365 printf("size of aha_mbx is %d\n", sizeof(struct aha_mbx));
366}
15637ed4 367
519fb2b7 368#else /*KERNEL */
15637ed4 369
519fb2b7
RG
370/*
371 * aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
372 * Activate Adapter command
373 * icnt: number of args (outbound bytes written after opcode)
374 * ocnt: number of expected returned bytes
375 * wait: number of seconds to wait for response
376 * retval: buffer where to place returned bytes
377 * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ...
378 * args: parameters
379 *
380 * Performs an adapter command through the ports. Not to be confused
381 * with a scsi command, which is read in via the dma. One of the adapter
382 * commands tells it to read in a scsi command but that one is done
383 * separately. This is only called during set-up.
384 */
385int
386aha_cmd(unit, icnt, ocnt, wait, retval, opcode, args)
4c45483e
GW
387 int unit;
388 int icnt;
389 int ocnt;
390 int wait;
519fb2b7
RG
391 u_char *retval;
392 unsigned opcode;
393 u_char args;
15637ed4 394{
519fb2b7 395 struct aha_data *aha = ahadata[unit];
15637ed4 396 unsigned *ic = &opcode;
519fb2b7 397 u_char oc;
15637ed4 398 register i;
519fb2b7
RG
399 int sts;
400
401 /*
402 * multiply the wait argument by a big constant
403 * zero defaults to 1 sec..
404 * all wait loops are in 50uSec cycles
405 */
406 if (wait)
407 wait *= 20000;
15637ed4 408 else
519fb2b7
RG
409 wait = 20000;
410 /*
411 * Wait for the adapter to go idle, unless it's one of
412 * the commands which don't need this
413 */
414 if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) {
415 i = 20000; /*do this for upto about a second */
416 while (--i) {
15637ed4 417 sts = inb(AHA_CTRL_STAT_PORT);
519fb2b7 418 if (sts & AHA_IDLE) {
15637ed4
RG
419 break;
420 }
519fb2b7 421 DELAY(50);
15637ed4 422 }
519fb2b7 423 if (!i) {
98639498 424 printf("aha%d: aha_cmd, host not idle(0x%x)\n",
519fb2b7
RG
425 unit, sts);
426 return (ENXIO);
15637ed4
RG
427 }
428 }
519fb2b7
RG
429 /*
430 * Now that it is idle, if we expect output, preflush the
431 * queue feeding to us.
432 */
433 if (ocnt) {
434 while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
15637ed4
RG
435 inb(AHA_CMD_DATA_PORT);
436 }
519fb2b7
RG
437 /*
438 * Output the command and the number of arguments given
439 * for each byte, first check the port is empty.
440 */
441 icnt++;
442 /* include the command */
443 while (icnt--) {
15637ed4 444 sts = inb(AHA_CTRL_STAT_PORT);
519fb2b7 445 for (i = wait; i; i--) {
15637ed4
RG
446 sts = inb(AHA_CTRL_STAT_PORT);
447 if (!(sts & AHA_CDF))
448 break;
519fb2b7 449 DELAY(50);
15637ed4 450 }
519fb2b7
RG
451 if (i == 0) {
452 printf("aha%d: aha_cmd, cmd/data port full\n", unit);
453 outb(AHA_CTRL_STAT_PORT, AHA_SRST);
454 return (ENXIO);
15637ed4 455 }
519fb2b7 456 outb(AHA_CMD_DATA_PORT, (u_char) (*ic++));
15637ed4 457 }
519fb2b7
RG
458 /*
459 * If we expect input, loop that many times, each time,
460 * looking for the data register to have valid data
461 */
462 while (ocnt--) {
15637ed4 463 sts = inb(AHA_CTRL_STAT_PORT);
519fb2b7 464 for (i = wait; i; i--) {
15637ed4 465 sts = inb(AHA_CTRL_STAT_PORT);
519fb2b7 466 if (sts & AHA_DF)
15637ed4 467 break;
519fb2b7 468 DELAY(50);
15637ed4 469 }
519fb2b7 470 if (i == 0) {
98639498 471 printf("aha%d: aha_cmd, cmd/data port empty %d\n",
519fb2b7
RG
472 unit, ocnt);
473 return (ENXIO);
15637ed4
RG
474 }
475 oc = inb(AHA_CMD_DATA_PORT);
476 if (retval)
477 *retval++ = oc;
478 }
519fb2b7
RG
479 /*
480 * Wait for the board to report a finised instruction
481 */
482 i = 20000;
483 while (--i) {
15637ed4 484 sts = inb(AHA_INTR_PORT);
519fb2b7 485 if (sts & AHA_HACC) {
15637ed4
RG
486 break;
487 }
519fb2b7 488 DELAY(50);
15637ed4 489 }
519fb2b7
RG
490 if (i == 0) {
491 printf("aha%d: aha_cmd, host not finished(0x%x)\n", unit, sts);
492 return (ENXIO);
15637ed4
RG
493 }
494 outb(AHA_CTRL_STAT_PORT, AHA_IRST);
519fb2b7 495 return 0;
15637ed4
RG
496}
497
519fb2b7
RG
498/*
499 * Check if the device can be found at the port given
500 * and if so, set it up ready for further work
501 * as an argument, takes the isa_device structure from
502 * autoconf.c
503 */
504int
15637ed4 505ahaprobe(dev)
519fb2b7 506 struct isa_device *dev;
15637ed4 507{
519fb2b7
RG
508 int unit = ahaunit;
509 struct aha_data *aha;
510
511 /*
512 * find unit and check we have that many defined
513 */
514 if (unit >= NAHA) {
515 printf("aha%d: unit number too high\n", unit);
516 return 0;
15637ed4 517 }
519fb2b7
RG
518 dev->id_unit = unit;
519
520 /*
521 * a quick safety check so we can be sleazy later
522 */
523 if (sizeof(struct aha_data) > PAGESIZ) {
524 printf("aha struct > pagesize\n");
525 return 0;
15637ed4 526 }
519fb2b7
RG
527 /*
528 * Allocate a storage area for us
529 */
530 if (ahadata[unit]) {
531 printf("aha%d: memory already allocated\n", unit);
532 return 0;
533 }
534 aha = malloc(sizeof(struct aha_data), M_TEMP, M_NOWAIT);
535 if (!aha) {
536 printf("aha%d: cannot malloc!\n", unit);
537 return 0;
538 }
4714cf38 539 bzero(aha, sizeof(struct aha_data));
519fb2b7
RG
540 ahadata[unit] = aha;
541 aha->aha_base = dev->id_iobase;
542 /*
543 * Try initialise a unit at this location
544 * sets up dma and bus speed, loads aha->aha_int
545 */
546 if (aha_init(unit) != 0) {
547 ahadata[unit] = NULL;
548 free(aha, M_TEMP);
549 return 0;
550 }
551 /*
552 * Calculate the xor product of the aha struct's
553 * physical and virtual address. This allows us
554 * to change addresses within the structure
555 * from physical to virtual easily, as long as
556 * the structure is less than 1 page in size.
557 * This is used to recognise CCBs which are in
558 * this struct and which are refered to by the
559 * hardware using physical addresses.
560 * (assumes malloc returns a chunk that doesn't
561 * span pages)
562 * eventually use the hash table in aha1742.c
563 */
564 aha->kv_phys_xor = (long int) aha ^ (KVTOPHYS(aha));
15637ed4 565
519fb2b7
RG
566 /*
567 * If it's there, put in it's interrupt vectors
568 */
569 dev->id_irq = (1 << aha->aha_int);
570 dev->id_drq = aha->aha_dma;
571 ahaunit++;
572 return 0x4;
15637ed4
RG
573}
574
519fb2b7
RG
575/*
576 * Attach all the sub-devices we can find
577 */
578int
15637ed4 579ahaattach(dev)
519fb2b7 580 struct isa_device *dev;
15637ed4 581{
519fb2b7
RG
582 int unit = dev->id_unit;
583 struct aha_data *aha = ahadata[unit];
584
585 /*
586 * fill in the prototype scsi_link.
587 */
588 aha->sc_link.adapter_unit = unit;
589 aha->sc_link.adapter_targ = aha->aha_scsi_dev;
590 aha->sc_link.adapter = &aha_switch;
591 aha->sc_link.device = &aha_dev;
8387479d 592 aha->sc_link.flags = SDEV_BOUNCE;
519fb2b7
RG
593
594 /*
595 * ask the adapter what subunits are present
596 */
597 scsi_attachdevs(&(aha->sc_link));
598
599 return 1;
15637ed4
RG
600}
601
519fb2b7
RG
602/*
603 * Return some information to the caller about the adapter and its
604 * capabilities.
605 */
606u_int32
607aha_adapter_info(unit)
608 int unit;
15637ed4 609{
519fb2b7 610 return (2); /* 2 outstanding requests at a time per device */
15637ed4
RG
611}
612
519fb2b7
RG
613/*
614 * Catch an interrupt from the adaptor
615 */
616int
15637ed4 617ahaintr(unit)
4c45483e 618 int unit;
15637ed4
RG
619{
620 struct aha_ccb *ccb;
621 unsigned char stat;
622 register i;
519fb2b7 623 struct aha_data *aha = ahadata[unit];
15637ed4 624
b33502d5 625#ifdef AHADEBUG
519fb2b7
RG
626 printf("ahaintr ");
627#endif /*AHADEBUG */
628 /*
629 * First acknowlege the interrupt, Then if it's not telling about
630 * a completed operation just return.
631 */
15637ed4
RG
632 stat = inb(AHA_INTR_PORT);
633 outb(AHA_CTRL_STAT_PORT, AHA_IRST);
519fb2b7
RG
634 if (!(stat & AHA_MBIF))
635 return 1;
b33502d5 636#ifdef AHADEBUG
519fb2b7
RG
637 printf("mbxin ");
638#endif /*AHADEBUG */
639 /*
640 * If it IS then process the competed operation
641 */
642 for (i = 0; i < AHA_MBX_SIZE; i++) {
643 if (aha->aha_mbx.mbi[i].stat != AHA_MBI_FREE) {
644 ccb = (struct aha_ccb *) PHYSTOKV(
645 (_3btol(aha->aha_mbx.mbi[i].ccb_addr)));
646
647 if ((stat = aha->aha_mbx.mbi[i].stat) != AHA_MBI_OK) {
648 switch (stat) {
649 case AHA_MBI_ABORT:
b33502d5 650#ifdef AHADEBUG
519fb2b7
RG
651 if (aha_debug)
652 printf("abort");
653#endif /*AHADEBUG */
15637ed4
RG
654 ccb->host_stat = AHA_ABORTED;
655 break;
656
519fb2b7
RG
657 case AHA_MBI_UNKNOWN:
658 ccb = (struct aha_ccb *) 0;
b33502d5 659#ifdef AHADEBUG
519fb2b7
RG
660 if (aha_debug)
661 printf("unknown ccb for abort ");
662#endif /*AHADEBUG */
15637ed4
RG
663 /* may have missed it */
664 /* no such ccb known for abort */
665
519fb2b7 666 case AHA_MBI_ERROR:
15637ed4
RG
667 break;
668
669 default:
670 panic("Impossible mbxi status");
671
672 }
b33502d5 673#ifdef AHADEBUG
519fb2b7
RG
674 if (aha_debug && ccb) {
675 u_char *cp;
676 cp = (u_char *) (&(ccb->scsi_cmd));
677 printf("op=%x %x %x %x %x %x\n",
678 cp[0], cp[1], cp[2],
679 cp[3], cp[4], cp[5]);
15637ed4 680 printf("stat %x for mbi[%d]\n"
519fb2b7 681 ,aha->aha_mbx.mbi[i].stat, i);
15637ed4
RG
682 printf("addr = 0x%x\n", ccb);
683 }
519fb2b7 684#endif /*AHADEBUG */
15637ed4 685 }
519fb2b7 686 if (ccb) {
fde1aeb2 687 untimeout(aha_timeout, (caddr_t)ccb);
519fb2b7 688 aha_done(unit, ccb);
15637ed4 689 }
519fb2b7 690 aha->aha_mbx.mbi[i].stat = AHA_MBI_FREE;
15637ed4
RG
691 }
692 }
519fb2b7 693 return 1;
15637ed4
RG
694}
695
519fb2b7
RG
696/*
697 * A ccb (and hence a mbx-out is put onto the
698 * free list.
699 */
700void
701aha_free_ccb(unit, ccb, flags)
4c45483e 702 int unit;
519fb2b7 703 struct aha_ccb *ccb;
4c45483e 704 int flags;
15637ed4 705{
519fb2b7 706 struct aha_data *aha = ahadata[unit];
4c45483e 707 unsigned int opri = 0;
519fb2b7
RG
708
709 if (!(flags & SCSI_NOMASK))
710 opri = splbio();
711
712 ccb->next = aha->aha_ccb_free;
713 aha->aha_ccb_free = ccb;
15637ed4 714 ccb->flags = CCB_FREE;
519fb2b7
RG
715 /*
716 * If there were none, wake anybody waiting for
717 * one to come free, starting with queued entries
718 */
15637ed4 719 if (!ccb->next) {
4c45483e 720 wakeup((caddr_t)&aha->aha_ccb_free);
15637ed4 721 }
519fb2b7 722 if (!(flags & SCSI_NOMASK))
15637ed4
RG
723 splx(opri);
724}
725
519fb2b7
RG
726/*
727 * Get a free ccb (and hence mbox-out entry)
728 */
15637ed4 729struct aha_ccb *
519fb2b7 730aha_get_ccb(unit, flags)
4c45483e
GW
731 int unit;
732 int flags;
15637ed4 733{
519fb2b7 734 struct aha_data *aha = ahadata[unit];
4c45483e 735 unsigned opri = 0;
15637ed4
RG
736 struct aha_ccb *rc;
737
519fb2b7
RG
738 if (!(flags & SCSI_NOMASK))
739 opri = splbio();
740 /*
741 * If we can and have to, sleep waiting for one
742 * to come free
743 */
744 while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) {
ee874879 745 tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0);
15637ed4 746 }
519fb2b7
RG
747 if (rc) {
748 aha->aha_ccb_free = aha->aha_ccb_free->next;
15637ed4
RG
749 rc->flags = CCB_ACTIVE;
750 }
519fb2b7 751 if (!(flags & SCSI_NOMASK))
15637ed4 752 splx(opri);
519fb2b7 753 return (rc);
15637ed4 754}
519fb2b7
RG
755
756/*
757 * We have a ccb which has been processed by the
758 * adaptor, now we look to see how the operation
759 * went. Wake up the owner if waiting
760 */
761void
762aha_done(unit, ccb)
763 int unit;
764 struct aha_ccb *ccb;
15637ed4 765{
519fb2b7
RG
766 struct aha_data *aha = ahadata[unit];
767 struct scsi_sense_data *s1, *s2;
768 struct scsi_xfer *xs = ccb->xfer;
15637ed4 769
519fb2b7
RG
770 SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n"));
771 /*
772 * Otherwise, put the results of the operation
773 * into the xfer and call whoever started it
774 */
775 if (!(xs->flags & INUSE)) {
776 printf("aha%d: exiting but not in use!\n", unit);
fde1aeb2 777 Debugger("aha1542");
15637ed4 778 }
519fb2b7
RG
779 if (((ccb->host_stat != AHA_OK) || (ccb->target_stat != SCSI_OK))
780 && ((xs->flags & SCSI_ERR_OK) == 0)) {
781 /*
782 * We have an error, that we cannot ignore.
783 */
784 s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd))
785 + ccb->scsi_cmd_length);
15637ed4
RG
786 s2 = &(xs->sense);
787
519fb2b7
RG
788 if (ccb->host_stat) {
789 SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n",
790 ccb->host_stat));
791 switch (ccb->host_stat) {
792 case AHA_ABORTED:
793 case AHA_SEL_TIMEOUT: /* No response */
15637ed4
RG
794 xs->error = XS_TIMEOUT;
795 break;
796 default: /* Other scsi protocol messes */
797 xs->error = XS_DRIVER_STUFFUP;
519fb2b7
RG
798 printf("aha%d:host_stat%x\n",
799 unit, ccb->host_stat);
15637ed4 800 }
519fb2b7
RG
801 } else {
802 SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n",
803 ccb->target_stat));
804 switch (ccb->target_stat) {
15637ed4 805 case 0x02:
519fb2b7
RG
806 /* structure copy!!!!! */
807 *s2 = *s1;
15637ed4
RG
808 xs->error = XS_SENSE;
809 break;
810 case 0x08:
811 xs->error = XS_BUSY;
812 break;
813 default:
519fb2b7
RG
814 printf("aha%d:target_stat%x\n",
815 unit, ccb->target_stat);
15637ed4
RG
816 xs->error = XS_DRIVER_STUFFUP;
817 }
818 }
519fb2b7
RG
819 } else {
820 /* All went correctly OR errors expected */
15637ed4
RG
821 xs->resid = 0;
822 }
823 xs->flags |= ITSDONE;
519fb2b7
RG
824 aha_free_ccb(unit, ccb, xs->flags);
825 scsi_done(xs);
15637ed4
RG
826}
827
519fb2b7
RG
828/*
829 * Start the board, ready for normal operation
830 */
831int
15637ed4 832aha_init(unit)
519fb2b7 833 int unit;
15637ed4 834{
519fb2b7 835 struct aha_data *aha = ahadata[unit];
15637ed4 836 unsigned char ad[3];
519fb2b7 837 volatile int i, sts;
15637ed4 838 struct aha_config conf;
b9f44595
RG
839 struct aha_inquire inquire;
840 struct aha_extbios extbios;
15637ed4 841
519fb2b7
RG
842 /*
843 * reset board, If it doesn't respond, assume
844 * that it's not there.. good for the probe
845 */
15637ed4 846
519fb2b7 847 outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST);
15637ed4 848
519fb2b7
RG
849 for (i = AHA_RESET_TIMEOUT; i; i--) {
850 sts = inb(AHA_CTRL_STAT_PORT);
851 if (sts == (AHA_IDLE | AHA_INIT))
15637ed4 852 break;
519fb2b7 853 DELAY(1000); /* calibrated in msec */
15637ed4 854 }
519fb2b7 855 if (i == 0) {
b33502d5 856#ifdef AHADEBUG
15637ed4
RG
857 if (aha_debug)
858 printf("aha_init: No answer from adaptec board\n");
519fb2b7
RG
859#endif /*AHADEBUG */
860 return (ENXIO);
15637ed4 861 }
519fb2b7 862
b9f44595
RG
863 /*
864 * Assume we have a board at this stage, do an adapter inquire
865 * to find out what type of controller it is
866 */
867 aha_cmd(unit, 0, sizeof(inquire), 1 ,&inquire, AHA_INQUIRE);
868#ifdef AHADEBUG
869 printf("aha%d: inquire %x, %x, %x, %x\n",
870 unit,
871 inquire.boardid, inquire.spec_opts,
872 inquire.revision_1, inquire.revision_2);
873#endif /* AHADEBUG */
874 /*
875 * XXX The Buslogic 545S gets the AHA_INQUIRE command wrong,
876 * they only return one byte which causes us to print an error,
877 * so if the boardid comes back as 0x20, tell the user why they
878 * get the "cmd/data port empty" message
879 */
880 if (inquire.boardid == 0x20) {
881 /* looks like a Buslogic 545 */
882 printf ("aha%d: above cmd/data port empty do to Buslogic 545\n",
883 unit);
884 }
885 /*
6ebbc403
RG
886 * If we are a 1542C or 1542CF disable the extended bios so that the
887 * mailbox interface is unlocked.
888 * No need to check the extended bios flags as some of the
889 * extensions that cause us problems are not flagged in that byte.
b9f44595 890 */
03c8dd07
AS
891 if ((inquire.boardid == 0x43) || (inquire.boardid == 0x44) ||
892 (inquire.boardid == 0x45)) {
b9f44595
RG
893 aha_cmd(unit, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS);
894#ifdef AHADEBUG
895 printf("aha%d: extended bios flags %x\n", unit, extbios.flags);
896#endif /* AHADEBUG */
6ebbc403
RG
897 printf("aha%d: 1542C/CF detected, unlocking mailbox\n");
898 aha_cmd(unit, 2, 0, 0, 0, AHA_MBX_ENABLE,
899 0, extbios.mailboxlock);
b9f44595 900 }
519fb2b7
RG
901
902 /*
903 * setup dma channel from jumpers and save int
904 * level
905 */
906 printf("aha%d: reading board settings, ", unit);
15637ed4 907#define PRNT(x) printf(x)
519fb2b7
RG
908 DELAY(1000); /* for Bustek 545 */
909 aha_cmd(unit, 0, sizeof(conf), 0, &conf, AHA_CONF_GET);
910 switch (conf.chan) {
911 case CHAN0:
15637ed4
RG
912 outb(0x0b, 0x0c);
913 outb(0x0a, 0x00);
519fb2b7 914 aha->aha_dma = 0;
15637ed4
RG
915 PRNT("dma=0 ");
916 break;
519fb2b7 917 case CHAN5:
15637ed4
RG
918 outb(0xd6, 0xc1);
919 outb(0xd4, 0x01);
519fb2b7 920 aha->aha_dma = 5;
15637ed4
RG
921 PRNT("dma=5 ");
922 break;
519fb2b7 923 case CHAN6:
15637ed4
RG
924 outb(0xd6, 0xc2);
925 outb(0xd4, 0x02);
519fb2b7 926 aha->aha_dma = 6;
15637ed4
RG
927 PRNT("dma=6 ");
928 break;
519fb2b7 929 case CHAN7:
15637ed4
RG
930 outb(0xd6, 0xc3);
931 outb(0xd4, 0x03);
519fb2b7 932 aha->aha_dma = 7;
15637ed4
RG
933 PRNT("dma=7 ");
934 break;
935 default:
936 printf("illegal dma jumper setting\n");
519fb2b7 937 return (EIO);
15637ed4 938 }
519fb2b7
RG
939 switch (conf.intr) {
940 case INT9:
941 aha->aha_int = 9;
15637ed4
RG
942 PRNT("int=9 ");
943 break;
519fb2b7
RG
944 case INT10:
945 aha->aha_int = 10;
15637ed4
RG
946 PRNT("int=10 ");
947 break;
519fb2b7
RG
948 case INT11:
949 aha->aha_int = 11;
15637ed4
RG
950 PRNT("int=11 ");
951 break;
519fb2b7
RG
952 case INT12:
953 aha->aha_int = 12;
15637ed4
RG
954 PRNT("int=12 ");
955 break;
519fb2b7
RG
956 case INT14:
957 aha->aha_int = 14;
15637ed4
RG
958 PRNT("int=14 ");
959 break;
519fb2b7
RG
960 case INT15:
961 aha->aha_int = 15;
15637ed4
RG
962 PRNT("int=15 ");
963 break;
964 default:
965 printf("illegal int jumper setting\n");
519fb2b7 966 return (EIO);
15637ed4 967 }
15637ed4 968
519fb2b7
RG
969 /* who are we on the scsi bus? */
970 aha->aha_scsi_dev = conf.scsi_dev;
15637ed4 971
519fb2b7
RG
972 /*
973 * Change the bus on/off times to not clash with other dma users.
974 */
975 aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
976 aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
977
978#ifdef TUNE_1542
979 /*
980 * Initialize memory transfer speed
981 * Not compiled in by default because it breaks some machines
982 */
983 if (!(aha_set_bus_speed(unit))) {
984 return (EIO);
15637ed4 985 }
9deb2487
RG
986#else
987 printf ("\n");
519fb2b7
RG
988#endif /*TUNE_1542*/
989 /*
990 * Initialize mail box
991 */
992 lto3b(KVTOPHYS(&aha->aha_mbx), ad);
15637ed4 993
519fb2b7
RG
994 aha_cmd(unit, 4, 0, 0, 0, AHA_MBX_INIT,
995 AHA_MBX_SIZE,
996 ad[0],
997 ad[1],
998 ad[2]);
15637ed4 999
519fb2b7
RG
1000 /*
1001 * link the ccb's with the mbox-out entries and
1002 * into a free-list
1003 * this is a kludge but it works
1004 */
1005 for (i = 0; i < AHA_MBX_SIZE; i++) {
1006 aha->aha_ccb[i].next = aha->aha_ccb_free;
1007 aha->aha_ccb_free = &aha->aha_ccb[i];
1008 aha->aha_ccb_free->flags = CCB_FREE;
1009 aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i];
1010 lto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr);
1011 }
1012 /*
1013 * Note that we are going and return (to probe)
1014 */
1015 return 0;
15637ed4
RG
1016}
1017
519fb2b7
RG
1018void
1019ahaminphys(bp)
1020 struct buf *bp;
15637ed4 1021{
519fb2b7
RG
1022/* aha seems to explode with 17 segs (64k may require 17 segs) */
1023/* on old boards so use a max of 16 segs if you have problems here */
1024 if (bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) {
15637ed4
RG
1025 bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ);
1026 }
1027}
519fb2b7
RG
1028
1029/*
1030 * start a scsi operation given the command and
1031 * the data address. Also needs the unit, target
1032 * and lu
1033 */
1034int32
1035aha_scsi_cmd(xs)
1036 struct scsi_xfer *xs;
15637ed4 1037{
519fb2b7
RG
1038 struct scsi_link *sc_link = xs->sc_link;
1039 int unit = sc_link->adapter_unit;
1040 struct aha_data *aha = ahadata[unit];
1041 struct scsi_sense_data *s1, *s2;
15637ed4
RG
1042 struct aha_ccb *ccb;
1043 struct aha_scat_gath *sg;
519fb2b7
RG
1044 int seg; /* scatter gather seg being worked on */
1045 int i = 0;
1046 int rc = 0;
1047 int thiskv;
1048 int thisphys, nextphys;
1049 int bytes_this_seg, bytes_this_page, datalen, flags;
1050 struct iovec *iovp;
1051 int s;
1052
1053 SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
1054 /*
1055 * get a ccb (mbox-out) to use. If the transfer
1056 * is from a buf (possibly from interrupt time)
1057 * then we can't allow it to sleep
1058 */
15637ed4 1059 flags = xs->flags;
519fb2b7 1060 if (!(ccb = aha_get_ccb(unit, flags))) {
15637ed4 1061 xs->error = XS_DRIVER_STUFFUP;
519fb2b7 1062 return (TRY_AGAIN_LATER);
15637ed4 1063 }
15637ed4 1064 if (ccb->mbx->cmd != AHA_MBO_FREE)
519fb2b7 1065 printf("aha%d: MBO not free\n", unit);
15637ed4 1066
519fb2b7
RG
1067 /*
1068 * Put all the arguments for the xfer in the ccb
1069 */
1070 ccb->xfer = xs;
1071 if (flags & SCSI_RESET) {
1072 ccb->opcode = AHA_RESET_CCB;
1073 } else {
15637ed4 1074 /* can't use S/G if zero length */
519fb2b7
RG
1075 ccb->opcode = (xs->datalen ?
1076 AHA_INIT_SCAT_GATH_CCB
1077 : AHA_INITIATOR_CCB);
15637ed4 1078 }
519fb2b7
RG
1079 ccb->target = sc_link->target;
1080 ccb->data_out = 0;
1081 ccb->data_in = 0;
1082 ccb->lun = sc_link->lun;
1083 ccb->scsi_cmd_length = xs->cmdlen;
1084 ccb->req_sense_length = sizeof(ccb->scsi_sense);
1085
1086 if ((xs->datalen) && (!(flags & SCSI_RESET))) {
1087 /* can use S/G only if not zero length */
1088 lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
1089 sg = ccb->scat_gath;
1090 seg = 0;
1091#ifdef TFS_ONLY
1092 if (flags & SCSI_DATA_UIO) {
1093 iovp = ((struct uio *) xs->data)->uio_iov;
1094 datalen = ((struct uio *) xs->data)->uio_iovcnt;
1095 while ((datalen) && (seg < AHA_NSEG)) {
1096 lto3b(iovp->iov_base, sg->seg_addr);
1097 lto3b(iovp->iov_len, sg->seg_len);
1098 SC_DEBUGN(xs->sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)"
1099 ,iovp->iov_len
1100 ,iovp->iov_base));
15637ed4
RG
1101 sg++;
1102 iovp++;
1103 seg++;
1104 datalen--;
1105 }
519fb2b7
RG
1106 } else
1107#endif /*TFS_ONLY */
15637ed4 1108 {
519fb2b7
RG
1109 /*
1110 * Set up the scatter gather block
1111 */
1112
1113 SC_DEBUG(xs->sc_link, SDEV_DB4,
1114 ("%d @0x%x:- ", xs->datalen, xs->data));
1115 datalen = xs->datalen;
1116 thiskv = (int) xs->data;
1117 thisphys = KVTOPHYS(thiskv);
1118
1119 while ((datalen) && (seg < AHA_NSEG)) {
1120 bytes_this_seg = 0;
1121
15637ed4 1122 /* put in the base address */
519fb2b7
RG
1123 lto3b(thisphys, sg->seg_addr);
1124
1125 SC_DEBUGN(xs->sc_link, SDEV_DB4,
1126 ("0x%x", thisphys));
1127
15637ed4 1128 /* do it at least once */
519fb2b7
RG
1129 nextphys = thisphys;
1130 while ((datalen) && (thisphys == nextphys)) {
1131 /*
1132 * This page is contiguous (physically)
1133 * with the the last, just extend the
1134 * length
1135 */
1136 /* check it fits on the ISA bus */
1137 if (thisphys > 0xFFFFFF)
1138 {
1139 printf("aha%d: DMA beyond"
1140 " end Of ISA\n", unit);
1141 xs->error = XS_DRIVER_STUFFUP;
1142 aha_free_ccb(unit, ccb, flags);
1143 return (HAD_ERROR);
1144 }
15637ed4
RG
1145 /** how far to the end of the page ***/
1146 nextphys = (thisphys & (~(PAGESIZ - 1)))
519fb2b7
RG
1147 + PAGESIZ;
1148 bytes_this_page = nextphys - thisphys;
15637ed4 1149 /**** or the data ****/
519fb2b7
RG
1150 bytes_this_page = min(bytes_this_page
1151 ,datalen);
1152 bytes_this_seg += bytes_this_page;
1153 datalen -= bytes_this_page;
1154
15637ed4 1155 /**** get more ready for the next page ****/
519fb2b7
RG
1156 thiskv = (thiskv & (~(PAGESIZ - 1)))
1157 + PAGESIZ;
1158 if (datalen)
15637ed4
RG
1159 thisphys = KVTOPHYS(thiskv);
1160 }
519fb2b7
RG
1161 /*
1162 * next page isn't contiguous, finish the seg
1163 */
1164 SC_DEBUGN(xs->sc_link, SDEV_DB4,
1165 ("(0x%x)", bytes_this_seg));
1166 lto3b(bytes_this_seg, sg->seg_len);
15637ed4
RG
1167 sg++;
1168 seg++;
1169 }
1170 }
519fb2b7
RG
1171 lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length);
1172 SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
1173
1174 if (datalen) { /* there's still data, must have run out of segs! */
98639498 1175 printf("aha%d: aha_scsi_cmd, more than %d DMA segs\n",
519fb2b7 1176 unit, AHA_NSEG);
15637ed4 1177 xs->error = XS_DRIVER_STUFFUP;
519fb2b7
RG
1178 aha_free_ccb(unit, ccb, flags);
1179 return (HAD_ERROR);
15637ed4 1180 }
519fb2b7
RG
1181 } else { /* No data xfer, use non S/G values */
1182 lto3b(0, ccb->data_addr);
1183 lto3b(0, ccb->data_length);
15637ed4 1184 }
519fb2b7
RG
1185 lto3b(0, ccb->link_addr);
1186 /*
1187 * Put the scsi command in the ccb and start it
1188 */
1189 if (!(flags & SCSI_RESET))
15637ed4 1190 bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
519fb2b7
RG
1191 if (!(flags & SCSI_NOMASK)) {
1192 s = splbio(); /* stop instant timeouts */
4c45483e 1193 timeout(aha_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000);
15637ed4 1194 aha_startmbx(ccb->mbx);
519fb2b7
RG
1195 /*
1196 * Usually return SUCCESSFULLY QUEUED
1197 */
15637ed4 1198 splx(s);
519fb2b7
RG
1199 SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n"));
1200 return (SUCCESSFULLY_QUEUED);
15637ed4
RG
1201 }
1202 aha_startmbx(ccb->mbx);
519fb2b7 1203 SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n"));
15637ed4 1204
519fb2b7
RG
1205 /*
1206 * If we can't use interrupts, poll on completion
1207 */
1208 return (aha_poll(unit, xs, ccb)); /* only during boot */
15637ed4 1209}
15637ed4 1210
519fb2b7
RG
1211/*
1212 * Poll a particular unit, looking for a particular xs
1213 */
1214int
1215aha_poll(unit, xs, ccb)
1216 int unit;
1217 struct scsi_xfer *xs;
1218 struct aha_ccb *ccb;
1219{
1220 struct aha_data *aha = ahadata[unit];
1221 int done = 0;
1222 int count = xs->timeout;
1223 u_char stat;
1224
1225 /*timeouts are in msec, so we loop in 1000uSec cycles */
1226 while (count) {
1227 /*
1228 * If we had interrupts enabled, would we
1229 * have got an interrupt?
1230 */
1231 stat = inb(AHA_INTR_PORT);
1232 if (stat & AHA_ANY_INTR) {
1233 ahaintr(unit);
15637ed4 1234 }
519fb2b7
RG
1235 if (xs->flags & ITSDONE) {
1236 break;
15637ed4 1237 }
519fb2b7
RG
1238 DELAY(1000); /* only happens in boot so ok */
1239 count--;
1240 }
1241 if (count == 0) {
1242 /*
1243 * We timed out, so call the timeout handler
1244 * manually, accout for the fact that the
1245 * clock is not running yet by taking out the
1246 * clock queue entry it makes
1247 */
4c45483e 1248 aha_timeout((caddr_t)ccb, 0);
519fb2b7
RG
1249
1250 /*
1251 * because we are polling,
1252 * take out the timeout entry aha_timeout made
1253 */
fde1aeb2 1254 untimeout(aha_timeout, (caddr_t)ccb);
519fb2b7
RG
1255 count = 2000;
1256 while (count) {
1257 /*
1258 * Once again, wait for the int bit
1259 */
1260 stat = inb(AHA_INTR_PORT);
1261 if (stat & AHA_ANY_INTR) {
1262 ahaintr(unit);
15637ed4 1263 }
519fb2b7
RG
1264 if (xs->flags & ITSDONE) {
1265 break;
15637ed4 1266 }
519fb2b7
RG
1267 DELAY(1000); /* only happens in boot so ok */
1268 count--;
1269 }
1270 if (count == 0) {
1271 /*
1272 * We timed out again.. this is bad
1273 * Notice that this time there is no
1274 * clock queue entry to remove
1275 */
4c45483e 1276 aha_timeout((caddr_t)ccb, 0);
15637ed4
RG
1277 }
1278 }
519fb2b7
RG
1279 if (xs->error)
1280 return (HAD_ERROR);
1281 return (COMPLETE);
1282
15637ed4
RG
1283}
1284
519fb2b7
RG
1285#ifdef TUNE_1542
1286/*
1287 * Try all the speeds from slowest to fastest.. if it finds a
1288 * speed that fails, back off one notch from the last working
1289 * speed (unless there is no other notch).
1290 * Returns the nSEC value of the time used
1291 * or 0 if it could get a working speed (or the NEXT speed
1292 * failed)
1293 */
15637ed4
RG
1294static struct bus_speed
1295{
1296 char arg;
1297 int nsecs;
1298}aha_bus_speeds[] =
1299{
1300 {0x88,100},
1301 {0x99,150},
1302 {0xaa,200},
1303 {0xbb,250},
1304 {0xcc,300},
1305 {0xdd,350},
1306 {0xee,400},
1307 {0xff,450}
1308};
15637ed4 1309
519fb2b7
RG
1310int
1311aha_set_bus_speed(unit)
1312 int unit;
15637ed4 1313{
519fb2b7
RG
1314 int speed;
1315 int lastworking;
1316 int retval,retval2;
1317 struct aha_data *aha = ahadata[unit];
15637ed4 1318
519fb2b7
RG
1319 lastworking = -1;
1320 speed = 7;
1321 while (1) {
1322 retval = aha_bus_speed_check(unit,speed);
1323 if(retval != 0) {
1324 lastworking = speed;
1325 }
1326 if((retval == 0) || (speed == 0)) {
1327 if(lastworking == -1) {
1328 printf("No working bus speed for aha154X\n");
1329 return 0;
1330 }
1331 printf("%d nSEC ok, using "
1332 ,aha_bus_speeds[lastworking].nsecs);
1333 if(lastworking == 7) { /* is slowest already */
1334 printf("marginal ");
1335 } else {
1336 lastworking++;
1337 }
1338 retval2 = aha_bus_speed_check(unit,lastworking);
1339 if(retval2 == 0) {
1340 printf("test retry failed.. aborting.\n");
1341 return 0;
1342 }
1343 printf("%d nSEC\n",retval2);
1344 return retval2 ;
1345
1346 }
1347 speed--;
15637ed4
RG
1348 }
1349}
1350
519fb2b7
RG
1351/*
1352 * Set the DMA speed to the Nth speed and try an xfer. If it
1353 * fails return 0, if it succeeds return the nSec value selected
1354 * If there is no such speed return HAD_ERROR.
1355 */
1356static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
15637ed4 1357
519fb2b7
RG
1358int
1359aha_bus_speed_check(unit, speed)
1360 int unit, speed;
15637ed4 1361{
519fb2b7
RG
1362 int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
1363 int loopcount;
1364 u_char ad[3];
1365 struct aha_data *aha = ahadata[unit];
1366
1367 /*
1368 * Check we have such an entry
1369 */
1370 if (speed >= numspeeds)
1371 return (HAD_ERROR); /* illegal speed */
15637ed4 1372
519fb2b7
RG
1373 /*
1374 * Set the dma-speed
1375 */
1376 aha_cmd(unit, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg);
b33502d5 1377
519fb2b7
RG
1378 /*
1379 * put the test data into the buffer and calculate
1380 * it's address. Read it onto the board
1381 */
1382 lto3b(KVTOPHYS(aha_scratch_buf), ad);
1383 for(loopcount = 2000;loopcount;loopcount--)
15637ed4 1384 {
519fb2b7
RG
1385 strcpy(aha_scratch_buf, aha_test_string);
1386
1387 aha_cmd(unit, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
1388
1389 /*
1390 * clear the buffer then copy the contents back from the
1391 * board.
1392 */
1393 bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */
1394
1395 aha_cmd(unit, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
1396
1397 /*
1398 * Compare the original data and the final data and
1399 * return the correct value depending upon the result
1400 */
1401 if (strcmp(aha_test_string, aha_scratch_buf))
1402 return 0; /* failed test */
1403 }
1404 /* copy succeded assume speed ok */
1405
1406 return (aha_bus_speeds[speed].nsecs);
1407
1408}
1409#endif /*TUNE_1542*/
1410
1411void
4c45483e 1412aha_timeout(caddr_t arg1, int arg2)
519fb2b7 1413{
4c45483e 1414 struct aha_ccb * ccb = (struct aha_ccb *)arg1;
519fb2b7
RG
1415 int unit;
1416 int s = splbio();
1417 struct aha_data *aha;
1418
1419 unit = ccb->xfer->sc_link->adapter_unit;
1420 aha = ahadata[unit];
1421 sc_print_addr(ccb->xfer->sc_link);
1422 printf("timed out ");
1423
1424 /*
1425 * If The ccb's mbx is not free, then
1426 * the board has gone south
1427 */
1428 if (ccb->mbx->cmd != AHA_MBO_FREE) {
1429 printf("\nadapter not taking commands.. frozen?!\n");
fde1aeb2 1430 Debugger("aha1542");
15637ed4 1431 }
519fb2b7
RG
1432 /*
1433 * If it has been through before, then
1434 * a previous abort has failed, don't
1435 * try abort again
1436 */
1437 if (ccb->flags == CCB_ABORTED) {
1438 /* abort timed out */
b33502d5 1439 printf(" AGAIN\n");
519fb2b7 1440 ccb->xfer->retries = 0; /* I MEAN IT ! */
b33502d5 1441 ccb->host_stat = AHA_ABORTED;
519fb2b7
RG
1442 aha_done(unit, ccb);
1443 } else {
1444 /* abort the operation that has timed out */
b33502d5
RG
1445 printf("\n");
1446 aha_abortmbx(ccb->mbx);
519fb2b7 1447 /* 4 secs for the abort */
4c45483e 1448 timeout(aha_timeout, (caddr_t)ccb, 4 * hz);
b33502d5 1449 ccb->flags = CCB_ABORTED;
519fb2b7 1450 } splx(s);
15637ed4 1451}
519fb2b7 1452#endif /* KERNEL */