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