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