]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdmylex.c
kernel: cleanup makefile for $CONF.$O target
[plan9front.git] / sys / src / 9 / pc / sdmylex.c
1 /*
2  * Mylex MultiMaster (Buslogic BT-*) SCSI Host Adapter
3  * in both 24-bit and 32-bit mode.
4  * 24-bit mode works for Adaptec AHA-154xx series too.
5  *
6  * To do:
7  *      allocate more Ccb's as needed, up to NMbox-1;
8  *      add nmbox and nccb to Ctlr struct for the above;
9  *      64-bit LUN/explicit wide support necessary?
10  *
11  */
12 #include "u.h"
13 #include "../port/lib.h"
14 #include "mem.h"
15 #include "dat.h"
16 #include "fns.h"
17 #include "io.h"
18 #include "ureg.h"
19 #include "../port/error.h"
20
21 #include "../port/sd.h"
22
23 #define K2BPA(va, tbdf) PADDR(va)
24 #define BPA2K(pa, tbdf) KADDR(pa)
25
26 extern SDifc sdmylexifc;
27
28 enum {                                  /* registers */
29         Rcontrol        = 0x00,         /* WO: control register */
30         Rstatus         = 0x00,         /* RO: status register */
31         Rcpr            = 0x01,         /* WO: command/parameter register */
32         Rdatain         = 0x01,         /* RO: data-in register */
33         Rinterrupt      = 0x02,         /* RO: interrupt register */
34 };
35
36 enum {                                  /* Rcontrol */
37         Rsbus           = 0x10,         /* SCSI Bus Reset */
38         Rint            = 0x20,         /* Interrupt Reset */
39         Rsoft           = 0x40,         /* Soft Reset */
40         Rhard           = 0x80,         /* Hard Reset */
41 };
42
43 enum {                                  /* Rstatus */
44         Cmdinv          = 0x01,         /* Command Invalid */
45         Dirrdy          = 0x04,         /* Data In Register Ready */
46         Cprbsy          = 0x08,         /* Command/Parameter Register Busy */
47         Hardy           = 0x10,         /* Host Adapter Ready */
48         Inreq           = 0x20,         /* Initialisation Required */
49         Dfail           = 0x40,         /* Diagnostic Failure */
50         Dact            = 0x80,         /* Diagnostic Active */
51 };
52
53 enum {                                  /* Rcpr */
54         Cinitialise     = 0x01,         /* Initialise Mailbox */
55         Cstart          = 0x02,         /* Start Mailbox Command */
56         Cinquiry        = 0x04,         /* Adapter Inquiry */
57         Ceombri         = 0x05,         /* Enable OMBR Interrupt */
58         Cinquire        = 0x0B,         /* Inquire Configuration */
59         Cextbios        = 0x28,         /* AHA-1542: extended BIOS info. */
60         Cmbienable      = 0x29,         /* AHA-1542: Mailbox interface enable */
61         Ciem            = 0x81,         /* Initialise Extended Mailbox */
62         Ciesi           = 0x8D,         /* Inquire Extended Setup Information */
63         Cerrm           = 0x8F,         /* Enable strict round-robin mode */
64         Cwide           = 0x96,         /* Wide CCB */
65 };
66
67 enum {                                  /* Rinterrupt */
68         Imbl            = 0x01,         /* Incoming Mailbox Loaded */
69         Mbor            = 0x02,         /* Mailbox Out Ready */
70         Cmdc            = 0x04,         /* Command Complete */
71         Rsts            = 0x08,         /* SCSI Reset State */
72         Intv            = 0x80,         /* Interrupt Valid */
73 };
74
75 typedef struct Mbox24 Mbox24;
76 struct Mbox24 {
77         uchar   code;                   /* action/completion code */
78         uchar   ccb[3];                 /* CCB pointer (MSB, ..., LSB) */
79 };
80
81 typedef struct Mbox32 Mbox32;
82 struct Mbox32 {
83         uchar   ccb[4];                 /* CCB pointer (LSB, ..., MSB) */
84         uchar   btstat;                 /* BT-7[45]7[SD] status */
85         uchar   sdstat;                 /* SCSI device status */
86         uchar   pad;
87         uchar   code;                   /* action/completion code */
88 };
89
90 enum {                                  /* mailbox commands */
91         Mbfree          = 0x00,         /* Mailbox not in use */
92
93         Mbostart        = 0x01,         /* Start a mailbox command */
94         Mboabort        = 0x02,         /* Abort a mailbox command */
95
96         Mbiok           = 0x01,         /* CCB completed without error */
97         Mbiabort        = 0x02,         /* CCB aborted at request of host */
98         Mbinx           = 0x03,         /* Aborted CCB not found */
99         Mbierror        = 0x04,         /* CCB completed with error */
100 };
101
102 typedef struct Ccb24 Ccb24;
103 typedef struct Ccb32 Ccb32;
104 typedef union Ccb Ccb;
105
106 typedef struct Ccb24 {
107         uchar   opcode;                 /* Operation code */
108         uchar   datadir;                /* Data direction control */
109         uchar   cdblen;                 /* Length of CDB */
110         uchar   senselen;               /* Length of sense area */
111         uchar   datalen[3];             /* Data length (MSB, ..., LSB) */
112         uchar   dataptr[3];             /* Data pointer (MSB, ..., LSB) */
113         uchar   linkptr[3];             /* Link pointer (MSB, ..., LSB) */
114         uchar   linkid;                 /* command linking identifier */
115         uchar   btstat;                 /* BT-* adapter status */
116         uchar   sdstat;                 /* SCSI device status */
117         uchar   reserved[2];            /* */
118         uchar   cs[12+0xFF];            /* Command descriptor block + Sense */
119
120         void*   data;                   /* buffer if address > 24-bits */
121
122         Rendez;
123         int     done;                   /* command completed */
124
125         Ccb*    ccb;                    /* link on free list */
126 } Ccb24;
127
128
129 typedef struct Ccb32 {
130         uchar   opcode;                 /* Operation code */
131         uchar   datadir;                /* Data direction control */
132         uchar   cdblen;                 /* Length of CDB */
133         uchar   senselen;               /* Length of sense area */
134         uchar   datalen[4];             /* Data length (LSB, ..., MSB) */
135         uchar   dataptr[4];             /* Data pointer (LSB, ..., MSB) */
136         uchar   reserved[2];
137         uchar   btstat;                 /* BT-* adapter status */
138         uchar   sdstat;                 /* SCSI device status */
139         uchar   targetid;               /* Target ID */
140         uchar   luntag;                 /* LUN & tag */
141         uchar   cdb[12];                /* Command descriptor block */
142         uchar   ccbctl;                 /* CCB control */
143         uchar   linkid;                 /* command linking identifier */
144         uchar   linkptr[4];             /* Link pointer (LSB, ..., MSB) */
145         uchar   senseptr[4];            /* Sense pointer (LSB, ..., MSB) */
146         uchar   sense[0xFF];            /* Sense bytes */
147
148         Rendez;
149         int     done;                   /* command completed */
150
151         Ccb*    ccb;                    /* link on free list */
152 } Ccb32;
153
154 typedef union Ccb {
155         Ccb24;
156         Ccb32;
157 } Ccb;
158
159 enum {                                  /* opcode */
160         OInitiator      = 0x00,         /* initiator CCB */
161         Ordl            = 0x03,         /* initiator CCB with
162                                          * residual data length returned
163                                          */
164 };
165
166 enum {                                  /* datadir */
167         CCBdatain       = 0x08,         /* inbound, length is checked */
168         CCBdataout      = 0x10,         /* outbound, length is checked */
169 };
170
171 enum {                                  /* btstat */
172         Eok             = 0x00,         /* normal completion with no errors */
173 };
174
175 enum {                                  /* luntag */
176         TagEnable       = 0x20,         /* Tag enable */
177         SQTag           = 0x00,         /* Simple Queue Tag */
178         HQTag           = 0x40,         /* Head of Queue Tag */
179         OQTag           = 0x80,         /* Ordered Queue Tag */
180 };
181
182 enum {                                  /* CCB control */
183         NoDisc          = 0x08,         /* No disconnect */
184         NoUnd           = 0x10,         /* No underrrun error report */
185         NoData          = 0x20,         /* No data transfer */
186         NoStat          = 0x40,         /* No CCB status if zero */
187         NoIntr          = 0x80,         /* No Interrupts */
188 };
189
190 typedef struct Ctlr Ctlr;
191 struct Ctlr {
192         int     port;                   /* I/O port */
193         int     id;                     /* adapter SCSI id */
194         int     bus;                    /* 24 or 32 -bit */
195         int     irq;
196         int     wide;
197         Pcidev* pcidev;
198         SDev*   sdev;
199         int     spurious;
200
201         Lock    issuelock;
202
203         Lock    ccblock;
204         QLock   ccbq;
205         Rendez  ccbr;
206
207         Lock    mboxlock;
208         void*   mb;                     /* mailbox out + mailbox in */
209         int     mbox;                   /* current mailbox out index into mb */
210         int     mbix;                   /* current mailbox in index into mb */
211
212         Lock    cachelock;
213         Ccb*    ccb;                    /* list of free Ccb's */
214         Ccb**   cache;                  /* last completed Ccb */
215 };
216
217 /*
218  * The number of mailboxes should be a multiple of 8 (4 for Mbox32)
219  * to ensure the boundary between the out and in mailboxes doesn't
220  * straddle a cache-line boundary.
221  * The number of Ccb's should be less than the number of mailboxes to
222  * ensure no queueing is necessary on mailbox allocation.
223  */
224 enum {
225         NMbox           = 8*8,          /* number of Mbox's */
226         NCcb            = NMbox-1,      /* number of Ccb's */
227 };
228
229 #define PADDR24(a, n)   ((PADDR(a)+(n)) <= (1<<24))
230
231 static void
232 ccbfree(Ctlr* ctlr, Ccb* ccb)
233 {
234         lock(&ctlr->ccblock);
235         if(ctlr->bus == 24)
236                 ((Ccb24*)ccb)->ccb = ctlr->ccb;
237         else
238                 ((Ccb32*)ccb)->ccb = ctlr->ccb;
239         if(ctlr->ccb == nil)
240                 wakeup(&ctlr->ccbr);
241         ctlr->ccb = ccb;
242         unlock(&ctlr->ccblock);
243 }
244
245 static int
246 ccbavailable(void* a)
247 {
248         return ((Ctlr*)a)->ccb != nil;
249 }
250
251 static Ccb*
252 ccballoc(Ctlr* ctlr)
253 {
254         Ccb *ccb;
255
256         for(;;){
257                 lock(&ctlr->ccblock);
258                 if((ccb = ctlr->ccb) != nil){
259                         if(ctlr->bus == 24)
260                                  ctlr->ccb = ((Ccb24*)ccb)->ccb;
261                         else
262                                  ctlr->ccb = ((Ccb32*)ccb)->ccb;
263                         unlock(&ctlr->ccblock);
264                         break;
265                 }
266
267                 unlock(&ctlr->ccblock);
268                 qlock(&ctlr->ccbq);
269                 if(waserror()){
270                         qunlock(&ctlr->ccbq);
271                         continue;
272                 }
273                 sleep(&ctlr->ccbr, ccbavailable, ctlr);
274                 qunlock(&ctlr->ccbq);
275                 poperror();
276         }
277
278         return ccb;
279 }
280
281 static int
282 done24(void* arg)
283 {
284         return ((Ccb24*)arg)->done;
285 }
286
287 static int
288 mylex24rio(SDreq* r)
289 {
290         ulong p;
291         Ctlr *ctlr;
292         Ccb24 *ccb;
293         Mbox24 *mb;
294         uchar *data, lun, *sense;
295         int d, n, btstat, sdstat, target;
296
297         ctlr = r->unit->dev->ctlr;
298         target = r->unit->subno;
299         lun = (r->cmd[1]>>5) & 0x07;
300
301         /*
302          * Ctlr->cache holds the last completed Ccb for this target if it
303          * returned 'check condition'.
304          * If this command is a request-sense and there is valid sense data
305          * from the last completed Ccb, return it immediately.
306          */
307         lock(&ctlr->cachelock);
308         if((ccb = ctlr->cache[target]) != nil){
309                 ctlr->cache[target] = nil;
310                 if(r->cmd[0] == 0x03
311                 && ccb->sdstat == SDcheck && lun == ((ccb->cs[1]>>5) & 0x07)){
312                         unlock(&ctlr->cachelock);
313                         if(r->dlen){
314                                 sense = &ccb->cs[ccb->cdblen];
315                                 n = 8+sense[7];
316                                 if(n > r->dlen)
317                                         n = r->dlen;
318                                 memmove(r->data, sense, n);
319                                 r->rlen = n;
320                         }
321                         ccbfree(ctlr, (Ccb*)ccb);
322                         return SDok;
323                 }
324         }
325         unlock(&ctlr->cachelock);
326         if(ccb == nil)
327                 ccb = ccballoc(ctlr);
328
329         /*
330          * Check if the transfer is to memory above the 24-bit limit the
331          * controller can address. If it is, try to allocate a temporary
332          * buffer as a staging area.
333          */
334         n = r->dlen;
335         if(n && !PADDR24(r->data, n)){
336                 data = mallocz(n, 0);
337                 if(data == nil || !PADDR24(data, n)){
338                         if(data != nil){
339                                 free(data);
340                                 ccb->data = nil;
341                         }
342                         ccbfree(ctlr, (Ccb*)ccb);
343                         return SDmalloc;
344                 }
345                 if(r->write)
346                         memmove(data, r->data, n);
347                 ccb->data = r->data;
348         }
349         else
350                 data = r->data;
351
352         /*
353          * Fill in the ccb.
354          */
355         ccb->opcode = Ordl;
356
357         ccb->datadir = (target<<5)|lun;
358         if(n == 0)
359                 ccb->datadir |= CCBdataout|CCBdatain;
360         else if(!r->write)
361                 ccb->datadir |= CCBdatain;
362         else
363                 ccb->datadir |= CCBdataout;
364
365         ccb->cdblen = r->clen;
366         ccb->senselen = 0xFF;
367
368         ccb->datalen[0] = n>>16;
369         ccb->datalen[1] = n>>8;
370         ccb->datalen[2] = n;
371         if(data == nil)
372                 p = 0;
373         else
374                 p = PADDR(data);
375         ccb->dataptr[0] = p>>16;
376         ccb->dataptr[1] = p>>8;
377         ccb->dataptr[2] = p;
378
379         ccb->linkptr[0] = ccb->linkptr[1] = ccb->linkptr[2] = 0;
380         ccb->linkid = 0;
381         ccb->btstat = ccb->sdstat = 0;
382         ccb->reserved[0] = ccb->reserved[1] = 0;
383
384         memmove(ccb->cs, r->cmd, r->clen);
385
386         /*
387          * There's one more mbox than there there is
388          * ccb so there is always one free.
389          */
390         lock(&ctlr->mboxlock);
391         mb = ctlr->mb;
392         mb += ctlr->mbox;
393         p = PADDR(ccb);
394         mb->ccb[0] = p>>16;
395         mb->ccb[1] = p>>8;
396         mb->ccb[2] = p;
397         mb->code = Mbostart;
398         ctlr->mbox++;
399         if(ctlr->mbox >= NMbox)
400                 ctlr->mbox = 0;
401
402         /*
403          * This command does not require Hardy
404          * and doesn't generate a Cmdc interrupt.
405          */
406         ccb->done = 0;
407         outb(ctlr->port+Rcpr, Cstart);
408         unlock(&ctlr->mboxlock);
409
410         /*
411          * Wait for the request to complete and return the status.
412          * Since the buffer is not reference counted cannot return
413          * until the DMA is done writing into the buffer so the caller
414          * cannot free the buffer prematurely.
415          */
416         while(waserror())
417                 ;
418         sleep(ccb, done24, ccb);
419         poperror();
420
421         /*
422          * Save the status and patch up the number of
423          * bytes actually transferred.
424          * There's a firmware bug on some 956C controllers
425          * which causes the return count from a successful
426          * READ CAPACITY not be updated, so fix it here.
427          */
428         sdstat = ccb->sdstat;
429         btstat = ccb->btstat;
430
431         d = ccb->datalen[0]<<16;
432         d |= ccb->datalen[1]<<8;
433         d |= ccb->datalen[2];
434         if(ccb->cs[0] == 0x25 && sdstat == SDok)
435                 d = 0;
436         n -= d;
437         r->rlen = n;
438
439         /*
440          * Tidy things up if a staging area was used for the data,
441          */
442         if(ccb->data != nil){
443                 if(sdstat == SDok && btstat == 0 && !r->write)
444                         memmove(ccb->data, data, n);
445                 free(data);
446                 ccb->data = nil;
447         }
448
449         /*
450          * If there was a check-condition, save the
451          * ccb for a possible request-sense command.
452          */
453         if(sdstat == SDcheck){
454                 if(r->flags & SDnosense){
455                         lock(&ctlr->cachelock);
456                         if(ctlr->cache[target])
457                                 ccbfree(ctlr, ctlr->cache[target]);
458                         ctlr->cache[target] = (Ccb*)ccb;
459                         unlock(&ctlr->cachelock);
460                         return SDcheck;
461                 }
462                 sense = &ccb->cs[ccb->cdblen];
463                 n = 8+sense[7];
464                 if(n > sizeof(r->sense)-1)
465                         n = sizeof(r->sense)-1;
466                 memmove(r->sense, sense, n);
467                 r->flags |= SDvalidsense;
468         }
469         ccbfree(ctlr, (Ccb*)ccb);
470
471         if(btstat){
472                 if(btstat == 0x11)
473                         return SDtimeout;
474                 return SDeio;
475         }
476         return sdstat;
477 }
478
479 static void
480 mylex24interrupt(Ureg*, void* arg)
481 {
482         ulong pa;
483         Ctlr *ctlr;
484         Ccb24 *ccb;
485         Mbox24 *mb, *mbox;
486         int port, rinterrupt, rstatus;
487
488         ctlr = arg;
489         port = ctlr->port;
490
491         /*
492          * Save and clear the interrupt(s). The only
493          * interrupts expected are Cmdc, which is ignored,
494          * and Imbl which means something completed.
495          * There's one spurious interrupt left over from
496          * initialisation, ignore it.
497          */
498         rinterrupt = inb(port+Rinterrupt);
499         rstatus = inb(port+Rstatus);
500         outb(port+Rcontrol, Rint);
501         if((rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
502                 print("%s: interrupt 0x%2.2ux\n",
503                         ctlr->sdev->name, rinterrupt);
504         if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
505                 print("%s: command invalid\n", ctlr->sdev->name);
506
507         /*
508          * Look for something in the mail.
509          * If there is, save the status, free the mailbox
510          * and wakeup whoever.
511          */
512         mb = ctlr->mb;
513         for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
514                 pa = (mbox->ccb[0]<<16)|(mbox->ccb[1]<<8)|mbox->ccb[2];
515                 ccb = BPA2K(pa, BUSUNKNOWN);
516                 mbox->code = 0;
517                 ccb->done = 1;
518                 wakeup(ccb);
519
520                 ctlr->mbix++;
521                 if(ctlr->mbix >= NMbox+NMbox)
522                         ctlr->mbix = NMbox;
523         }
524 }
525
526 static int
527 done32(void* arg)
528 {
529         return ((Ccb32*)arg)->done;
530 }
531
532 static int
533 mylex32rio(SDreq* r)
534 {
535         ulong p;
536         uchar lun;
537         Ctlr *ctlr;
538         Ccb32 *ccb;
539         Mbox32 *mb;
540         int d, n, btstat, sdstat, target;
541
542         ctlr = r->unit->dev->ctlr;
543         target = r->unit->subno;
544         lun = (r->cmd[1]>>5) & 0x07;
545
546         /*
547          * Ctlr->cache holds the last completed Ccb for this target if it
548          * returned 'check condition'.
549          * If this command is a request-sense and there is valid sense data
550          * from the last completed Ccb, return it immediately.
551          */
552         lock(&ctlr->cachelock);
553         if((ccb = ctlr->cache[target]) != nil){
554                 ctlr->cache[target] = nil;
555                 if(r->cmd[0] == 0x03
556                 && ccb->sdstat == SDcheck && lun == (ccb->luntag & 0x07)){
557                         unlock(&ctlr->cachelock);
558                         if(r->dlen){
559                                 n = 8+ccb->sense[7];
560                                 if(n > r->dlen)
561                                         n = r->dlen;
562                                 memmove(r->data, ccb->sense, n);
563                                 r->rlen = n;
564                         }
565                         ccbfree(ctlr, (Ccb*)ccb);
566                         return SDok;
567                 }
568         }
569         unlock(&ctlr->cachelock);
570         if(ccb == nil)
571                 ccb = ccballoc(ctlr);
572
573         /*
574          * Fill in the ccb.
575          */
576         ccb->opcode = Ordl;
577
578         n = r->dlen;
579         if(n == 0)
580                 ccb->datadir = CCBdataout|CCBdatain;
581         else if(!r->write)
582                 ccb->datadir = CCBdatain;
583         else
584                 ccb->datadir = CCBdataout;
585
586         ccb->cdblen = r->clen;
587
588         ccb->datalen[0] = n;
589         ccb->datalen[1] = n>>8;
590         ccb->datalen[2] = n>>16;
591         ccb->datalen[3] = n>>24;
592         if(r->data == nil)
593                 p = 0;
594         else
595                 p = PADDR(r->data);
596         ccb->dataptr[0] = p;
597         ccb->dataptr[1] = p>>8;
598         ccb->dataptr[2] = p>>16;
599         ccb->dataptr[3] = p>>24;
600
601         ccb->targetid = target;
602         ccb->luntag = lun;
603         if(r->unit->inquiry[7] & 0x02)
604                 if(ctlr->wide)
605                         ccb->datadir |= SQTag|TagEnable;
606                 else
607                         ccb->luntag |= SQTag|TagEnable;
608         memmove(ccb->cdb, r->cmd, r->clen);
609         ccb->btstat = ccb->sdstat = 0;
610         ccb->ccbctl = 0;
611
612         /*
613          * There's one more mbox than there there is
614          * ccb so there is always one free.
615          */
616         lock(&ctlr->mboxlock);
617         mb = ctlr->mb;
618         mb += ctlr->mbox;
619         p = PADDR(ccb);
620         mb->ccb[0] = p;
621         mb->ccb[1] = p>>8;
622         mb->ccb[2] = p>>16;
623         mb->ccb[3] = p>>24;
624         mb->code = Mbostart;
625         ctlr->mbox++;
626         if(ctlr->mbox >= NMbox)
627                 ctlr->mbox = 0;
628
629         /*
630          * This command does not require Hardy
631          * and doesn't generate a Cmdc interrupt.
632          */
633         ccb->done = 0;
634         outb(ctlr->port+Rcpr, Cstart);
635         unlock(&ctlr->mboxlock);
636
637         /*
638          * Wait for the request to complete and return the status.
639          * Since the buffer is not reference counted cannot return
640          * until the DMA is done writing into the buffer so the caller
641          * cannot free the buffer prematurely.
642          */
643         while(waserror())
644                 ;
645         sleep(ccb, done32, ccb);
646         poperror();
647
648         /*
649          * Save the status and patch up the number of
650          * bytes actually transferred.
651          * There's a firmware bug on some 956C controllers
652          * which causes the return count from a successful
653          * READ CAPACITY not to be updated, so fix it here.
654          */
655         sdstat = ccb->sdstat;
656         btstat = ccb->btstat;
657
658         d = ccb->datalen[0];
659         d |= (ccb->datalen[1]<<8);
660         d |= (ccb->datalen[2]<<16);
661         d |= (ccb->datalen[3]<<24);
662         if(ccb->cdb[0] == 0x25 && sdstat == SDok)
663                 d = 0;
664         n -= d;
665         r->rlen = n;
666
667         /*
668          * If there was a check-condition, save the
669          * ccb for a possible request-sense command.
670          */
671         if(sdstat == SDcheck){
672                 if(r->flags & SDnosense){
673                         lock(&ctlr->cachelock);
674                         if(ctlr->cache[target])
675                                 ccbfree(ctlr, ctlr->cache[target]);
676                         ctlr->cache[target] = (Ccb*)ccb;
677                         unlock(&ctlr->cachelock);
678                         return SDcheck;
679                 }
680                 n = 8+ccb->sense[7];
681                 if(n > sizeof(r->sense)-1)
682                         n = sizeof(r->sense)-1;
683                 memmove(r->sense, ccb->sense, n);
684                 r->flags |= SDvalidsense;
685         }
686         ccbfree(ctlr, (Ccb*)ccb);
687
688         if(btstat){
689                 if(btstat == 0x11)
690                         return SDtimeout;
691                 return SDeio;
692         }
693         return sdstat;
694 }
695
696 static void
697 mylex32interrupt(Ureg*, void* arg)
698 {
699         ulong pa;
700         Ctlr *ctlr;
701         Ccb32 *ccb;
702         Mbox32 *mb, *mbox;
703         int port, rinterrupt, rstatus;
704
705         ctlr = arg;
706         port = ctlr->port;
707
708         /*
709          * Save and clear the interrupt(s). The only
710          * interrupts expected are Cmdc, which is ignored,
711          * and Imbl which means something completed.
712          * There's one spurious interrupt left over from
713          * initialisation, ignore it.
714          * In order to share PCI IRQs, just ignore spurious interrupts.
715          */
716         rinterrupt = inb(port+Rinterrupt);
717         rstatus = inb(port+Rstatus);
718         outb(port+Rcontrol, Rint);
719         if(0 && (rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
720                 print("%s: interrupt 0x%2.2ux\n",
721                         ctlr->sdev->name, rinterrupt);
722         if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
723                 print("%s: command invalid\n", ctlr->sdev->name);
724
725         /*
726          * Look for something in the mail.
727          * If there is, free the mailbox and wakeup whoever.
728          */
729         mb = ctlr->mb;
730         for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
731                 pa = (mbox->ccb[3]<<24)
732                     |(mbox->ccb[2]<<16)
733                     |(mbox->ccb[1]<<8)
734                     |mbox->ccb[0];
735                 if(ctlr->pcidev)
736                         ccb = BPA2K(pa, ctlr->pcidev->tbdf);
737                 else
738                         ccb = BPA2K(pa, BUSUNKNOWN);
739                 mbox->code = 0;
740                 ccb->done = 1;
741                 wakeup(ccb);
742
743                 ctlr->mbix++;
744                 if(ctlr->mbix >= NMbox+NMbox)
745                         ctlr->mbix = NMbox;
746         }
747 }
748
749 static int
750 mylexrio(SDreq* r)
751 {
752         int subno;
753         Ctlr *ctlr;
754
755         subno = r->unit->subno;
756         ctlr = r->unit->dev->ctlr;
757         if(subno == ctlr->id || (!ctlr->wide && subno >= 8))
758                 r->status = SDtimeout;
759         else if(ctlr->bus == 24)
760                 r->status = mylex24rio(r);
761         else
762                 r->status = mylex32rio(r);
763         return r->status;
764 }
765
766 /*
767  * Issue a command to a controller. The command and its length is
768  * contained in cmd and cmdlen. If any data is to be
769  * returned, datalen should be non-zero, and the returned data
770  * will be placed in data.
771  * If Cmdc is set, bail out, the invalid command will be handled
772  * when the interrupt is processed.
773  */
774 static void
775 issueio(int port, uchar* cmd, int cmdlen, uchar* data, int datalen)
776 {
777         int len;
778
779         if(cmd[0] != Cstart && cmd[0] != Ceombri){
780                 while(!(inb(port+Rstatus) & Hardy))
781                         ;
782         }
783         outb(port+Rcpr, cmd[0]);
784
785         len = 1;
786         while(len < cmdlen){
787                 if(!(inb(port+Rstatus) & Cprbsy)){
788                         outb(port+Rcpr, cmd[len]);
789                         len++;
790                 }
791                 if(inb(port+Rinterrupt) & Cmdc)
792                         return;
793         }
794
795         if(datalen){
796                 len = 0;
797                 while(len < datalen){
798                         if(inb(port+Rstatus) & Dirrdy){
799                                 data[len] = inb(port+Rdatain);
800                                 len++;
801                         }
802                         if(inb(port+Rinterrupt) & Cmdc)
803                                 return;
804                 }
805         }
806 }
807
808 /*
809  * Issue a command to a controller, wait for it to complete then
810  * try to reset the interrupt. Should only be called at initialisation.
811  */
812 static int
813 issue(Ctlr* ctlr, uchar* cmd, int cmdlen, uchar* data, int datalen)
814 {
815         int port;
816         uchar rinterrupt, rstatus;
817         static Lock mylexissuelock;
818
819         port = ctlr->port;
820
821         ilock(&ctlr->issuelock);
822         issueio(port, cmd, cmdlen, data, datalen);
823
824         while(!((rinterrupt = inb(port+Rinterrupt)) & Cmdc))
825                 ;
826
827         rstatus = inb(port+Rstatus);
828         outb(port+Rcontrol, Rint);
829         iunlock(&ctlr->issuelock);
830
831         if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
832                 return 0;
833         return 1;
834 }
835
836 static SDev*
837 mylexprobe(int port, int irq)
838 {
839         SDev *sdev;
840         Ctlr *ctlr;
841         uchar cmd[6], data[256];
842         int clen, dlen, timeo;
843
844         if(ioalloc(port, 0x3, 0, "mylex") < 0)
845                 return nil;
846         ctlr = nil;
847         sdev = nil;
848         /*
849          * Attempt to hard-reset the board and reset
850          * the SCSI bus. If the board state doesn't settle to
851          * idle with mailbox initialisation required, either
852          * it isn't a compatible board or it's broken.
853          * If the controller has SCAM set this can take a while.
854          */
855         if(getconf("*noscsireset") != nil)
856                 outb(port+Rcontrol, Rhard);
857         else
858                 outb(port+Rcontrol, Rhard|Rsbus);
859         for(timeo = 0; timeo < 100; timeo++){
860                 if(inb(port+Rstatus) == (Inreq|Hardy))
861                         break;
862                 delay(100);
863         }
864         if(inb(port+Rstatus) != (Inreq|Hardy)){
865 buggery:
866                 if(ctlr != nil)
867                         free(ctlr);
868                 if (sdev != nil)
869                         free(sdev);
870                 iofree(port);
871                 return nil;
872         }
873
874         if((ctlr = malloc(sizeof(Ctlr))) == nil)
875                 goto buggery;
876         ctlr->port = port;
877         ctlr->irq = irq;
878         ctlr->bus = 24;
879         ctlr->wide = 0;
880
881         /*
882          * Try to determine if this is a 32-bit MultiMaster controller
883          * by attempting to obtain the extended inquiry information;
884          * this command is not implemented on Adaptec 154xx
885          * controllers. If successful, the first byte of the returned
886          * data is the host adapter bus type, 'E' for 32-bit EISA,
887          * PCI and VLB buses.
888          */
889         cmd[0] = Ciesi;
890         cmd[1] = 14;
891         clen = 2;
892         dlen = 256;
893         if(issue(ctlr, cmd, clen, data, dlen)){
894                 if(data[0] == 'E')
895                         ctlr->bus = 32;
896                 print("mylex ctlr @ port 0x%ux: 32-bit ", ctlr->port);
897                 ctlr->wide = data[0x0D] & 0x01;
898                 if (ctlr->wide)
899                         print("wide ");
900                 else
901                         print("narrow ");
902                 print("SCSI host adapter\n");
903         }
904         else{
905                 /*
906                  * Inconceivable though it may seem, a hard controller reset
907                  * is necessary here to clear out the command queue. Every
908                  * board seems to lock-up in a different way if you give an
909                  * invalid command and then try to clear out the
910                  * command/parameter and/or data-in register.
911                  * Soft reset doesn't do the job either. Fortunately no
912                  * serious initialisation has been done yet so there's nothing
913                  * to tidy up.
914                  */
915                 outb(port+Rcontrol, Rhard);
916                 for(timeo = 0; timeo < 100; timeo++){
917                         if(inb(port+Rstatus) == (Inreq|Hardy))
918                                 break;
919                         delay(100);
920                 }
921                 if(inb(port+Rstatus) != (Inreq|Hardy))
922                         goto buggery;
923         }
924
925         /*
926          * If the BIOS is enabled on the AHA-1542C/CF and BIOS options for
927          * support of drives > 1Gb, dynamic scanning of the SCSI bus or more
928          * than 2 drives under DOS 5.0 are enabled, the BIOS disables
929          * accepting Cmbinit to protect against running with drivers which
930          * don't support those options. In order to unlock the interface it
931          * is necessary to read a lock-code using Cextbios and write it back
932          * using Cmbienable; the lock-code is non-zero.
933          */
934         cmd[0] = Cinquiry;
935         clen = 1;
936         dlen = 4;
937         if(issue(ctlr, cmd, clen, data, dlen) == 0)
938                 goto buggery;
939         if(data[0] >= 0x43){
940                 cmd[0] = Cextbios;
941                 clen = 1;
942                 dlen = 2;
943                 if(issue(ctlr, cmd, clen, data, dlen) == 0)
944                         goto buggery;
945
946                 /*
947                  * Lock-code returned in data[1]. If it's non-zero write
948                  * it back along with bit 0 of byte 0 cleared to enable
949                  * mailbox initialisation.
950                  */
951                 if(data[1]){
952                         cmd[0] = Cmbienable;
953                         cmd[1] = 0;
954                         cmd[2] = data[1];
955                         clen = 3;
956                         if(issue(ctlr, cmd, clen, 0, 0) == 0)
957                                 goto buggery;
958                 }
959         }
960
961         /*
962          * Get the id, DMA and IRQ info from the board. This will
963          * cause an interrupt which will hopefully not cause any
964          * trouble because the interrupt number isn't known yet.
965          * This is necessary as the DMA won't be set up if the
966          * board has the BIOS disabled.
967          *
968          * If the IRQ is already known, this must be a 32-bit PCI
969          * or EISA card, in which case the returned DMA and IRQ can
970          * be ignored.
971          */
972         cmd[0] = Cinquire;
973         clen = 1;
974         dlen = 3;
975         if(issue(ctlr, cmd, clen, data, dlen) == 0)
976                 goto buggery;
977
978         ctlr->id = data[2] & 0x07;
979         if(ctlr->irq < 0){
980                 switch(data[0]){                /* DMA Arbitration Priority */
981                 case 0x80:                      /* Channel 7 */
982                         outb(0xD6, 0xC3);
983                         outb(0xD4, 0x03);
984                         break;
985                 case 0x40:                      /* Channel 6 */
986                         outb(0xD6, 0xC2);
987                         outb(0xD4, 0x02);
988                         break;
989                 case 0x20:                      /* Channel 5 */
990                         outb(0xD6, 0xC1);
991                         outb(0xD4, 0x01);
992                         break;
993                 case 0x01:                      /* Channel 0 */
994                         outb(0x0B, 0xC0);
995                         outb(0x0A, 0x00);
996                         break;
997                 default:
998                         if(ctlr->bus == 24)
999                                 goto buggery;
1000                         break;
1001                 }
1002         
1003                 switch(data[1]){                /* Interrupt Channel */
1004                 case 0x40:
1005                         ctlr->irq = 15;
1006                         break;
1007                 case 0x20:
1008                         ctlr->irq = 14;
1009                         break;
1010                 case 0x08:
1011                         ctlr->irq = 12;
1012                         break;
1013                 case 0x04:
1014                         ctlr->irq = 11;
1015                         break;
1016                 case 0x02:
1017                         ctlr->irq = 10;
1018                         break;
1019                 case 0x01:
1020                         ctlr->irq = 9;
1021                         break;
1022                 default:
1023                         goto buggery;
1024                 }
1025         }
1026
1027         if((sdev = malloc(sizeof(SDev))) == nil)
1028                 goto buggery;
1029         sdev->ifc = &sdmylexifc;
1030         sdev->ctlr = ctlr;
1031         sdev->idno = '0';
1032         ctlr->sdev = sdev;
1033         if(!ctlr->wide)
1034                 sdev->nunit = 8;
1035         else
1036                 sdev->nunit = 16;
1037
1038         return sdev;
1039 }
1040
1041 static int mylexport[8] = {
1042         0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0x000, 0x000,
1043 };
1044
1045 static SDev*
1046 mylexpnp(void)
1047 {
1048         Pcidev *p;
1049         Ctlr *ctlr;
1050         ISAConf isa;
1051         int cfg, ctlrno, i, x;
1052         SDev *sdev, *head, *tail;
1053
1054         p = nil;
1055         head = tail = nil;
1056         while(p = pcimatch(p, 0x104B, 0)){
1057                 if((sdev = mylexprobe(p->mem[0].bar & ~0x01, p->intl)) == nil)
1058                         continue;
1059
1060                 ctlr = sdev->ctlr;
1061                 ctlr->pcidev = p;
1062
1063                 if(head != nil)
1064                         tail->next = sdev;
1065                 else
1066                         head = sdev;
1067                 tail = sdev;
1068         }
1069
1070         if(strncmp(KADDR(0xFFFD9), "EISA", 4) == 0){
1071                 for(cfg = 0x1000; cfg < MaxEISA*0x1000; cfg += 0x1000){
1072                         x = 0;
1073                         for(i = 0; i < 4; i++)
1074                                 x |= inb(cfg+CfgEISA+i)<<(i*8);
1075                         if(x != 0x0142B30A && x != 0x0242B30A)
1076                                 continue;
1077         
1078                         x = inb(cfg+0xC8C);
1079                         if((sdev = mylexprobe(mylexport[x & 0x07], -1)) == nil)
1080                                 continue;
1081         
1082                         if(head != nil)
1083                                 tail->next = sdev;
1084                         else
1085                                 head = sdev;
1086                         tail = sdev;
1087                 }
1088         }
1089
1090         for(ctlrno = 0; ctlrno < 4; ctlrno++){
1091                 memset(&isa, 0, sizeof(isa));
1092                 if(!isaconfig("scsi", ctlrno, &isa))
1093                         continue;
1094                 if(strcmp(isa.type, "aha1542"))
1095                         continue;
1096                 if((sdev = mylexprobe(isa.port, -1)) == nil)
1097                         continue;
1098
1099                 if(head != nil)
1100                         tail->next = sdev;
1101                 else
1102                         head = sdev;
1103                 tail = sdev;
1104         }
1105
1106         return head;
1107 }
1108
1109 static int
1110 mylex24enable(Ctlr* ctlr)
1111 {
1112         ulong p;
1113         Ccb24 *ccb, *ccbp;
1114         uchar cmd[6], *v;
1115         int len;
1116
1117         len = (sizeof(Mbox24)*NMbox*2)+(sizeof(Ccb24)*NCcb);
1118         v = xspanalloc(len, 32, 0);
1119
1120         if(!PADDR24(ctlr, sizeof(Ctlr)) || !PADDR24(v, len))
1121                 return 0;
1122
1123         ctlr->mb = v;
1124         v += sizeof(Mbox24)*NMbox*2;
1125
1126         ccb = (Ccb24*)v;
1127         for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
1128                 ccbp->ccb = ctlr->ccb;
1129                 ctlr->ccb = (Ccb*)ccbp;
1130         }
1131
1132         /*
1133          * Initialise the software controller and
1134          * set the board scanning the mailboxes.
1135          */
1136         ctlr->mbix = NMbox;
1137
1138         cmd[0] = Cinitialise;
1139         cmd[1] = NMbox;
1140         p = K2BPA(ctlr->mb, BUSUNKNOWN);
1141         cmd[2] = p>>16;
1142         cmd[3] = p>>8;
1143         cmd[4] = p;
1144
1145         return issue(ctlr, cmd, 5, 0, 0);
1146 }
1147
1148 static int
1149 mylex32enable(Ctlr* ctlr)
1150 {
1151         ulong p;
1152         Ccb32 *ccb, *ccbp;
1153         uchar cmd[6], *v;
1154
1155         v = xspanalloc((sizeof(Mbox32)*NMbox*2)+(sizeof(Ccb32)*NCcb), 32, 0);
1156
1157         ctlr->mb = v;
1158         v += sizeof(Mbox32)*NMbox*2;
1159
1160         ccb = (Ccb32*)v;
1161         for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
1162                 /*
1163                  * Fill in some stuff that doesn't change.
1164                  */
1165                 ccbp->senselen = sizeof(ccbp->sense);
1166                 p = PADDR(ccbp->sense);
1167                 ccbp->senseptr[0] = p;
1168                 ccbp->senseptr[1] = p>>8;
1169                 ccbp->senseptr[2] = p>>16;
1170                 ccbp->senseptr[3] = p>>24;
1171
1172                 ccbp->ccb = ctlr->ccb;
1173                 ctlr->ccb = (Ccb*)ccbp;
1174         }
1175
1176         /*
1177          * Attempt wide mode setup.
1178          */
1179         if(ctlr->wide){
1180                 cmd[0] = Cwide;
1181                 cmd[1] = 1;
1182                 if(!issue(ctlr, cmd, 2, 0, 0)) {
1183                         ctlr->wide = 0;
1184                         print(
1185 "mylex32enable: ctlr @ port 0x%ux: scsi wide-mode setup failed on wide host adapter",
1186                                 ctlr->port);
1187                 }
1188         }
1189
1190         /*
1191          * Initialise the software controller and
1192          * set the board scanning the mailboxes.
1193          */
1194         ctlr->mbix = NMbox;
1195
1196         cmd[0] = Ciem;
1197         cmd[1] = NMbox;
1198         if(ctlr->pcidev)
1199                 p = K2BPA(ctlr->mb, ctlr->tbdf);
1200         else
1201                 p = K2BPA(ctlr->mb, BUSUNKNOWN);
1202         cmd[2] = p;
1203         cmd[3] = p>>8;
1204         cmd[4] = p>>16;
1205         cmd[5] = p>>24;
1206
1207         return issue(ctlr, cmd, 6, 0, 0);
1208 }
1209
1210 static int
1211 mylexenable(SDev* sdev)
1212 {
1213         int tbdf;
1214         Ctlr *ctlr;
1215         void (*interrupt)(Ureg*, void*);
1216         char name[32];
1217
1218         ctlr = sdev->ctlr;
1219         if(ctlr->cache == nil){
1220                 if((ctlr->cache = malloc(sdev->nunit*sizeof(Ccb*))) == nil)
1221                         return 0;
1222         }
1223
1224         tbdf = BUSUNKNOWN;
1225         if(ctlr->bus == 32){
1226                 if(ctlr->pcidev){
1227                         tbdf = ctlr->pcidev->tbdf;
1228                         pcisetbme(ctlr->pcidev);
1229                 }
1230                 if(!mylex32enable(ctlr))
1231                         return 0;
1232                 interrupt = mylex32interrupt;
1233         }
1234         else if(mylex24enable(ctlr))
1235                 interrupt = mylex24interrupt;
1236         else
1237                 return 0;
1238
1239         snprint(name, sizeof(name), "sd%c (%s)", sdev->idno, sdev->ifc->name);
1240         intrenable(ctlr->irq, interrupt, ctlr, tbdf, name);
1241
1242         return 1;
1243 }
1244
1245 SDifc sdmylexifc = {
1246         "mylex",                        /* name */
1247
1248         mylexpnp,                       /* pnp */
1249         nil,                            /* legacy */
1250         mylexenable,                    /* enable */
1251         nil,                            /* disable */
1252
1253         scsiverify,                     /* verify */
1254         scsionline,                     /* online */
1255         mylexrio,                       /* rio */
1256         nil,                            /* rctl */
1257         nil,                            /* wctl */
1258
1259         scsibio,                        /* bio */
1260         nil,                            /* probe */
1261         nil,                            /* clear */
1262         nil,                            /* rtopctl */
1263         nil,                            /* wtopctl */
1264 };