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