Initial import, 0.1 + pk 0.2.4-B1
[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 *
15 *
16 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
17 * -------------------- ----- ----------------------
18 * CURRENT PATCH LEVEL: 1 00098
19 * -------------------- ----- ----------------------
20 *
21 * 16 Feb 93 Julian Elischer ADDED for SCSI system
22 */
23
24/*
25 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
26 */
27
28/*
29 * HISTORY
30 * $Log: aha1542.c,v $
31 * Revision 1.6 1992/08/24 21:01:58 jason
32 * many changes and bugfixes for osf1
33 *
34 * Revision 1.5 1992/07/31 01:22:03 julian
35 * support improved scsi.h layout
36 *
37 * Revision 1.4 1992/07/25 03:11:26 julian
38 * check each request fro sane flags.
39 *
40 * Revision 1.3 1992/07/24 00:52:45 julian
41 * improved timeout handling.
42 * added support for two arguments to the sd_done (or equiv) call so that
43 * they can pre-queue several arguments.
44 * slightly clean up error handling
45 *
46 * Revision 1.2 1992/07/17 22:03:54 julian
47 * upgraded the timeout code.
48 * added support for UIO-based i/o (as used for pmem operations)
49 *
50 * Revision 1.1 1992/05/27 00:51:12 balsup
51 * machkern/cor merge
52 */
53
54/*
55 * a FEW lines in this driver come from a MACH adaptec-disk driver
56 * so the copyright below is included:
57 *
58 * Copyright 1990 by Open Software Foundation,
59 * Grenoble, FRANCE
60 *
61 * All Rights Reserved
62 *
63 * Permission to use, copy, modify, and distribute this software and
64 * its documentation for any purpose and without fee is hereby granted,
65 * provided that the above copyright notice appears in all copies and
66 * that both the copyright notice and this permission notice appear in
67 * supporting documentation, and that the name of OSF or Open Software
68 * Foundation not be used in advertising or publicity pertaining to
69 * distribution of the software without specific, written prior
70 * permission.
71 *
72 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
73 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
74 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
75 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
76 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
77 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
78 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
79 */
80
81
82#include <sys/types.h>
83#include <aha.h>
84
85#include <sys/param.h>
86#include <sys/systm.h>
87#include <sys/errno.h>
88#include <sys/ioctl.h>
89#include <sys/buf.h>
90#include <sys/proc.h>
91#include <sys/user.h>
92
93#ifdef MACH /* EITHER CMU OR OSF */
94#include <i386/ipl.h>
95#include <i386at/scsi.h>
96#include <i386at/scsiconf.h>
97
98#ifdef OSF /* OSF ONLY */
99#include <sys/table.h>
100#include <i386/handler.h>
101#include <i386/dispatcher.h>
102#include <i386/AT386/atbus.h>
103
104#else OSF /* CMU ONLY */
105#include <i386at/atbus.h>
106#include <i386/pio.h>
107#endif OSF
108#endif MACH /* end of MACH specific */
109
110#ifdef __386BSD__ /* 386BSD specific */
111#define isa_dev isa_device
112#define dev_unit id_unit
113#define dev_addr id_iobase
114
115#include <i386/isa/isa_device.h>
116#include <scsi/scsi_all.h>
117#include <scsi/scsiconf.h>
118#endif __386BSD__
119
120
121#ifdef __386BSD__
122#include "ddb.h"
123#if NDDB > 0
124int Debugger();
125#else NDDB
126#define Debugger() panic("should call debugger here (adaptec.c)")
127#endif NDDB
128#endif __386BSD__
129extern int delaycount; /* from clock setup code */
130
131/************************** board definitions *******************************/
132/*
133 * I/O Port Interface
134 */
135
136#define AHA_BASE aha_base[unit]
137#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */
138#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */
139#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */
140
141/*
142 * AHA_CTRL_STAT bits (write)
143 */
144
145#define AHA_HRST 0x80 /* Hardware reset */
146#define AHA_SRST 0x40 /* Software reset */
147#define AHA_IRST 0x20 /* Interrupt reset */
148#define AHA_SCRST 0x10 /* SCSI bus reset */
149
150/*
151 * AHA_CTRL_STAT bits (read)
152 */
153
154#define AHA_STST 0x80 /* Self test in Progress */
155#define AHA_DIAGF 0x40 /* Diagnostic Failure */
156#define AHA_INIT 0x20 /* Mbx Init required */
157#define AHA_IDLE 0x10 /* Host Adapter Idle */
158#define AHA_CDF 0x08 /* cmd/data out port full */
159#define AHA_DF 0x04 /* Data in port full */
160#define AHA_INVDCMD 0x01 /* Invalid command */
161
162/*
163 * AHA_CMD_DATA bits (write)
164 */
165
166#define AHA_NOP 0x00 /* No operation */
167#define AHA_MBX_INIT 0x01 /* Mbx initialization */
168#define AHA_START_SCSI 0x02 /* start scsi command */
169#define AHA_START_BIOS 0x03 /* start bios command */
170#define AHA_INQUIRE 0x04 /* Adapter Inquiry */
171#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
172#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
173#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
174#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
175#define AHA_SPEED_SET 0x09 /* set transfer speed */
176#define AHA_DEV_GET 0x0a /* return installed devices */
177#define AHA_CONF_GET 0x0b /* return configuration data */
178#define AHA_TARGET_EN 0x0c /* enable target mode */
179#define AHA_SETUP_GET 0x0d /* return setup data */
180#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */
181#define AHA_READ_CH2 0x1b /* read channel 2 buffer */
182#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */
183#define AHA_READ_FIFO 0x1d /* read fifo buffer */
184#define AHA_ECHO 0x1e /* Echo command data */
185
186struct aha_cmd_buf {
187 u_char byte[16];
188};
189
190/*
191 * AHA_INTR_PORT bits (read)
192 */
193
194#define AHA_ANY_INTR 0x80 /* Any interrupt */
195#define AHA_SCRD 0x08 /* SCSI reset detected */
196#define AHA_HACC 0x04 /* Command complete */
197#define AHA_MBOA 0x02 /* MBX out empty */
198#define AHA_MBIF 0x01 /* MBX in full */
199
200/*
201 * Mail box defs
202 */
203
204#define AHA_MBX_SIZE 16 /* mail box size */
205
206struct aha_mbx {
207 struct aha_mbx_out {
208 unsigned char cmd;
209 unsigned char ccb_addr[3];
210 } mbo [AHA_MBX_SIZE];
211 struct aha_mbx_in{
212 unsigned char stat;
213 unsigned char ccb_addr[3];
214 } mbi[AHA_MBX_SIZE];
215};
216
217/*
218 * mbo.cmd values
219 */
220
221#define AHA_MBO_FREE 0x0 /* MBO entry is free */
222#define AHA_MBO_START 0x1 /* MBO activate entry */
223#define AHA_MBO_ABORT 0x2 /* MBO abort entry */
224
225#define AHA_MBI_FREE 0x0 /* MBI entry is free */
226#define AHA_MBI_OK 0x1 /* completed without error */
227#define AHA_MBI_ABORT 0x2 /* aborted ccb */
228#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
229#define AHA_MBI_ERROR 0x4 /* Completed with error */
230
231extern struct aha_mbx aha_mbx[];
232
233/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
234#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
235 /* allow 64 K i/o (min) */
236
237struct aha_ccb {
238 unsigned char opcode;
239 unsigned char lun:3;
240 unsigned char data_in:1; /* must be 0 */
241 unsigned char data_out:1; /* must be 0 */
242 unsigned char target:3;
243 unsigned char scsi_cmd_length;
244 unsigned char req_sense_length;
245 unsigned char data_length[3];
246 unsigned char data_addr[3];
247 unsigned char link_addr[3];
248 unsigned char link_id;
249 unsigned char host_stat;
250 unsigned char target_stat;
251 unsigned char reserved[2];
252 struct scsi_generic scsi_cmd;
253 struct scsi_sense_data scsi_sense;
254 struct aha_scat_gath {
255 unsigned char seg_len[3];
256 unsigned char seg_addr[3];
257 } scat_gath[AHA_NSEG];
258 struct aha_ccb *next;
259 struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
260 struct aha_mbx_out *mbx; /* pointer to mail box */
261 long int delta; /* difference from previous*/
262 struct aha_ccb *later,*sooner;
263 int flags;
264#define CCB_FREE 0
265#define CCB_ACTIVE 1
266#define CCB_ABORTED 2
267
268};
269
270struct aha_ccb *aha_soonest = (struct aha_ccb *)0;
271struct aha_ccb *aha_latest = (struct aha_ccb *)0;
272long int aha_furtherest = 0; /* longest time in the timeout queue */
273
274/*
275 * opcode fields
276 */
277
278#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
279#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */
280#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/
281#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */
282
283
284/*
285 * aha_ccb.host_stat values
286 */
287
288#define AHA_OK 0x00 /* cmd ok */
289#define AHA_LINK_OK 0x0a /* Link cmd ok */
290#define AHA_LINK_IT 0x0b /* Link cmd ok + int */
291#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */
292#define AHA_OVER_UNDER 0x12 /* Data over/under run */
293#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
294#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
295#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
296#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
297#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */
298#define AHA_INV_TARGET 0x18 /* Invalid target direction */
299#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */
300#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */
301#define AHA_ABORTED 42
302
303
304
305
306struct aha_setup
307{
308 u_char sync_neg:1;
309 u_char parity:1;
310 u_char :6;
311 u_char speed;
312 u_char bus_on;
313 u_char bus_off;
314 u_char num_mbx;
315 u_char mbx[3];
316 struct
317 {
318 u_char offset:4;
319 u_char period:3;
320 u_char valid:1;
321 }sync[8];
322 u_char disc_sts;
323};
324
325struct aha_config
326{
327 u_char chan;
328 u_char intr;
329 u_char scsi_dev:3;
330 u_char :5;
331};
332
333#define INT9 0x01
334#define INT10 0x02
335#define INT11 0x04
336#define INT12 0x08
337#define INT14 0x20
338#define INT15 0x40
339
340#define CHAN0 0x01
341#define CHAN5 0x20
342#define CHAN6 0x40
343#define CHAN7 0x80
344
345
346/*********************************** end of board definitions***************/
347
348
349#ifdef MACH
350#define PHYSTOKV(x) phystokv(x)
351#define KVTOPHYS(x) kvtophys(x)
352#else MACH
353#ifdef __386BSD__
354#define PHYSTOKV(x) (x | 0xFE000000)
355#define KVTOPHYS(x) vtophys(x)
356#else __386BSD__
357#endif __386BSD__
358#endif MACH
359#define AHA_DMA_PAGES AHA_NSEG
360
361#define PAGESIZ 4096
362#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
363
364
365u_char aha_scratch_buf[256];
366#ifdef MACH
367caddr_t aha_base[NAHA]; /* base port for each board */
368#else
369short aha_base[NAHA]; /* base port for each board */
370#endif
371struct aha_mbx aha_mbx[NAHA];
372struct aha_ccb *aha_ccb_free[NAHA];
373struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE];
374struct scsi_xfer aha_scsi_xfer[NAHA];
375struct isa_dev *ahainfo[NAHA];
376struct aha_ccb *aha_get_ccb();
377int aha_int[NAHA];
378int aha_dma[NAHA];
379int aha_scsi_dev[NAHA];
380int aha_initialized[NAHA];
381#ifdef OSF
382int aha_attached[NAHA];
383#endif OSF
384int aha_debug = 0;
385
386int ahaprobe(), ahaattach(), ahaintr();
387#ifdef MACH
388struct isa_driver ahadriver = { ahaprobe, 0, ahaattach, "aha", 0, 0, 0};
389int (*ahaintrs[])() = {ahaintr, 0};
390#endif
391#ifdef __386BSD__
392struct isa_driver ahadriver = { ahaprobe, ahaattach, "aha",};
393#endif __386BSD__
394static int ahaunit = 0;
395
396
397#define aha_abortmbx(mbx) \
398 (mbx)->cmd = AHA_MBO_ABORT; \
399 outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
400#define aha_startmbx(mbx) \
401 (mbx)->cmd = AHA_MBO_START; \
402 outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
403
404
405
406int aha_scsi_cmd();
407int aha_timeout();
408void ahaminphys();
409long int aha_adapter_info();
410
411struct scsi_switch aha_switch =
412{
413 aha_scsi_cmd,
414 ahaminphys,
415 0,
416 0,
417 aha_adapter_info,
418 0,0,0
419};
420#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */
421#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */
422#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */
423
424
425/***********************************************************************\
426* aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args) *
427* Activate Adapter command *
428* icnt: number of args (outbound bytes written after opcode) *
429* ocnt: number of expected returned bytes *
430* wait: number of seconds to wait for response *
431* retval: buffer where to place returned bytes *
432* opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... *
433* args: parameters *
434* *
435* Performs an adapter command through the ports. Not to be confused *
436* with a scsi command, which is read in via the dma *
437* One of the adapter commands tells it to read in a scsi command *
438\***********************************************************************/
439
440
441aha_cmd(unit,icnt, ocnt, wait,retval, opcode, args)
442
443u_char *retval;
444unsigned opcode;
445u_char args;
446{
447 unsigned *ic = &opcode;
448 u_char oc;
449 register i;
450 int sts;
451
452 /*******************************************************\
453 * multiply the wait argument by a big constant *
454 * zero defaults to 1 *
455 \*******************************************************/
456 if(!wait)
457 wait = AHA_CMD_TIMEOUT_FUDGE * delaycount;
458 else
459 wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount;
460 /*******************************************************\
461 * Wait for the adapter to go idle, unless it's one of *
462 * the commands which don't need this *
463 \*******************************************************/
464 if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI)
465 {
466 i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/
467 while (--i)
468 {
469 sts = inb(AHA_CTRL_STAT_PORT);
470 if (sts & AHA_IDLE)
471 {
472 break;
473 }
474 }
475 if (!i)
476 {
477 printf("aha_cmd: aha1542 host not idle(0x%x)\n",sts);
478 return(ENXIO);
479 }
480 }
481 /*******************************************************\
482 * Now that it is idle, if we expect output, preflush the*
483 * queue feeding to us. *
484 \*******************************************************/
485 if (ocnt)
486 {
487 while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
488 inb(AHA_CMD_DATA_PORT);
489 }
490
491 /*******************************************************\
492 * Output the command and the number of arguments given *
493 * for each byte, first check the port is empty. *
494 \*******************************************************/
495 icnt++; /* include the command */
496 while (icnt--)
497 {
498 sts = inb(AHA_CTRL_STAT_PORT);
499 for (i=0; i< wait; i++)
500 {
501 sts = inb(AHA_CTRL_STAT_PORT);
502 if (!(sts & AHA_CDF))
503 break;
504 }
505 if (i >= wait)
506 {
507 printf("aha_cmd: aha1542 cmd/data port full\n");
508 outb(AHA_CTRL_STAT_PORT, AHA_SRST);
509 return(ENXIO);
510 }
511 outb(AHA_CMD_DATA_PORT, (u_char)(*ic++));
512 }
513 /*******************************************************\
514 * If we expect input, loop that many times, each time, *
515 * looking for the data register to have valid data *
516 \*******************************************************/
517 while (ocnt--)
518 {
519 sts = inb(AHA_CTRL_STAT_PORT);
520 for (i=0; i< wait; i++)
521 {
522 sts = inb(AHA_CTRL_STAT_PORT);
523 if (sts & AHA_DF)
524 break;
525 }
526 if (i >= wait)
527 {
528 printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt);
529 return(ENXIO);
530 }
531 oc = inb(AHA_CMD_DATA_PORT);
532 if (retval)
533 *retval++ = oc;
534 }
535 /*******************************************************\
536 * Wait for the board to report a finised instruction *
537 \*******************************************************/
538 i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */
539 while (--i)
540 {
541 sts = inb(AHA_INTR_PORT);
542 if (sts & AHA_HACC)
543 {
544 break;
545 }
546 }
547 if (!i)
548 {
549 printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts);
550 return(ENXIO);
551 }
552 outb(AHA_CTRL_STAT_PORT, AHA_IRST);
553 return(0);
554}
555
556/*******************************************************\
557* Check if the device can be found at the port given *
558* and if so, set it up ready for further work *
559* as an argument, takes the isa_dev structure from *
560* autoconf.c *
561\*******************************************************/
562ahaprobe(dev)
563struct isa_dev *dev;
564{
565 int unit = ahaunit;
566#if defined(OSF)
567 static ihandler_t aha_handler[NAHA];
568 static ihandler_id_t *aha_handler_id[NAHA];
569 register ihandler_t *chp = &aha_handler[unit];;
570#endif /* defined(OSF) */
571
572 /***********************************************\
573 /***********************************************\
574 * find unit and check we have that many defined *
575 \***********************************************/
576 dev->dev_unit = unit;
577 aha_base[unit] = dev->dev_addr;
578 if(unit >= NAHA)
579 {
580 printf("aha: unit number (%d) too high\n",unit);
581 return(0);
582 }
583 /***********************************************\
584 * Try initialise a unit at this location *
585 * sets up dma and bus speed, loads aha_int[unit]*
586 \***********************************************/
587 if (aha_init(unit) != 0)
588 {
589 return(0);
590 }
591
592 /***********************************************\
593 * If it's there, put in it's interrupt vectors *
594 \***********************************************/
595#if !defined(OSF)
596#if defined MACH
597 iunit[aha_int[unit]] =unit;
598 ivect[aha_int[unit]] = ahaintr;
599 intpri[aha_int[unit]] = dev->dev_spl;
600 form_pic_mask();
601 /*take_dev_irq(dev);*/
602#else
603#ifdef __386BSD__
604 dev->id_irq = (1 << aha_int[unit]);
605 dev->id_drq = aha_dma[unit];
606#endif __386BSD__
607#endif
608#else /* !defined(OSF) */
609
610 chp->ih_level = dev->dev_pic;
611 chp->ih_handler = dev->dev_intr[0];
612 chp->ih_resolver = i386_resolver;
613 chp->ih_rdev = dev;
614 chp->ih_stats.intr_type = INTR_DEVICE;
615 chp->ih_stats.intr_cnt = 0;
616 chp->ih_hparam[0].intparam = unit;
617 if ((aha_handler_id[unit] = handler_add(chp)) != NULL)
618 handler_enable(aha_handler_id[unit]);
619 else
620 panic("Unable to add aha interrupt handler");
621#endif /* !defined(OSF) */
622#ifdef __386BSD__
623 printf("\n **");
624#else __386BSD__
625 printf("port=%x spl=%d\n",
626 dev->dev_addr, dev->dev_spl);
627#endif __386BSD__
628 ahaunit ++;
629 return(1);
630}
631
632/***********************************************\
633* Attach all the sub-devices we can find *
634\***********************************************/
635ahaattach(dev)
636struct isa_dev *dev;
637{
638 int unit = dev->dev_unit;
639
640#ifdef __386BSD__
641 printf(" probing for scsi devices**\n");
642#endif __386BSD__
643 /***********************************************\
644 * ask the adapter what subunits are present *
645 \***********************************************/
646 scsi_attachdevs( unit, aha_scsi_dev[unit], &aha_switch);
647#if defined(OSF)
648 aha_attached[unit]=1;
649#endif /* defined(OSF) */
650 if(!unit) /* only one for all boards */
651 {
652 aha_timeout(0);
653 }
654#ifdef __386BSD__
655 printf("aha%d",unit);
656#endif __386BSD__
657 return;
658
659}
660
661
662/***********************************************\
663* Return some information to the caller about *
664* the adapter and it's capabilities *
665\***********************************************/
666long int aha_adapter_info(unit)
667int unit;
668{
669 return(2); /* 2 outstanding requests at a time per device */
670}
671
672/***********************************************\
673* Catch an interrupt from the adaptor *
674\***********************************************/
675ahaintr(unit)
676{
677 struct aha_ccb *ccb;
678 unsigned char stat;
679 register i;
680
681 if(scsi_debug & PRINTROUTINES)
682 printf("ahaintr ");
683 /***********************************************\
684 * First acknowlege the interrupt, Then if it's *
685 * not telling about a completed operation *
686 * just return. *
687 \***********************************************/
688 stat = inb(AHA_INTR_PORT);
689 outb(AHA_CTRL_STAT_PORT, AHA_IRST);
690 if(scsi_debug & TRACEINTERRUPTS)
691 printf("int ");
692 if (! (stat & AHA_MBIF))
693 return(1);
694 if(scsi_debug & TRACEINTERRUPTS)
695 printf("b ");
696#if defined(OSF)
697 if (!aha_attached[unit])
698 {
699 return(1);
700 }
701#endif /* defined(OSF) */
702 /***********************************************\
703 * If it IS then process the competed operation *
704 \***********************************************/
705 for (i = 0; i < AHA_MBX_SIZE; i++)
706 {
707 if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE)
708 {
709 ccb = (struct aha_ccb *)PHYSTOKV(
710 (_3btol(aha_mbx[unit].mbi[i].ccb_addr)));
711
712 if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK)
713 {
714 switch(stat)
715 {
716 case AHA_MBI_ABORT:
717 if(aha_debug)
718 printf("abort");
719 ccb->host_stat = AHA_ABORTED;
720 break;
721
722 case AHA_MBI_UNKNOWN:
723 ccb = (struct aha_ccb *)0;
724 if(aha_debug)
725 printf("unknown ccb for abort ");
726 /* may have missed it */
727 /* no such ccb known for abort */
728
729 case AHA_MBI_ERROR:
730 break;
731
732 default:
733 panic("Impossible mbxi status");
734
735 }
736 if( aha_debug && ccb )
737 {
738 u_char *cp;
739 cp = (u_char *)(&(ccb->scsi_cmd));
740 printf("op=%x %x %x %x %x %x\n",
741 cp[0], cp[1], cp[2],
742 cp[3], cp[4], cp[5]);
743 printf("stat %x for mbi[%d]\n"
744 , aha_mbx[unit].mbi[i].stat, i);
745 printf("addr = 0x%x\n", ccb);
746 }
747 }
748 if(ccb)
749 {
750 aha_remove_timeout(ccb);
751 aha_done(unit,ccb);
752 }
753 aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
754 }
755 }
756 return(1);
757}
758
759/***********************************************\
760* A ccb (and hence a mbx-out is put onto the *
761* free list. *
762\***********************************************/
763aha_free_ccb(unit,ccb, flags)
764struct aha_ccb *ccb;
765{
766 unsigned int opri;
767
768 if(scsi_debug & PRINTROUTINES)
769 printf("ccb%d(0x%x)> ",unit,flags);
770 if (!(flags & SCSI_NOMASK))
771 opri = splbio();
772
773 ccb->next = aha_ccb_free[unit];
774 aha_ccb_free[unit] = ccb;
775 ccb->flags = CCB_FREE;
776 if(ccb->sooner || ccb->later)
777 {
778 printf("yikes, still in timeout queue\n");
779 aha_remove_timeout(ccb);
780 }
781 /***********************************************\
782 * If there were none, wake abybody waiting for *
783 * one to come free, starting with queued entries*
784 \***********************************************/
785 if (!ccb->next) {
786 wakeup(&aha_ccb_free[unit]);
787 }
788 if (!(flags & SCSI_NOMASK))
789 splx(opri);
790}
791
792/***********************************************\
793* Get a free ccb (and hence mbox-out entry) *
794\***********************************************/
795struct aha_ccb *
796aha_get_ccb(unit,flags)
797{
798 unsigned opri;
799 struct aha_ccb *rc;
800
801 if(scsi_debug & PRINTROUTINES)
802 printf("<ccb%d(0x%x) ",unit,flags);
803 if (!(flags & SCSI_NOMASK))
804 opri = splbio();
805 /***********************************************\
806 * If we can and have to, sleep waiting for one *
807 * to come free *
808 \***********************************************/
809 while ((!(rc = aha_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP)))
810 {
811 sleep(&aha_ccb_free[unit], PRIBIO);
812 }
813 if (rc)
814 {
815 aha_ccb_free[unit] = aha_ccb_free[unit]->next;
816 rc->flags = CCB_ACTIVE;
817 }
818 if (!(flags & SCSI_NOMASK))
819 splx(opri);
820 return(rc);
821}
822
823
824/***********************************************\
825* We have a ccb which has been processed by the *
826* adaptor, now we look to see how the operation *
827* went. Wake up the owner if waiting *
828\***********************************************/
829aha_done(unit,ccb)
830struct aha_ccb *ccb;
831{
832 struct scsi_sense_data *s1,*s2;
833 struct scsi_xfer *xs = ccb->xfer;
834
835 if(scsi_debug & PRINTROUTINES )
836 printf("aha_done ");
837 /***********************************************\
838 * Otherwise, put the results of the operation *
839 * into the xfer and call whoever started it *
840 \***********************************************/
841 if(!(xs->flags & INUSE))
842 {
843 printf("exiting but not in use! ");
844 Debugger();
845 }
846 if ( ( ccb->host_stat != AHA_OK
847 || ccb->target_stat != SCSI_OK)
848 && (!(xs->flags & SCSI_ERR_OK)))
849 {
850 s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd))
851 + ccb->scsi_cmd_length);
852 s2 = &(xs->sense);
853
854 if(ccb->host_stat)
855 {
856 switch(ccb->host_stat)
857 {
858 case AHA_ABORTED:
859 case AHA_SEL_TIMEOUT: /* No response */
860 xs->error = XS_TIMEOUT;
861 break;
862 default: /* Other scsi protocol messes */
863 xs->error = XS_DRIVER_STUFFUP;
864 if (aha_debug > 1)
865 {
866 printf("host_stat%x\n",
867 ccb->host_stat);
868 }
869 }
870
871 }
872 else
873 {
874 switch(ccb->target_stat)
875 {
876 case 0x02:
877 /* structure copy!!!!!*/
878 *s2=*s1;
879 xs->error = XS_SENSE;
880 break;
881 case 0x08:
882 xs->error = XS_BUSY;
883 break;
884 default:
885 if (aha_debug > 1)
886 {
887 printf("target_stat%x\n",
888 ccb->target_stat);
889 }
890 xs->error = XS_DRIVER_STUFFUP;
891 }
892 }
893 }
894 else /* All went correctly OR errors expected */
895 {
896 xs->resid = 0;
897 }
898 xs->flags |= ITSDONE;
899 aha_free_ccb(unit,ccb, xs->flags);
900 if(xs->when_done)
901 (*(xs->when_done))(xs->done_arg,xs->done_arg2);
902}
903
904
905/***********************************************\
906* Start the board, ready for normal operation *
907\***********************************************/
908aha_init(unit)
909int unit;
910{
911 unsigned char ad[3];
912 volatile int i,sts;
913 struct aha_config conf;
914
915 /***********************************************\
916 * reset board, If it doesn't respond, assume *
917 * that it's not there.. good for the probe *
918 \***********************************************/
919
920 outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST);
921
922 for (i=0; i < AHA_RESET_TIMEOUT; i++)
923 {
924 sts = inb(AHA_CTRL_STAT_PORT) ;
925 if ( sts == (AHA_IDLE | AHA_INIT))
926 break;
927 }
928 if (i >= AHA_RESET_TIMEOUT)
929 {
930 if (aha_debug)
931 printf("aha_init: No answer from adaptec board\n");
932 return(ENXIO);
933 }
934
935 /***********************************************\
936 * Assume we have a board at this stage *
937 * setup dma channel from jumpers and save int *
938 * level *
939 \***********************************************/
940#ifdef __386BSD__
941 printf("aha%d reading board settings, ",unit);
942#define PRNT(x)
943#else __386BSD__
944 printf("aha%d:",unit);
945#define PRNT(x) printf(x)
946#endif __386BSD__
947 aha_cmd(unit,0, sizeof(conf), 0 ,&conf, AHA_CONF_GET);
948 switch(conf.chan)
949 {
950 case CHAN0:
951 outb(0x0b, 0x0c);
952 outb(0x0a, 0x00);
953 aha_dma[unit] = 0;
954 PRNT("dma=0 ");
955 break;
956 case CHAN5:
957 outb(0xd6, 0xc1);
958 outb(0xd4, 0x01);
959 aha_dma[unit] = 5;
960 PRNT("dma=5 ");
961 break;
962 case CHAN6:
963 outb(0xd6, 0xc2);
964 outb(0xd4, 0x02);
965 aha_dma[unit] = 6;
966 PRNT("dma=6 ");
967 break;
968 case CHAN7:
969 outb(0xd6, 0xc3);
970 outb(0xd4, 0x03);
971 aha_dma[unit] = 7;
972 PRNT("dma=7 ");
973 break;
974 default:
975 printf("illegal dma jumper setting\n");
976 return(EIO);
977 }
978 switch(conf.intr)
979 {
980 case INT9:
981 aha_int[unit] = 9;
982 PRNT("int=9 ");
983 break;
984 case INT10:
985 aha_int[unit] = 10;
986 PRNT("int=10 ");
987 break;
988 case INT11:
989 aha_int[unit] = 11;
990 PRNT("int=11 ");
991 break;
992 case INT12:
993 aha_int[unit] = 12;
994 PRNT("int=12 ");
995 break;
996 case INT14:
997 aha_int[unit] = 14;
998 PRNT("int=14 ");
999 break;
1000 case INT15:
1001 aha_int[unit] = 15;
1002 PRNT("int=15 ");
1003 break;
1004 default:
1005 printf("illegal int jumper setting\n");
1006 return(EIO);
1007 }
1008 /* who are we on the scsi bus */
1009 aha_scsi_dev[unit] = conf.scsi_dev;
1010
1011
1012 /***********************************************\
1013 * Initialize memory transfer speed *
1014 \***********************************************/
1015 if(!(aha_set_bus_speed(unit)))
1016 {
1017 return(EIO);
1018 }
1019
1020
1021 /***********************************************\
1022 * Initialize mail box *
1023 \***********************************************/
1024
1025 lto3b(KVTOPHYS(&aha_mbx[unit]), ad);
1026
1027 aha_cmd(unit,4, 0, 0, 0, AHA_MBX_INIT,
1028 AHA_MBX_SIZE,
1029 ad[0],
1030 ad[1],
1031 ad[2]);
1032
1033
1034 /***********************************************\
1035 * link the ccb's with the mbox-out entries and *
1036 * into a free-list *
1037 \***********************************************/
1038 for (i=0; i < AHA_MBX_SIZE; i++) {
1039 aha_ccb[unit][i].next = aha_ccb_free[unit];
1040 aha_ccb_free[unit] = &aha_ccb[unit][i];
1041 aha_ccb_free[unit]->flags = CCB_FREE;
1042 aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i];
1043 lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr);
1044 }
1045
1046 /***********************************************\
1047 * Note that we are going and return (to probe) *
1048 \***********************************************/
1049 aha_initialized[unit]++;
1050 return(0);
1051}
1052
1053
1054
1055
1056
1057void ahaminphys(bp)
1058struct buf *bp;
1059{
1060#ifdef MACH
1061#if !defined(OSF)
1062 bp->b_flags |= B_NPAGES; /* can support scat/gather */
1063#endif /* !defined(OSF) */
1064#endif MACH
1065/* aha seems to explode with 17 segs (64k may require 17 segs) */
1066/* on old boards so use a max of 16 segs if you have problems here*/
1067 if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ))
1068 {
1069 bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ);
1070 }
1071}
1072
1073/***********************************************\
1074* start a scsi operation given the command and *
1075* the data address. Also needs the unit, target *
1076* and lu *
1077\***********************************************/
1078int aha_scsi_cmd(xs)
1079struct scsi_xfer *xs;
1080{
1081 struct scsi_sense_data *s1,*s2;
1082 struct aha_ccb *ccb;
1083 struct aha_scat_gath *sg;
1084 int seg; /* scatter gather seg being worked on */
1085 int i = 0;
1086 int rc = 0;
1087 int thiskv;
1088 int thisphys,nextphys;
1089 int unit =xs->adapter;
1090 int bytes_this_seg,bytes_this_page,datalen,flags;
1091 struct iovec *iovp;
1092 int s;
1093
1094 if(scsi_debug & PRINTROUTINES)
1095 printf("aha_scsi_cmd ");
1096 /***********************************************\
1097 * get a ccb (mbox-out) to use. If the transfer *
1098 * is from a buf (possibly from interrupt time) *
1099 * then we can't allow it to sleep *
1100 \***********************************************/
1101 flags = xs->flags;
1102 if(!(flags & INUSE))
1103 {
1104 printf("not in use!");
1105 Debugger();
1106 xs->flags |= INUSE;
1107 }
1108 if(flags & ITSDONE)
1109 {
1110 printf("Already done! check device retry code ");
1111 Debugger();
1112 xs->flags &= ~ITSDONE;
1113 }
1114 if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
1115 if (!(ccb = aha_get_ccb(unit,flags)))
1116 {
1117 xs->error = XS_DRIVER_STUFFUP;
1118 return(TRY_AGAIN_LATER);
1119 }
1120
1121 if (ccb->mbx->cmd != AHA_MBO_FREE)
1122 printf("MBO not free\n");
1123
1124 /***********************************************\
1125 * Put all the arguments for the xfer in the ccb *
1126 \***********************************************/
1127 ccb->xfer = xs;
1128 if(flags & SCSI_RESET)
1129 {
1130 ccb->opcode = AHA_RESET_CCB;
1131 }
1132 else
1133 {
1134 /* can't use S/G if zero length */
1135 ccb->opcode = (xs->datalen?
1136 AHA_INIT_SCAT_GATH_CCB
1137 :AHA_INITIATOR_CCB);
1138 }
1139 ccb->target = xs->targ;;
1140 ccb->data_out = 0;
1141 ccb->data_in = 0;
1142 ccb->lun = xs->lu;
1143 ccb->scsi_cmd_length = xs->cmdlen;
1144 ccb->req_sense_length = sizeof(ccb->scsi_sense);
1145
1146 if((xs->datalen) && (!(flags & SCSI_RESET)))
1147 { /* can use S/G only if not zero length */
1148 lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr );
1149 sg = ccb->scat_gath ;
1150 seg = 0;
1151 if(flags & SCSI_DATA_UIO)
1152 {
1153 iovp = ((struct uio *)xs->data)->uio_iov;
1154 datalen = ((struct uio *)xs->data)->uio_iovcnt;
1155 while ((datalen) && (seg < AHA_NSEG))
1156 {
1157 lto3b(iovp->iov_base,&(sg->seg_addr));
1158 lto3b(iovp->iov_len,&(sg->seg_len));
1159 if(scsi_debug & SHOWSCATGATH)
1160 printf("(0x%x@0x%x)"
1161 ,iovp->iov_len
1162 ,iovp->iov_base);
1163 sg++;
1164 iovp++;
1165 seg++;
1166 datalen--;
1167 }
1168 }
1169 else
1170 {
1171 /***********************************************\
1172 * Set up the scatter gather block *
1173 \***********************************************/
1174
1175 if(scsi_debug & SHOWSCATGATH)
1176 printf("%d @0x%x:- ",xs->datalen,xs->data);
1177 datalen = xs->datalen;
1178 thiskv = (int)xs->data;
1179 thisphys = KVTOPHYS(thiskv);
1180
1181 while ((datalen) && (seg < AHA_NSEG))
1182 {
1183 bytes_this_seg = 0;
1184
1185 /* put in the base address */
1186 lto3b(thisphys,&(sg->seg_addr));
1187
1188 if(scsi_debug & SHOWSCATGATH)
1189 printf("0x%x",thisphys);
1190
1191 /* do it at least once */
1192 nextphys = thisphys;
1193 while ((datalen) && (thisphys == nextphys))
1194 /***************************************\
1195 * This page is contiguous (physically) *
1196 * with the the last, just extend the *
1197 * length *
1198 \***************************************/
1199 {
1200 /** how far to the end of the page ***/
1201 nextphys = (thisphys & (~(PAGESIZ - 1)))
1202 + PAGESIZ;
1203 bytes_this_page = nextphys - thisphys;
1204 /**** or the data ****/
1205 bytes_this_page = min(bytes_this_page
1206 ,datalen);
1207 bytes_this_seg += bytes_this_page;
1208 datalen -= bytes_this_page;
1209
1210 /**** get more ready for the next page ****/
1211 thiskv = (thiskv & (~(PAGESIZ - 1)))
1212 + PAGESIZ;
1213 if(datalen)
1214 thisphys = KVTOPHYS(thiskv);
1215 }
1216 /***************************************\
1217 * next page isn't contiguous, finish the seg*
1218 \***************************************/
1219 if(scsi_debug & SHOWSCATGATH)
1220 printf("(0x%x)",bytes_this_seg);
1221 lto3b(bytes_this_seg,&(sg->seg_len));
1222 sg++;
1223 seg++;
1224 }
1225 }
1226 lto3b(seg * sizeof(struct aha_scat_gath),ccb->data_length);
1227 if(scsi_debug & SHOWSCATGATH)
1228 printf("\n");
1229 if (datalen)
1230 { /* there's still data, must have run out of segs! */
1231 printf("aha_scsi_cmd%d: more than %d DMA segs\n",
1232 unit,AHA_NSEG);
1233 xs->error = XS_DRIVER_STUFFUP;
1234 aha_free_ccb(unit,ccb,flags);
1235 return(HAD_ERROR);
1236 }
1237
1238 }
1239 else
1240 { /* No data xfer, use non S/G values */
1241 lto3b(0, ccb->data_addr );
1242 lto3b(0,ccb->data_length);
1243 }
1244 lto3b(0, ccb->link_addr );
1245 /***********************************************\
1246 * Put the scsi command in the ccb and start it *
1247 \***********************************************/
1248 if(!(flags & SCSI_RESET))
1249 bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
1250 if(scsi_debug & SHOWCOMMANDS)
1251 {
1252 u_char *b = (u_char *)&ccb->scsi_cmd;
1253 if(!(flags & SCSI_RESET))
1254 {
1255 int i = 0;
1256 printf("aha%d:%d:%d-"
1257 ,unit
1258 ,ccb->target
1259 ,ccb->lun );
1260 while(i < ccb->scsi_cmd_length )
1261 {
1262 if(i) printf(",");
1263 printf("%x",b[i++]);
1264 }
1265 }
1266 else
1267 {
1268 printf("aha%d:%d:%d-RESET- "
1269 ,unit
1270 ,ccb->target
1271 ,ccb->lun
1272 );
1273 }
1274 }
1275 if (!(flags & SCSI_NOMASK))
1276 {
1277 s= splbio(); /* stop instant timeouts */
1278 aha_add_timeout(ccb,xs->timeout);
1279 aha_startmbx(ccb->mbx);
1280 /***********************************************\
1281 * Usually return SUCCESSFULLY QUEUED *
1282 \***********************************************/
1283 splx(s);
1284 if(scsi_debug & TRACEINTERRUPTS)
1285 printf("sent ");
1286 return(SUCCESSFULLY_QUEUED);
1287 }
1288 aha_startmbx(ccb->mbx);
1289 if(scsi_debug & TRACEINTERRUPTS)
1290 printf("cmd_sent, waiting ");
1291 /***********************************************\
1292 * If we can't use interrupts, poll on completion*
1293 \***********************************************/
1294 {
1295 int done = 0;
1296 int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE;
1297 while((!done) && count)
1298 {
1299 i=0;
1300 while ( (!done) && i<AHA_MBX_SIZE)
1301 {
1302 if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
1303 && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
1304 == (int)ccb)))
1305 {
1306 aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
1307 aha_done(unit,ccb);
1308 done++;
1309 }
1310 i++;
1311 }
1312 count--;
1313 }
1314 if (!count)
1315 {
1316 if (!(xs->flags & SCSI_SILENT))
1317 printf("cmd fail\n");
1318 aha_abortmbx(ccb->mbx);
1319 count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE;
1320 while((!done) && count)
1321 {
1322 i=0;
1323 while ( (!done) && i<AHA_MBX_SIZE)
1324 {
1325 if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
1326 && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
1327 == (int)ccb)))
1328 {
1329 aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
1330 aha_done(unit,ccb);
1331 done++;
1332 }
1333 i++;
1334 }
1335 count--;
1336 }
1337 if(!count)
1338 {
1339 printf("abort failed in wait\n");
1340 ccb->mbx->cmd = AHA_MBO_FREE;
1341 }
1342 aha_free_ccb(unit,ccb,flags);
1343 ahaintr(unit);
1344 xs->error = XS_DRIVER_STUFFUP;
1345 return(HAD_ERROR);
1346 }
1347 ahaintr(unit);
1348 if(xs->error) return(HAD_ERROR);
1349 return(COMPLETE);
1350
1351 }
1352}
1353/***************************************************************\
1354* try each speed in turn, when we find one that works, use *
1355* the NEXT one for a safety margin, unless that doesn't exist *
1356* or doesn't work. returns the nSEC value of the time used *
1357* or 0 if it could get a working speed ( or the NEXT speed *
1358* failed) *
1359\***************************************************************/
1360
1361int aha_set_bus_speed(unit)
1362int unit;
1363{
1364 int speed;
1365 int retval,retval2;
1366
1367#ifdef EISA
1368 speed = 0; /* start at the fastest */
1369#else EISA
1370 speed = 1; /* 100 ns can crash some ISA busses (!?!) */
1371#endif EISA
1372 while (1)
1373 {
1374 retval = aha_bus_speed_check(unit,speed);
1375 if(retval == HAD_ERROR)
1376 {
1377 printf("no working bus speed!!!\n");
1378 return(0);
1379 }
1380 if(retval == 0)
1381 {
1382 speed++;
1383 }
1384 else /* Go one slower to be safe */
1385 { /* unless eisa at 100 ns.. trust it */
1386 if(speed != 0)
1387 {
1388 speed++;
1389 }
1390 printf("%d nSEC ok, use ",retval);
1391 retval2 = aha_bus_speed_check(unit,speed);
1392 if(retval2 == HAD_ERROR) /* retval is slowest already */
1393 {
1394 printf("marginal ");
1395 retval2 = retval;
1396 }
1397 if(retval2)
1398 {
1399 printf("%d nSEC ",retval2);
1400 return(retval2);
1401 }
1402 else
1403 {
1404 printf(".. slower failed, abort.\n",retval);
1405 return(0);
1406 }
1407
1408 }
1409 }
1410}
1411
1412/***************************************************************\
1413* Set the DMA speed to the Nth speed and try an xfer. If it *
1414* fails return 0, if it succeeds return the nSec value selected *
1415* If there is no such speed return HAD_ERROR. *
1416\***************************************************************/
1417static struct bus_speed
1418{
1419 char arg;
1420 int nsecs;
1421}aha_bus_speeds[] =
1422{
1423 {0x88,100},
1424 {0x99,150},
1425 {0xaa,200},
1426 {0xbb,250},
1427 {0xcc,300},
1428 {0xdd,350},
1429 {0xee,400},
1430 {0xff,450}
1431};
1432static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
1433
1434int aha_bus_speed_check(unit,speed)
1435int unit,speed;
1436{
1437 int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed);
1438 u_char ad[3];
1439
1440 /*******************************************************\
1441 * Check we have such an entry *
1442 \*******************************************************/
1443 if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */
1444
1445 /*******************************************************\
1446 * Set the dma-speed *
1447 \*******************************************************/
1448 aha_cmd(unit,1, 0, 0, 0, AHA_SPEED_SET,aha_bus_speeds[speed].arg);
1449
1450 /*******************************************************\
1451 * put the test data into the buffer and calculate *
1452 * it's address. Read it onto the board *
1453 \*******************************************************/
1454 strcpy(aha_scratch_buf,aha_test_string);
1455 lto3b(KVTOPHYS(aha_scratch_buf),ad);
1456
1457 aha_cmd(unit,3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
1458
1459 /*******************************************************\
1460 * clear the buffer then copy the contents back from the *
1461 * board. *
1462 \*******************************************************/
1463 bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */
1464
1465 aha_cmd(unit,3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
1466
1467 /*******************************************************\
1468 * Compare the original data and the final data and *
1469 * return the correct value depending upon the result *
1470 \*******************************************************/
1471 if(strcmp(aha_test_string,aha_scratch_buf))
1472 { /* copy failed.. assume too fast */
1473 return(0);
1474 }
1475 else
1476 { /* copy succeded assume speed ok */
1477 return(aha_bus_speeds[speed].nsecs);
1478 }
1479}
1480
1481
1482/*
1483 * +----------+ +----------+ +----------+
1484 * aha_soonest--->| later |--->| later|--->| later|-->0
1485 * | [Delta] | | [Delta] | | [Delta] |
1486 * 0<---|sooner |<---|sooner |<---|sooner |<---aha_latest
1487 * +----------+ +----------+ +----------+
1488 *
1489 * aha_furtherest = sum(Delta[1..n])
1490 */
1491aha_add_timeout(ccb,time)
1492struct aha_ccb *ccb;
1493int time;
1494{
1495 int timeprev;
1496 struct aha_ccb *prev;
1497 int s = splbio();
1498
1499 if(prev = aha_latest) /* yes, an assign */
1500 {
1501 timeprev = aha_furtherest;
1502 }
1503 else
1504 {
1505 timeprev = 0;
1506 }
1507 while(prev && (timeprev > time))
1508 {
1509 timeprev -= prev->delta;
1510 prev = prev->sooner;
1511 }
1512 if(prev)
1513 {
1514 ccb->delta = time - timeprev;
1515 if( ccb->later = prev->later) /* yes an assign */
1516 {
1517 ccb->later->sooner = ccb;
1518 ccb->later->delta -= ccb->delta;
1519 }
1520 else
1521 {
1522 aha_furtherest = time;
1523 aha_latest = ccb;
1524 }
1525 ccb->sooner = prev;
1526 prev->later = ccb;
1527 }
1528 else
1529 {
1530 if( ccb->later = aha_soonest) /* yes, an assign*/
1531 {
1532 ccb->later->sooner = ccb;
1533 ccb->later->delta -= time;
1534 }
1535 else
1536 {
1537 aha_furtherest = time;
1538 aha_latest = ccb;
1539 }
1540 ccb->delta = time;
1541 ccb->sooner = (struct aha_ccb *)0;
1542 aha_soonest = ccb;
1543 }
1544 splx(s);
1545}
1546
1547aha_remove_timeout(ccb)
1548struct aha_ccb *ccb;
1549{
1550 int s = splbio();
1551
1552 if(ccb->sooner)
1553 {
1554 ccb->sooner->later = ccb->later;
1555 }
1556 else
1557 {
1558 aha_soonest = ccb->later;
1559 }
1560 if(ccb->later)
1561 {
1562 ccb->later->sooner = ccb->sooner;
1563 ccb->later->delta += ccb->delta;
1564 }
1565 else
1566 {
1567 aha_latest = ccb->sooner;
1568 aha_furtherest -= ccb->delta;
1569 }
1570 ccb->sooner = ccb->later = (struct aha_ccb *)0;
1571 splx(s);
1572}
1573
1574
1575extern int hz;
1576#define ONETICK 500 /* milliseconds */
1577#define SLEEPTIME ((hz * 1000) / ONETICK)
1578aha_timeout(arg)
1579int arg;
1580{
1581 struct aha_ccb *ccb;
1582 int unit;
1583 int s = splbio();
1584
1585 while( ccb = aha_soonest )
1586 {
1587 if(ccb->delta <= ONETICK)
1588 /***********************************************\
1589 * It has timed out, we need to do some work *
1590 \***********************************************/
1591 {
1592 unit = ccb->xfer->adapter;
1593 printf("aha%d: device %d timed out ",unit
1594 ,ccb->xfer->targ);
1595
1596 /***************************************\
1597 * Unlink it from the queue *
1598 \***************************************/
1599 aha_remove_timeout(ccb);
1600
1601 /***************************************\
1602 * If The ccb's mbx is not free, then *
1603 * the board has gone south *
1604 \***************************************/
1605 if(ccb->mbx->cmd != AHA_MBO_FREE)
1606 {
1607 printf("aha%d not taking commands!\n"
1608 ,unit);
1609 Debugger();
1610 }
1611 /***************************************\
1612 * If it has been through before, then *
1613 * a previous abort has failed, don't *
1614 * try abort again *
1615 \***************************************/
1616 if(ccb->flags == CCB_ABORTED) /* abort timed out */
1617 {
1618 printf(" AGAIN\n");
1619 ccb->xfer->retries = 0; /* I MEAN IT ! */
1620 ccb->host_stat = AHA_ABORTED;
1621 aha_done(unit,ccb);
1622 }
1623 else /* abort the operation that has timed out */
1624 {
1625 printf("\n");
1626 aha_abortmbx(ccb->mbx);
1627 /* 2 secs for the abort */
1628 aha_add_timeout(ccb,2000 + ONETICK);
1629 ccb->flags = CCB_ABORTED;
1630 }
1631 }
1632 else
1633 /***********************************************\
1634 * It has not timed out, adjust and leave *
1635 \***********************************************/
1636 {
1637 ccb->delta -= ONETICK;
1638 aha_furtherest -= ONETICK;
1639 break;
1640 }
1641 }
1642 splx(s);
1643 timeout(aha_timeout,arg,SLEEPTIME);
1644}