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