|
|
1.1 root 1: /*
2: * Ported for use with the UltraStor 14f by Gary Close ([email protected])
3: * Thanks to Julian Elischer for advice and help with this port.
4: *
5: * Written by Julian Elischer ([email protected])
6: * for TRW Financial Systems for use under the MACH(2.5) operating system.
7: *
8: * TRW Financial Systems, in accordance with their agreement with Carnegie
9: * Mellon University, makes this software available to CMU to distribute
10: * or use in any manner that they see fit as long as this message is kept with
11: * the software. For this reason TFS also grants any other persons or
12: * organisations permission to use or modify this software.
13: *
14: * TFS supplies this software to be publicly redistributed
15: * on the understanding that TFS is not responsible for the correct
16: * functioning of this software in any circumstances.
17: *
1.1.1.2 ! root 18: * ultra14f.c,v 1.12.2.1 1993/07/22 10:06:59 cgd Exp
1.1 root 19: */
20:
21: #include <sys/types.h>
22: #include <uha.h>
23:
24: #include <sys/param.h>
25: #include <sys/systm.h>
26: #include <sys/errno.h>
27: #include <sys/ioctl.h>
28: #include <sys/buf.h>
29: #include <sys/proc.h>
30: #include <sys/user.h>
31:
32: #ifdef MACH /* EITHER CMU OR OSF */
33: #include <i386/ipl.h>
34: #include <i386at/scsi.h>
35: #include <i386at/scsiconf.h>
36:
37: #ifdef OSF /* OSF ONLY */
38: #include <sys/table.h>
39: #include <i386/handler.h>
40: #include <i386/dispatcher.h>
41: #include <i386/AT386/atbus.h>
42:
43: #else OSF /* CMU ONLY */
44: #include <i386at/atbus.h>
45: #include <i386/pio.h>
46: #endif OSF
47: #endif MACH /* end of MACH specific */
48:
49: #ifdef __386BSD__ /* 386BSD specific */
50: #define isa_dev isa_device
51: #define dev_unit id_unit
52: #define dev_addr id_iobase
53:
54: #include <i386/include/pio.h>
55: #include <i386/isa/isa_device.h>
56: #include <scsi/scsi_all.h>
57: #include <scsi/scsiconf.h>
58: #endif __386BSD__
59:
60: /**/
61:
1.1.1.2 ! root 62: #ifdef DDB
! 63: int Debugger();
! 64: #else DDB
! 65: #define Debugger() panic("should call debugger here")
! 66: #endif /* DDB */
1.1 root 67:
68: #ifdef MACH
69: int Debugger();
70: #endif MACH
71:
72: typedef struct {unsigned char addr[4]; } physaddr;
73: typedef struct {unsigned char len[4]; } physlen;
74:
75:
76: #ifdef MACH
77: extern physaddr kvtophys();
78: #define PHYSTOKV(x) phystokv(x)
79: #define KVTOPHYS(x) kvtophys(x)
80: #endif MACH
81:
82: #ifdef __386BSD__
83: #define PHYSTOKV(x) (x | 0xFE000000)
84: #define KVTOPHYS(x) vtophys(x)
85: #endif __386BSD__
86:
87: extern int delaycount; /* from clock setup code */
88: #define NUM_CONCURRENT 16 /* number of concurrent ops per board */
89: #define UHA_NSEG 33 /* number of dma segments supported */
90: #define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */
91: /**/
92: /************************** board definitions *******************************/
93: /*
94: * I/O Port Interface
95: */
96: #define UHA_LMASK (0x000) /* local doorbell mask reg */
97: #define UHA_LINT (0x001) /* local doorbell int/stat reg */
98: #define UHA_SMASK (0x002) /* system doorbell mask reg */
99: #define UHA_SINT (0x003) /* system doorbell int/stat reg */
100: #define UHA_ID0 (0x004) /* product id reg 0 */
101: #define UHA_ID1 (0x005) /* product id reg 1 */
102: #define UHA_CONF1 (0x006) /* config reg 1 */
103: #define UHA_CONF2 (0x007) /* config reg 2 */
104: #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */
105: #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */
106: #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */
107: #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */
108: #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */
109: #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */
110: #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */
111: #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */
112:
113: /*
114: * UHA_LMASK bits (read only)
115: */
116:
117: #define UHA_LDIE 0x80 /* local doorbell int enabled */
118: #define UHA_SRSTE 0x40 /* soft reset enabled */
119: #define UHA_ABORTEN 0x10 /* abort MSCP enabled */
120: #define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */
121:
122: /*
123: * UHA_LINT bits (read)
124: */
125:
126: #define UHA_LDIP 0x80 /* local doorbell int pending */
127:
128: /*
129: * UHA_LINT bits (write)
130: */
131:
132: #define UHA_ADRST 0x40 /* adapter soft reset */
133: #define UHA_SBRST 0x20 /* scsi bus reset */
134: #define UHA_ASRST 0x60 /* adapter and scsi reset */
135: #define UHA_ABORT 0x10 /* abort MSCP */
136: #define UHA_OGMINT 0x01 /* tell adapter to get mail */
137:
138: /*
139: * UHA_SMASK bits (read)
140: */
141:
142: #define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */
143: #define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */
144: #define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled
145:
146: /*
147: * UHA_SMASK bits (write)
148: */
149:
150: #define UHA_ENSINT 0x80 /* enable system doorbell interrupt */
151: #define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */
152: #define UHA_ENICM 0x01 /* enable ICM interrupt */
153:
154: /*
155: * UHA_SINT bits (read)
156: */
157:
158: #define UHA_SINTP 0x80 /* system doorbell int pending */
159: #define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */
160: #define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */
161:
162: /*
163: * UHA_SINT bits (write)
164: */
165:
166: #define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */
167: #define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */
168:
169: /*
170: * UHA_CONF1 bits (read only)
171: */
172:
173: #define UHA_DMA_CH5 0x00 /* DMA channel 5 */
174: #define UHA_DMA_CH6 0x40 /* 6 */
175: #define UHA_DMA_CH7 0x80 /* 7 */
176: #define UHA_IRQ15 0x00 /* IRQ 15 */
177: #define UHA_IRQ14 0x10 /* 14 */
178: #define UHA_IRQ11 0x20 /* 11 */
179: #define UHA_IRQ10 0x30 /* 10 */
180:
181: /***********************************
182: * ha_status error codes
183: \***********************************/
184:
185: #define UHA_NO_ERR 0x00 /* No error supposedly */
186: #define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */
187: #define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */
188: #define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */
189: #define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */
190: #define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */
191: #define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */
192: #define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */
193:
194: /**/
195:
196: struct uha_dma_seg
197: {
198: physaddr addr;
199: physlen len;
200: };
201: /**/
202:
203: struct mscp
204: {
205: unsigned char opcode:3;
206: #define U14_HAC 0x01 /*host adapter command*/
207: #define U14_TSP 0x02 /*target scsi pass through command*/
208: #define U14_SDR 0x04 /*scsi device reset*/
209: unsigned char xdir:2; /*xfer direction*/
210: #define U14_SDET 0x00 /*determined by scsi command*/
211: #define U14_SDIN 0x01 /*scsi data in*/
212: #define U14_SDOUT 0x02 /*scsi data out*/
213: #define U14_NODATA 0x03 /*no data xfer*/
214: unsigned char dcn:1; /*disable disconnect for this command*/
215: unsigned char ca:1; /*Cache control*/
216: unsigned char sgth:1; /*scatter gather flag*/
217: unsigned char target:3;
218: unsigned char chan:2; /*scsi channel (always 0 for 14f)*/
219: unsigned char lun:3;
220: physaddr data;
221: physlen datalen;
222: physaddr link;
223: unsigned char link_id;
224: unsigned char sg_num; /*number of scat gath segs */
225: /*in s-g list if sg flag is*/
226: /*set. starts at 1, 8bytes per*/
227: unsigned char senselen;
228: unsigned char cdblen;
229: unsigned char cdb[12];
230: unsigned char ha_status;
231: unsigned char targ_status;
232: physaddr sense; /* if 0 no auto sense */
233: /*-----------------end of hardware supported fields----------------*/
234: struct mscp *next; /* in free list */
235: struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
236: long int delta; /* difference from previous*/
237: struct mscp *later,*sooner;
238: int flags;
239: #define MSCP_FREE 0
240: #define MSCP_ACTIVE 1
241: #define MSCP_ABORTED 2
242: struct uha_dma_seg uha_dma[UHA_NSEG];
243: struct scsi_sense_data mscp_sense;
244: };
245:
246: struct mscp *uha_soonest = (struct mscp *)0;
247: struct mscp *uha_latest = (struct mscp *)0;
248: long int uha_furtherest = 0; /* longest time in the timeout queue */
249: /**/
250:
251: struct uha_data
252: {
253: int flags;
254: #define UHA_INIT 0x01;
255: int baseport;
256: struct mscp mscps[NUM_CONCURRENT];
257: struct mscp *free_mscp;
258: int our_id; /* our scsi id */
259: int vect;
260: int dma;
261: } uha_data[NUHA];
262:
263: int uhaprobe();
264: int uha_attach();
265: int uhaintr();
266: int uha_scsi_cmd();
267: int uha_timeout();
268: int uha_abort();
269: struct mscp *cheat;
270: void uhaminphys();
271: long int uha_adapter_info();
272:
273: unsigned long int scratch;
274:
275: #ifdef MACH
276: struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0};
277: int (*uhaintrs[])() = {uhaintr, 0};
278: #endif MACH
279:
280: #ifdef __386BSD__
281: struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"};
282: #endif __386BSD__
283:
284: static uha_unit = 0;
285: int uha_debug = 0;
286: #define UHA_SHOWMSCPS 0x01
287: #define UHA_SHOWINTS 0x02
288: #define UHA_SHOWCMDS 0x04
289: #define UHA_SHOWMISC 0x08
290: #define FAIL 1
291: #define SUCCESS 0
292: #define PAGESIZ 4096
293:
294: struct scsi_switch uha_switch =
295: {
1.1.1.2 ! root 296: "uha",
1.1 root 297: uha_scsi_cmd,
298: uhaminphys,
299: 0,
300: 0,
301: uha_adapter_info,
302: 0,0,0
303: };
304:
305: /**/
306: /***********************************************************************\
307: * Function to send a command out through a mailbox *
308: \***********************************************************************/
309: uha_send_mbox( int unit
310: ,struct mscp *mscp)
311: {
312: int port = uha_data[unit].baseport;
1.1.1.2 ! root 313: int spincount = FUDGE(delaycount) * 1000; /* 1s should be enough */
1.1 root 314: int s = splbio();
315:
316: while( ((inb(port + UHA_LINT) & (UHA_LDIP))
317: != (0))
318: && (spincount--));
319: if(spincount == -1)
320: {
321: printf("uha%d: board not responding\n",unit);
322: Debugger();
323: }
324:
325: outl(port + UHA_OGM0,KVTOPHYS(mscp));
326: outb(port + UHA_LINT, (UHA_OGMINT));
327: splx(s);
328: }
329:
330: /***********************************************************************\
331: * Function to send abort to 14f *
332: \***********************************************************************/
333:
334: uha_abort( int unit
335: ,struct mscp *mscp)
336: {
337: int port = uha_data[unit].baseport;
338: int spincount = FUDGE(delaycount) * 1;
339: int abortcount = FUDGE(delaycount) * 2000;
340: int s = splbio();
341:
342: while(((inb(port + UHA_LINT) & (UHA_LDIP))
343: != (0))
344: && (spincount--));
345: if(spincount == -1);
346: {
347: printf("uha%d: board not responding\n",unit);
348: Debugger();
349: }
350:
351: outl(port + UHA_OGM0,KVTOPHYS(mscp));
352: outb(port + UHA_LINT,UHA_ABORT);
353:
354: while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL)));
355: if(abortcount == -1)
356: {
357: printf("uha%d: board not responding\n",unit);
358: Debugger();
359: }
360: if((inb(port + UHA_SINT) & 0x10) != 0)
361: {
362: outb(port + UHA_SINT,UHA_ABORT_ACK);
363: return(1);
364: }
365: else
366: {
367: outb(port + UHA_SINT,UHA_ABORT_ACK);
368: return(0);
369: }
370: }
371:
372: /***********************************************************************\
373: * Function to poll for command completion when in poll mode *
374: \***********************************************************************/
375: uha_poll(int unit ,int wait) /* in msec */
376: {
377: int port = uha_data[unit].baseport;
378: int spincount = FUDGE(delaycount) * wait; /* in msec */
379: int stport = port + UHA_SINT;
380: int start = spincount;
381:
382: retry:
383: while( (spincount--) && (!(inb(stport) & UHA_SINTP)));
384: if(spincount == -1)
385: {
386: printf("uha%d: board not responding\n",unit);
387: return(EIO);
388: }
389: if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0)))
390: {
391: printf("discarding %x ",inl(port + UHA_ICM0));
392: outb(port + UHA_SINT, UHA_ICM_ACK);
393: spinwait(50);
394: goto retry;
395: }/* don't know this will work */
396: uhaintr(unit);
397: return(0);
398: }
399:
400: /*******************************************************\
401: * Check if the device can be found at the port given *
402: * and if so, set it up ready for further work *
403: * as an argument, takes the isa_dev structure from *
404: * autoconf.c *
405: \*******************************************************/
406: uhaprobe(dev)
407: struct isa_dev *dev;
408: {
409: int unit = uha_unit;
410: dev->dev_unit = unit;
411: uha_data[unit].baseport = dev->dev_addr;
412: if(unit >= NUHA)
413: {
414: printf("uha: unit number (%d) too high\n",unit);
415: return(0);
416: }
417:
418: /*try and initialize unit at this location*/
419: if (uha_init(unit) != 0)
420: {
421: return(0);
422: }
423:
424: /* if its there put in it's interrupt and DRQ vectors */
425:
426: dev->id_irq = (1 << uha_data[unit].vect);
427: dev->id_drq = uha_data[unit].dma;
428:
429:
430: uha_unit ++;
1.1.1.2 ! root 431: return(8);
1.1 root 432: }
433:
434: /***********************************************\
435: * Attach all the sub-devices we can find *
436: \***********************************************/
437: uha_attach(dev)
438: struct isa_dev *dev;
439: {
1.1.1.2 ! root 440: static int firsttime;
! 441: int masunit = dev->id_masunit;
! 442: int r;
! 443:
! 444: r = scsi_attach(masunit, uha_data[masunit].our_id, &uha_switch,
! 445: &dev->id_physid, &dev->id_unit, dev->id_flags);
! 446:
! 447: /* only one for all boards */
! 448: if(firsttime==0) {
! 449: firsttime = 1;
1.1 root 450: uha_timeout(0);
451: }
1.1.1.2 ! root 452: return r;
1.1 root 453: }
454:
455: /***********************************************\
456: * Return some information to the caller about *
457: * the adapter and it's capabilities *
458: \***********************************************/
459: long int uha_adapter_info(unit)
460: int unit;
461: {
462: return(2); /* 2 outstanding requests at a time per device */
463: }
464:
465: /***********************************************\
466: * Catch an interrupt from the adaptor *
467: \***********************************************/
468: uhaintr(unit)
469: {
470: struct mscp *mscp;
471: u_char uhastat;
472: unsigned long int mboxval;
473:
474: int port = uha_data[unit].baseport;
475:
476:
477: if(scsi_debug & PRINTROUTINES)
478: printf("uhaintr ");
479:
480: #if defined(OSF)
481: if (!uha_attached[unit])
482: {
483: return(1);
484: }
485: #endif /* defined(OSF) */
486: while(inb(port + UHA_SINT) & UHA_SINTP)
487: {
488: /***********************************************\
489: * First get all the information and then *
490: * acknowlege the interrupt *
491: \***********************************************/
492: uhastat = inb(port + UHA_SINT);
493: mboxval = inl(port + UHA_ICM0);
494: outb(port + UHA_SINT,UHA_ICM_ACK);
495:
496: if(scsi_debug & TRACEINTERRUPTS)
497: printf("status = 0x%x ",uhastat);
498: /***********************************************\
499: * Process the completed operation *
500: \***********************************************/
501:
502: mscp = (struct mscp *)(PHYSTOKV(mboxval));
503:
504: if(uha_debug & UHA_SHOWCMDS )
505: {
506: uha_show_scsi_cmd(mscp->xs);
507: }
508: if((uha_debug & UHA_SHOWMSCPS) && mscp)
509: printf("<int mscp(%x)>",mscp);
510: uha_remove_timeout(mscp);
511:
512: uha_done(unit,mscp);
513: }
514: return(1);
515: }
516:
517: /***********************************************\
518: * We have a mscp which has been processed by the *
519: * adaptor, now we look to see how the operation *
520: * went. *
521: \***********************************************/
522:
523: uha_done(unit,mscp)
524: int unit;
525: struct mscp *mscp;
526: {
527: struct scsi_sense_data *s1,*s2;
528: struct scsi_xfer *xs = mscp->xs;
529:
530: if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS))
531: printf("uha_done ");
532: /***********************************************\
533: * Otherwise, put the results of the operation *
534: * into the xfer and call whoever started it *
535: \***********************************************/
536: if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK))
537: { /* All went correctly OR errors expected */
538: xs->resid = 0;
539: xs->error = 0;
540: }
541: else
542: {
543:
544: s1 = &(mscp->mscp_sense);
545: s2 = &(xs->sense);
546:
547: if(mscp->ha_status != UHA_NO_ERR)
548: {
549: switch(mscp->ha_status)
550: {
551: case UHA_SBUS_TIMEOUT: /* No response */
552: if (uha_debug & UHA_SHOWMISC)
553: {
554: printf("timeout reported back\n");
555: }
556: xs->error = XS_TIMEOUT;
557: break;
558: case UHA_SBUS_OVER_UNDER:
559: if (uha_debug & UHA_SHOWMISC)
560: {
561: printf("scsi bus xfer over/underrun\n");
562: }
563: xs->error = XS_DRIVER_STUFFUP;
564: break;
565: case UHA_BAD_SG_LIST:
566: if (uha_debug & UHA_SHOWMISC)
567: {
568: printf("bad sg list reported back\n");
569: }
570: xs->error = XS_DRIVER_STUFFUP;
571: break;
572: default: /* Other scsi protocol messes */
573: xs->error = XS_DRIVER_STUFFUP;
574: if (uha_debug & UHA_SHOWMISC)
575: {
576: printf("unexpected ha_status: %x\n",
577: mscp->ha_status);
578: }
579: }
580:
581: }
582: else
583: {
584:
585: if (mscp->targ_status != 0)
586: /**************************************************************************\
587: * I have no information for any possible value of target status field *
588: * other than 0 means no error!! So I guess any error is unexpected in that *
589: * event!! *
590: \**************************************************************************/
591:
592: {
593: if (uha_debug & UHA_SHOWMISC)
594: {
595: printf("unexpected targ_status: %x\n",
596: mscp->targ_status);
597: }
598: xs->error = XS_DRIVER_STUFFUP;
599: }
600: }
601: }
602: done: xs->flags |= ITSDONE;
603: uha_free_mscp(unit,mscp, xs->flags);
604: if(xs->when_done)
605: (*(xs->when_done))(xs->done_arg,xs->done_arg2);
606: }
607:
608: /***********************************************\
609: * A mscp (and hence a mbx-out is put onto the *
610: * free list. *
611: \***********************************************/
612: uha_free_mscp(unit,mscp, flags)
613: struct mscp *mscp;
614: {
615: unsigned int opri;
616:
617: if(scsi_debug & PRINTROUTINES)
618: printf("mscp%d(0x%x)> ",unit,flags);
619: if (!(flags & SCSI_NOMASK))
620: opri = splbio();
621:
622: mscp->next = uha_data[unit].free_mscp;
623: uha_data[unit].free_mscp = mscp;
624: mscp->flags = MSCP_FREE;
625: /***********************************************\
626: * If there were none, wake abybody waiting for *
627: * one to come free, starting with queued entries*
628: \***********************************************/
629: if (!mscp->next) {
630: wakeup(&uha_data[unit].free_mscp);
631: }
632: if (!(flags & SCSI_NOMASK))
633: splx(opri);
634: }
635:
636: /***********************************************\
637: * Get a free mscp (and hence mbox-out entry) *
638: \***********************************************/
639: struct mscp *
640: uha_get_mscp(unit,flags)
641: {
642: unsigned opri;
643: struct mscp *rc;
644:
645: if(scsi_debug & PRINTROUTINES)
646: printf("<mscp%d(0x%x) ",unit,flags);
647: if (!(flags & SCSI_NOMASK))
648: opri = splbio();
649: /***********************************************\
650: * If we can and have to, sleep waiting for one *
651: * to come free *
652: \***********************************************/
653: while ((!(rc = uha_data[unit].free_mscp)) && (!(flags & SCSI_NOSLEEP)))
654: {
655: sleep(&uha_data[unit].free_mscp, PRIBIO);
656: }
657: if (rc)
658: {
659: uha_data[unit].free_mscp = rc->next;
660: rc->flags = MSCP_ACTIVE;
661: }
662: if (!(flags & SCSI_NOMASK))
663: splx(opri);
664: return(rc);
665: }
666:
667:
668:
669: /***********************************************\
670: * Start the board, ready for normal operation *
671: \***********************************************/
672:
673: uha_init(unit)
674: int unit;
675: {
676: unsigned char ad[4];
677: volatile unsigned char model;
678: volatile unsigned char submodel;
679: unsigned char config_reg1;
680: unsigned char config_reg2;
681: unsigned char dma_ch;
682: unsigned char irq_ch;
683: unsigned char uha_id;
684: int port = uha_data[unit].baseport;
685: int i;
686: int resetcount = FUDGE(delaycount) * 4000;
687:
688: model = inb(port + UHA_ID0);
689: submodel = inb(port + UHA_ID1);
690: if ((model != 0x56) & (submodel != 0x40))
691: { /* printf("ultrastor 14f not responding\n"); */
692: return(ENXIO); }
693:
694: printf("uha%d reading board settings, ",unit);
695:
696: config_reg1 = inb(port + UHA_CONF1);
697: config_reg2 = inb(port + UHA_CONF2);
698: dma_ch = (config_reg1 & 0xc0);
699: irq_ch = (config_reg1 & 0x30);
700: uha_id = (config_reg2 & 0x07);
701:
702: switch(dma_ch)
703: {
704: case UHA_DMA_CH5:
705: uha_data[unit].dma = 5;
706: printf("dma=5 ");
707: break;
708: case UHA_DMA_CH6:
709: uha_data[unit].dma = 6;
710: printf("dma=6 ");
711: break;
712: case UHA_DMA_CH7:
713: uha_data[unit].dma = 7;
714: printf("dma=7 ");
715: break;
716: default:
717: printf("illegal dma jumper setting\n");
718: return(EIO);
719: }
720: switch(irq_ch)
721: {
722: case UHA_IRQ10:
723: uha_data[unit].vect = 10;
724: printf("int=10 ");
725: break;
726: case UHA_IRQ11:
727: uha_data[unit].vect = 11;
728: printf("int=11 ");
729: break;
730: case UHA_IRQ14:
731: uha_data[unit].vect = 14;
732: printf("int=14 ");
733: break;
734: case UHA_IRQ15:
735: uha_data[unit].vect = 15;
736: printf("int=15 ");
737: break;
738: default:
739: printf("illegal int jumper setting\n");
740: return(EIO);
741: }
742: /* who are we on the scsi bus */
743: printf("id=%x\n",uha_id);
744: uha_data[unit].our_id = uha_id;
745:
746:
747: /***********************************************\
748: * link up all our MSCPs into a free list *
749: \***********************************************/
750: for (i=0; i < NUM_CONCURRENT; i++)
751: {
752: uha_data[unit].mscps[i].next = uha_data[unit].free_mscp;
753: uha_data[unit].free_mscp = &uha_data[unit].mscps[i];
754: uha_data[unit].free_mscp->flags = MSCP_FREE;
755: }
756:
757: /***********************************************\
758: * Note that we are going and return (to probe) *
759: \***********************************************/
760: outb(port + UHA_LINT, UHA_ASRST);
761: while( (resetcount--) && (!(inb(port + UHA_LINT))));
762: if(resetcount == -1)
763: {
764: printf("uha%d: board timed out during reset\n",unit);
765: return(ENXIO);
766: }
767:
768: outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */
769: uha_data[unit].flags |= UHA_INIT;
770: return(0);
771: }
772:
773:
774:
775: #ifndef min
776: #define min(x,y) (x < y ? x : y)
777: #endif min
778:
779:
780: void uhaminphys(bp)
781: struct buf *bp;
782: {
783: #ifdef MACH
784: #if !defined(OSF)
785: bp->b_flags |= B_NPAGES; /* can support scat/gather */
786: #endif /* defined(OSF) */
787: #endif MACH
788: if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ))
789: {
790: bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ);
791: }
792: }
793:
794: /***********************************************\
795: * start a scsi operation given the command and *
796: * the data address. Also needs the unit, target *
797: * and lu *
798: \***********************************************/
799: int uha_scsi_cmd(xs)
800: struct scsi_xfer *xs;
801: {
802: struct scsi_sense_data *s1,*s2;
803: struct mscp *mscp;
804: struct uha_dma_seg *sg;
805: int seg; /* scatter gather seg being worked on */
806: int i = 0;
807: int rc = 0;
808: int thiskv;
809: unsigned long int thisphys,nextphys;
810: int unit =xs->adapter;
811: int bytes_this_seg,bytes_this_page,datalen,flags;
812: struct iovec *iovp;
813: int s;
814: unsigned int stat;
815: int port = uha_data[unit].baseport;
816: unsigned long int templen;
817:
818:
819: if(scsi_debug & PRINTROUTINES)
820: printf("uha_scsi_cmd ");
821: /***********************************************\
822: * get a mscp (mbox-out) to use. If the transfer *
823: * is from a buf (possibly from interrupt time) *
824: * then we can't allow it to sleep *
825: \***********************************************/
826: flags = xs->flags;
827: if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
828: if(flags & ITSDONE)
829: {
830: printf("Already done?");
831: xs->flags &= ~ITSDONE;
832: }
833: if(!(flags & INUSE))
834: {
835: printf("Not in use?");
836: xs->flags |= INUSE;
837: }
838: if (!(mscp = uha_get_mscp(unit,flags)))
839: {
840: xs->error = XS_DRIVER_STUFFUP;
841: return(TRY_AGAIN_LATER);
842: }
843:
844: cheat = mscp;
845: if(uha_debug & UHA_SHOWMSCPS)
846: printf("<start mscp(%x)>",mscp);
847: if(scsi_debug & SHOWCOMMANDS)
848: {
849: uha_show_scsi_cmd(xs);
850: }
851: mscp->xs = xs;
852: /***********************************************\
853: * Put all the arguments for the xfer in the mscp *
854: \***********************************************/
855:
856: if (flags & SCSI_RESET)
857: {
858: mscp->opcode = 0x04;
859: mscp->ca = 0x01;
860: }
861: else
862: {
863: mscp->opcode = 0x02;
864: mscp->ca = 0x01;
865: }
866:
867: if (flags & SCSI_DATA_IN)
868: {
869: mscp->xdir = 0x01;
870: }
871: if (flags & SCSI_DATA_OUT)
872: {
873: mscp->xdir = 0x02;
874: }
875:
876: if (xs->lu != 0)
877: {
878: xs->error = XS_DRIVER_STUFFUP;
879: uha_free_mscp(unit,mscp,flags);
880: return(HAD_ERROR);
881: }
882:
883: mscp->dcn = 0x00;
884: mscp->chan = 0x00;
885: mscp->target = xs->targ;
886: mscp->lun = xs->lu;
887: mscp->link.addr[0] = 0x00;
888: mscp->link.addr[1] = 0x00;
889: mscp->link.addr[2] = 0x00;
890: mscp->link.addr[3] = 0x00;
891: mscp->link_id = 0x00;
892: mscp->cdblen = xs->cmdlen;
893: scratch = KVTOPHYS(&(mscp->mscp_sense));
894: mscp->sense.addr[0] = (scratch & 0xff);
895: mscp->sense.addr[1] = ((scratch >> 8) & 0xff);
896: mscp->sense.addr[2] = ((scratch >> 16) & 0xff);
897: mscp->sense.addr[3] = ((scratch >> 24) & 0xff);
898: mscp->senselen = sizeof(mscp->mscp_sense);
899: mscp->ha_status = 0x00;
900: mscp->targ_status = 0x00;
901:
902: if(xs->datalen)
903: { /* should use S/G only if not zero length */
904: scratch = KVTOPHYS(mscp->uha_dma);
905: mscp->data.addr[0] = (scratch & 0xff);
906: mscp->data.addr[1] = ((scratch >> 8) & 0xff);
907: mscp->data.addr[2] = ((scratch >> 16) & 0xff);
908: mscp->data.addr[3] = ((scratch >> 24) & 0xff);
909: sg = mscp->uha_dma ;
910: seg = 0;
911: mscp->sgth = 0x01;
912:
913: if(flags & SCSI_DATA_UIO)
914: {
915: iovp = ((struct uio *)xs->data)->uio_iov;
916: datalen = ((struct uio *)xs->data)->uio_iovcnt;
917: xs->datalen = 0;
918: while ((datalen) && (seg < UHA_NSEG))
919: {
920: scratch = (unsigned long)iovp->iov_base;
921: sg->addr.addr[0] = (scratch & 0xff);
922: sg->addr.addr[1] = ((scratch >> 8) & 0xff);
923: sg->addr.addr[2] = ((scratch >> 16) & 0xff);
924: sg->addr.addr[3] = ((scratch >> 24) & 0xff);
925: xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len;
926: if(scsi_debug & SHOWSCATGATH)
927: printf("(0x%x@0x%x)"
928: ,iovp->iov_len
929: ,iovp->iov_base);
930: sg++;
931: iovp++;
932: seg++;
933: datalen--;
934: }
935: }
936: else
937: {
938: /***********************************************\
939: * Set up the scatter gather block *
940: \***********************************************/
941:
942: if(scsi_debug & SHOWSCATGATH)
943: printf("%d @0x%x:- ",xs->datalen,xs->data);
944: datalen = xs->datalen;
945: thiskv = (int)xs->data;
946: thisphys = KVTOPHYS(thiskv);
947: templen = 0;
948:
949: while ((datalen) && (seg < UHA_NSEG))
950: {
951: bytes_this_seg = 0;
952:
953: /* put in the base address */
954: sg->addr.addr[0] = (thisphys & 0xff);
955: sg->addr.addr[1] = ((thisphys >> 8) & 0xff);
956: sg->addr.addr[2] = ((thisphys >> 16) & 0xff);
957: sg->addr.addr[3] = ((thisphys >> 24) & 0xff);
958:
959: if(scsi_debug & SHOWSCATGATH)
960: printf("0x%x",thisphys);
961:
962: /* do it at least once */
963: nextphys = thisphys;
964: while ((datalen) && (thisphys == nextphys))
965: /*********************************************\
966: * This page is contiguous (physically) with *
967: * the the last, just extend the length *
968: \*********************************************/
969: {
970: /* how far to the end of the page */
971: nextphys = (thisphys & (~(PAGESIZ - 1)))
972: + PAGESIZ;
973: bytes_this_page = nextphys - thisphys;
974: /**** or the data ****/
975: bytes_this_page = min(bytes_this_page
976: ,datalen);
977: bytes_this_seg += bytes_this_page;
978: datalen -= bytes_this_page;
979:
980: /* get more ready for the next page */
981: thiskv = (thiskv & (~(PAGESIZ - 1)))
982: + PAGESIZ;
983: if(datalen)
984: thisphys = KVTOPHYS(thiskv);
985: }
986: /********************************************\
987: * next page isn't contiguous, finish the seg *
988: \********************************************/
989: if(scsi_debug & SHOWSCATGATH)
990: printf("(0x%x)",bytes_this_seg);
991: sg->len.len[0] = (bytes_this_seg & 0xff);
992: sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff);
993: sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff);
994: sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff);
995: templen += bytes_this_seg;
996: sg++;
997: seg++;
998: }
999: } /*end of iov/kv decision */
1000: mscp->datalen.len[0] = (templen & 0xff);
1001: mscp->datalen.len[1] = ((templen >> 8) & 0xff);
1002: mscp->datalen.len[2] = ((templen >> 16) & 0xff);
1003: mscp->datalen.len[3] = ((templen >> 24) & 0xff);
1004: mscp->sg_num = seg;
1005:
1006: if(scsi_debug & SHOWSCATGATH)
1007: printf("\n");
1008: if (datalen)
1009: { /* there's still data, must have run out of segs! */
1010: printf("uha_scsi_cmd%d: more than %d DMA segs\n",
1011: unit,UHA_NSEG);
1012: xs->error = XS_DRIVER_STUFFUP;
1013: uha_free_mscp(unit,mscp,flags);
1014: return(HAD_ERROR);
1015: }
1016:
1017: }
1018: else
1019: { /* No data xfer, use non S/G values */
1020: mscp->data.addr[0] = 0x00;
1021: mscp->data.addr[1] = 0x00;
1022: mscp->data.addr[2] = 0x00;
1023: mscp->data.addr[3] = 0x00;
1024: mscp->datalen.len[0] = 0x00;
1025: mscp->datalen.len[1] = 0x00;
1026: mscp->datalen.len[2] = 0x00;
1027: mscp->datalen.len[3] = 0x00;
1028: mscp->xdir = 0x03;
1029: mscp->sgth = 0x00;
1030: mscp->sg_num = 0x00;
1031: }
1032:
1033: /***********************************************\
1034: * Put the scsi command in the mscp and start it *
1035: \***********************************************/
1036: bcopy(xs->cmd, mscp->cdb, xs->cmdlen);
1037:
1038: /***********************************************\
1039: * Usually return SUCCESSFULLY QUEUED *
1040: \***********************************************/
1041: if (!(flags & SCSI_NOMASK))
1042: {
1043: s = splbio();
1044: uha_send_mbox(unit,mscp);
1045: uha_add_timeout(mscp,xs->timeout);
1046: splx(s);
1047: if(scsi_debug & TRACEINTERRUPTS)
1048: printf("cmd_sent ");
1049: return(SUCCESSFULLY_QUEUED);
1050: }
1051: /***********************************************\
1052: * If we can't use interrupts, poll on completion*
1053: \***********************************************/
1054: uha_send_mbox(unit,mscp);
1055: if(scsi_debug & TRACEINTERRUPTS)
1056: printf("cmd_wait ");
1057: do
1058: {
1059: if(uha_poll(unit,xs->timeout))
1060: {
1061: if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n");
1062: if(!(uha_abort(unit,mscp)))
1063: {
1064: printf("abort failed in wait\n");
1065: uha_free_mscp(unit,mscp,flags);
1066: }
1067: xs->error = XS_DRIVER_STUFFUP;
1068: splx(s);
1069: return(HAD_ERROR);
1070: }
1071: } while (!(xs->flags & ITSDONE));/* something (?) else finished */
1072: splx(s);
1073: scsi_debug = 0;uha_debug = 0;
1074: if(xs->error)
1075: {
1076: return(HAD_ERROR);
1077: }
1078: return(COMPLETE);
1079: }
1080:
1081: /*
1082: * +----------+ +----------+ +----------+
1083: * uha_soonest--->| later |--->| later|--->| later|--->0
1084: * | [Delta] | | [Delta] | | [Delta] |
1085: * 0<---|sooner |<---|sooner |<---|sooner |<---uha_latest
1086: * +----------+ +----------+ +----------+
1087: *
1088: * uha_furtherest = sum(Delta[1..n])
1089: */
1090: uha_add_timeout(mscp,time)
1091: struct mscp *mscp;
1092: int time;
1093: {
1094: int timeprev;
1095: struct mscp *prev;
1096: int s = splbio();
1097:
1098: if(prev = uha_latest) /* yes, an assign */
1099: {
1100: timeprev = uha_furtherest;
1101: }
1102: else
1103: {
1104: timeprev = 0;
1105: }
1106: while(prev && (timeprev > time))
1107: {
1108: timeprev -= prev->delta;
1109: prev = prev->sooner;
1110: }
1111: if(prev)
1112: {
1113: mscp->delta = time - timeprev;
1114: if( mscp->later = prev->later) /* yes an assign */
1115: {
1116: mscp->later->sooner = mscp;
1117: mscp->later->delta -= mscp->delta;
1118: }
1119: else
1120: {
1121: uha_furtherest = time;
1122: uha_latest = mscp;
1123: }
1124: mscp->sooner = prev;
1125: prev->later = mscp;
1126: }
1127: else
1128: {
1129: if( mscp->later = uha_soonest) /* yes, an assign*/
1130: {
1131: mscp->later->sooner = mscp;
1132: mscp->later->delta -= time;
1133: }
1134: else
1135: {
1136: uha_furtherest = time;
1137: uha_latest = mscp;
1138: }
1139: mscp->delta = time;
1140: mscp->sooner = (struct mscp *)0;
1141: uha_soonest = mscp;
1142: }
1143: splx(s);
1144: }
1145:
1146: uha_remove_timeout(mscp)
1147: struct mscp *mscp;
1148: {
1149: int s = splbio();
1150:
1151: if(mscp->sooner)
1152: {
1153: mscp->sooner->later = mscp->later;
1154: }
1155: else
1156: {
1157: uha_soonest = mscp->later;
1158: }
1159: if(mscp->later)
1160: {
1161: mscp->later->sooner = mscp->sooner;
1162: mscp->later->delta += mscp->delta;
1163: }
1164: else
1165: {
1166: uha_latest = mscp->sooner;
1167: uha_furtherest -= mscp->delta;
1168: }
1169: mscp->sooner = mscp->later = (struct mscp *)0;
1170: splx(s);
1171: }
1172:
1173:
1174: extern int hz;
1175: #define ONETICK 500 /* milliseconds */
1176: #define SLEEPTIME ((hz * 1000) / ONETICK)
1177: uha_timeout(arg)
1178: int arg;
1179: {
1180: struct mscp *mscp;
1181: int unit;
1182: int s = splbio();
1183: unsigned int stat;
1184: int port = uha_data[unit].baseport;
1185:
1186: while( mscp = uha_soonest )
1187: {
1188: if(mscp->delta <= ONETICK)
1189: /***********************************************\
1190: * It has timed out, we need to do some work *
1191: \***********************************************/
1192: {
1193: unit = mscp->xs->adapter;
1194: printf("uha%d:%d device timed out\n",unit
1195: ,mscp->xs->targ);
1196: if(uha_debug & UHA_SHOWMSCPS)
1197: uha_print_active_mscp();
1198:
1199: /***************************************\
1200: * Unlink it from the queue *
1201: \***************************************/
1202: uha_remove_timeout(mscp);
1203:
1204: if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED))
1205: {
1206: printf("AGAIN");
1207: mscp->xs->retries = 0; /* I MEAN IT ! */
1208: uha_done(unit,mscp,FAIL);
1209: }
1210: else /* abort the operation that has timed out */
1211: {
1212: printf("\n");
1213: uha_add_timeout(mscp,2000 + ONETICK);
1214: mscp->flags = MSCP_ABORTED;
1215: }
1216: }
1217: else
1218: /***********************************************\
1219: * It has not timed out, adjust and leave *
1220: \***********************************************/
1221: {
1222: mscp->delta -= ONETICK;
1223: uha_furtherest -= ONETICK;
1224: break;
1225: }
1226: }
1227: splx(s);
1228: timeout(uha_timeout,arg,SLEEPTIME);
1229: }
1230:
1231: uha_show_scsi_cmd(struct scsi_xfer *xs)
1232: {
1233: u_char *b = (u_char *)xs->cmd;
1234: int i = 0;
1235: if(!(xs->flags & SCSI_RESET))
1236: {
1237: printf("uha%d:%d:%d-"
1238: ,xs->adapter
1239: ,xs->targ
1240: ,xs->lu);
1241: while(i < xs->cmdlen )
1242: {
1243: if(i) printf(",");
1244: printf("%x",b[i++]);
1245: }
1246: printf("-\n");
1247: }
1248: else
1249: {
1250: printf("uha%d:%d:%d-RESET-\n"
1251: ,xs->adapter
1252: ,xs->targ
1253: ,xs->lu
1254: );
1255: }
1256: }
1257: uha_print_mscp(mscp)
1258: struct mscp *mscp;
1259: {
1260: printf("mscp:%x op:%x cmdlen:%d senlen:%d\n"
1261: ,mscp
1262: ,mscp->opcode
1263: ,mscp->cdblen
1264: ,mscp->senselen);
1265: printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n"
1266: ,mscp->sgth
1267: ,mscp->sg_num
1268: ,mscp->datalen
1269: ,mscp->ha_status
1270: ,mscp->targ_status
1271: ,mscp->delta
1272: ,mscp->flags);
1273: uha_show_scsi_cmd(mscp->xs);
1274: }
1275:
1276: uha_print_active_mscp()
1277: {
1278: struct mscp *mscp;
1279: mscp = uha_soonest;
1280:
1281: while(mscp)
1282: {
1283: uha_print_mscp(mscp);
1284: mscp = mscp->later;
1285: }
1286: printf("Furtherest = %d\n",uha_furtherest);
1287: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.