17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Mylex MultiMaster (Buslogic BT-*) SCSI Host Adapter
37dd7cddfSDavid du Colombier * in both 24-bit and 32-bit mode.
47dd7cddfSDavid du Colombier * 24-bit mode works for Adaptec AHA-154xx series too.
57dd7cddfSDavid du Colombier *
67dd7cddfSDavid du Colombier * To do:
77dd7cddfSDavid du Colombier * allocate more Ccb's as needed, up to NMbox-1;
87dd7cddfSDavid du Colombier * add nmbox and nccb to Ctlr struct for the above;
97dd7cddfSDavid du Colombier * 64-bit LUN/explicit wide support necessary?
107dd7cddfSDavid du Colombier *
117dd7cddfSDavid du Colombier */
127dd7cddfSDavid du Colombier #include "u.h"
137dd7cddfSDavid du Colombier #include "../port/lib.h"
147dd7cddfSDavid du Colombier #include "mem.h"
157dd7cddfSDavid du Colombier #include "dat.h"
167dd7cddfSDavid du Colombier #include "fns.h"
177dd7cddfSDavid du Colombier #include "io.h"
187dd7cddfSDavid du Colombier #include "ureg.h"
197dd7cddfSDavid du Colombier #include "../port/error.h"
207dd7cddfSDavid du Colombier
2180ee5cbfSDavid du Colombier #include "../port/sd.h"
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier #define K2BPA(va, tbdf) PADDR(va)
247dd7cddfSDavid du Colombier #define BPA2K(pa, tbdf) KADDR(pa)
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier extern SDifc sdmylexifc;
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier enum { /* registers */
297dd7cddfSDavid du Colombier Rcontrol = 0x00, /* WO: control register */
307dd7cddfSDavid du Colombier Rstatus = 0x00, /* RO: status register */
317dd7cddfSDavid du Colombier Rcpr = 0x01, /* WO: command/parameter register */
327dd7cddfSDavid du Colombier Rdatain = 0x01, /* RO: data-in register */
337dd7cddfSDavid du Colombier Rinterrupt = 0x02, /* RO: interrupt register */
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier enum { /* Rcontrol */
377dd7cddfSDavid du Colombier Rsbus = 0x10, /* SCSI Bus Reset */
387dd7cddfSDavid du Colombier Rint = 0x20, /* Interrupt Reset */
397dd7cddfSDavid du Colombier Rsoft = 0x40, /* Soft Reset */
407dd7cddfSDavid du Colombier Rhard = 0x80, /* Hard Reset */
417dd7cddfSDavid du Colombier };
427dd7cddfSDavid du Colombier
437dd7cddfSDavid du Colombier enum { /* Rstatus */
447dd7cddfSDavid du Colombier Cmdinv = 0x01, /* Command Invalid */
457dd7cddfSDavid du Colombier Dirrdy = 0x04, /* Data In Register Ready */
467dd7cddfSDavid du Colombier Cprbsy = 0x08, /* Command/Parameter Register Busy */
477dd7cddfSDavid du Colombier Hardy = 0x10, /* Host Adapter Ready */
487dd7cddfSDavid du Colombier Inreq = 0x20, /* Initialisation Required */
497dd7cddfSDavid du Colombier Dfail = 0x40, /* Diagnostic Failure */
507dd7cddfSDavid du Colombier Dact = 0x80, /* Diagnostic Active */
517dd7cddfSDavid du Colombier };
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier enum { /* Rcpr */
547dd7cddfSDavid du Colombier Cinitialise = 0x01, /* Initialise Mailbox */
557dd7cddfSDavid du Colombier Cstart = 0x02, /* Start Mailbox Command */
5659cc4ca5SDavid du Colombier Cinquiry = 0x04, /* Adapter Inquiry */
577dd7cddfSDavid du Colombier Ceombri = 0x05, /* Enable OMBR Interrupt */
587dd7cddfSDavid du Colombier Cinquire = 0x0B, /* Inquire Configuration */
597dd7cddfSDavid du Colombier Cextbios = 0x28, /* AHA-1542: extended BIOS info. */
607dd7cddfSDavid du Colombier Cmbienable = 0x29, /* AHA-1542: Mailbox interface enable */
617dd7cddfSDavid du Colombier Ciem = 0x81, /* Initialise Extended Mailbox */
627dd7cddfSDavid du Colombier Ciesi = 0x8D, /* Inquire Extended Setup Information */
637dd7cddfSDavid du Colombier Cerrm = 0x8F, /* Enable strict round-robin mode */
647dd7cddfSDavid du Colombier Cwide = 0x96, /* Wide CCB */
657dd7cddfSDavid du Colombier };
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier enum { /* Rinterrupt */
687dd7cddfSDavid du Colombier Imbl = 0x01, /* Incoming Mailbox Loaded */
697dd7cddfSDavid du Colombier Mbor = 0x02, /* Mailbox Out Ready */
707dd7cddfSDavid du Colombier Cmdc = 0x04, /* Command Complete */
717dd7cddfSDavid du Colombier Rsts = 0x08, /* SCSI Reset State */
727dd7cddfSDavid du Colombier Intv = 0x80, /* Interrupt Valid */
737dd7cddfSDavid du Colombier };
747dd7cddfSDavid du Colombier
7559c21d95SDavid du Colombier typedef struct Mbox24 Mbox24;
7659c21d95SDavid du Colombier struct Mbox24 {
777dd7cddfSDavid du Colombier uchar code; /* action/completion code */
787dd7cddfSDavid du Colombier uchar ccb[3]; /* CCB pointer (MSB, ..., LSB) */
7959c21d95SDavid du Colombier };
807dd7cddfSDavid du Colombier
8159c21d95SDavid du Colombier typedef struct Mbox32 Mbox32;
8259c21d95SDavid du Colombier struct Mbox32 {
837dd7cddfSDavid du Colombier uchar ccb[4]; /* CCB pointer (LSB, ..., MSB) */
847dd7cddfSDavid du Colombier uchar btstat; /* BT-7[45]7[SD] status */
857dd7cddfSDavid du Colombier uchar sdstat; /* SCSI device status */
867dd7cddfSDavid du Colombier uchar pad;
877dd7cddfSDavid du Colombier uchar code; /* action/completion code */
8859c21d95SDavid du Colombier };
897dd7cddfSDavid du Colombier
907dd7cddfSDavid du Colombier enum { /* mailbox commands */
917dd7cddfSDavid du Colombier Mbfree = 0x00, /* Mailbox not in use */
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier Mbostart = 0x01, /* Start a mailbox command */
947dd7cddfSDavid du Colombier Mboabort = 0x02, /* Abort a mailbox command */
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier Mbiok = 0x01, /* CCB completed without error */
977dd7cddfSDavid du Colombier Mbiabort = 0x02, /* CCB aborted at request of host */
987dd7cddfSDavid du Colombier Mbinx = 0x03, /* Aborted CCB not found */
997dd7cddfSDavid du Colombier Mbierror = 0x04, /* CCB completed with error */
1007dd7cddfSDavid du Colombier };
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier typedef struct Ccb24 Ccb24;
1037dd7cddfSDavid du Colombier typedef struct Ccb32 Ccb32;
1047dd7cddfSDavid du Colombier typedef union Ccb Ccb;
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier typedef struct Ccb24 {
1077dd7cddfSDavid du Colombier uchar opcode; /* Operation code */
1087dd7cddfSDavid du Colombier uchar datadir; /* Data direction control */
1097dd7cddfSDavid du Colombier uchar cdblen; /* Length of CDB */
1107dd7cddfSDavid du Colombier uchar senselen; /* Length of sense area */
1117dd7cddfSDavid du Colombier uchar datalen[3]; /* Data length (MSB, ..., LSB) */
1127dd7cddfSDavid du Colombier uchar dataptr[3]; /* Data pointer (MSB, ..., LSB) */
1137dd7cddfSDavid du Colombier uchar linkptr[3]; /* Link pointer (MSB, ..., LSB) */
1147dd7cddfSDavid du Colombier uchar linkid; /* command linking identifier */
1157dd7cddfSDavid du Colombier uchar btstat; /* BT-* adapter status */
1167dd7cddfSDavid du Colombier uchar sdstat; /* SCSI device status */
1177dd7cddfSDavid du Colombier uchar reserved[2]; /* */
1187dd7cddfSDavid du Colombier uchar cs[12+0xFF]; /* Command descriptor block + Sense */
1197dd7cddfSDavid du Colombier
1207dd7cddfSDavid du Colombier void* data; /* buffer if address > 24-bits */
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier Rendez;
1237dd7cddfSDavid du Colombier int done; /* command completed */
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier Ccb* ccb; /* link on free list */
1267dd7cddfSDavid du Colombier } Ccb24;
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier
1297dd7cddfSDavid du Colombier typedef struct Ccb32 {
1307dd7cddfSDavid du Colombier uchar opcode; /* Operation code */
1317dd7cddfSDavid du Colombier uchar datadir; /* Data direction control */
1327dd7cddfSDavid du Colombier uchar cdblen; /* Length of CDB */
1337dd7cddfSDavid du Colombier uchar senselen; /* Length of sense area */
1347dd7cddfSDavid du Colombier uchar datalen[4]; /* Data length (LSB, ..., MSB) */
1357dd7cddfSDavid du Colombier uchar dataptr[4]; /* Data pointer (LSB, ..., MSB) */
1367dd7cddfSDavid du Colombier uchar reserved[2];
1377dd7cddfSDavid du Colombier uchar btstat; /* BT-* adapter status */
1387dd7cddfSDavid du Colombier uchar sdstat; /* SCSI device status */
1397dd7cddfSDavid du Colombier uchar targetid; /* Target ID */
1407dd7cddfSDavid du Colombier uchar luntag; /* LUN & tag */
1417dd7cddfSDavid du Colombier uchar cdb[12]; /* Command descriptor block */
1427dd7cddfSDavid du Colombier uchar ccbctl; /* CCB control */
1437dd7cddfSDavid du Colombier uchar linkid; /* command linking identifier */
1447dd7cddfSDavid du Colombier uchar linkptr[4]; /* Link pointer (LSB, ..., MSB) */
1457dd7cddfSDavid du Colombier uchar senseptr[4]; /* Sense pointer (LSB, ..., MSB) */
1467dd7cddfSDavid du Colombier uchar sense[0xFF]; /* Sense bytes */
1477dd7cddfSDavid du Colombier
1487dd7cddfSDavid du Colombier Rendez;
1497dd7cddfSDavid du Colombier int done; /* command completed */
1507dd7cddfSDavid du Colombier
1517dd7cddfSDavid du Colombier Ccb* ccb; /* link on free list */
1527dd7cddfSDavid du Colombier } Ccb32;
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier typedef union Ccb {
1557dd7cddfSDavid du Colombier Ccb24;
1567dd7cddfSDavid du Colombier Ccb32;
1577dd7cddfSDavid du Colombier } Ccb;
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier enum { /* opcode */
1607dd7cddfSDavid du Colombier OInitiator = 0x00, /* initiator CCB */
1617dd7cddfSDavid du Colombier Ordl = 0x03, /* initiator CCB with
1627dd7cddfSDavid du Colombier * residual data length returned
1637dd7cddfSDavid du Colombier */
1647dd7cddfSDavid du Colombier };
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier enum { /* datadir */
1677dd7cddfSDavid du Colombier CCBdatain = 0x08, /* inbound, length is checked */
1687dd7cddfSDavid du Colombier CCBdataout = 0x10, /* outbound, length is checked */
1697dd7cddfSDavid du Colombier };
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier enum { /* btstat */
1727dd7cddfSDavid du Colombier Eok = 0x00, /* normal completion with no errors */
1737dd7cddfSDavid du Colombier };
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier enum { /* luntag */
1767dd7cddfSDavid du Colombier TagEnable = 0x20, /* Tag enable */
1777dd7cddfSDavid du Colombier SQTag = 0x00, /* Simple Queue Tag */
1787dd7cddfSDavid du Colombier HQTag = 0x40, /* Head of Queue Tag */
1797dd7cddfSDavid du Colombier OQTag = 0x80, /* Ordered Queue Tag */
1807dd7cddfSDavid du Colombier };
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier enum { /* CCB control */
1837dd7cddfSDavid du Colombier NoDisc = 0x08, /* No disconnect */
1847dd7cddfSDavid du Colombier NoUnd = 0x10, /* No underrrun error report */
1857dd7cddfSDavid du Colombier NoData = 0x20, /* No data transfer */
1867dd7cddfSDavid du Colombier NoStat = 0x40, /* No CCB status if zero */
1877dd7cddfSDavid du Colombier NoIntr = 0x80, /* No Interrupts */
1887dd7cddfSDavid du Colombier };
1897dd7cddfSDavid du Colombier
19059c21d95SDavid du Colombier typedef struct Ctlr Ctlr;
19159c21d95SDavid du Colombier struct Ctlr {
1927dd7cddfSDavid du Colombier int port; /* I/O port */
1937dd7cddfSDavid du Colombier int id; /* adapter SCSI id */
1947dd7cddfSDavid du Colombier int bus; /* 24 or 32 -bit */
1957dd7cddfSDavid du Colombier int irq;
1967dd7cddfSDavid du Colombier int wide;
1977dd7cddfSDavid du Colombier Pcidev* pcidev;
1987dd7cddfSDavid du Colombier SDev* sdev;
1997dd7cddfSDavid du Colombier int spurious;
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier Lock issuelock;
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier Lock ccblock;
2047dd7cddfSDavid du Colombier QLock ccbq;
2057dd7cddfSDavid du Colombier Rendez ccbr;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier Lock mboxlock;
2087dd7cddfSDavid du Colombier void* mb; /* mailbox out + mailbox in */
2097dd7cddfSDavid du Colombier int mbox; /* current mailbox out index into mb */
2107dd7cddfSDavid du Colombier int mbix; /* current mailbox in index into mb */
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier Lock cachelock;
2137dd7cddfSDavid du Colombier Ccb* ccb; /* list of free Ccb's */
2147dd7cddfSDavid du Colombier Ccb** cache; /* last completed Ccb */
21559c21d95SDavid du Colombier };
2167dd7cddfSDavid du Colombier
2177dd7cddfSDavid du Colombier /*
2187dd7cddfSDavid du Colombier * The number of mailboxes should be a multiple of 8 (4 for Mbox32)
2197dd7cddfSDavid du Colombier * to ensure the boundary between the out and in mailboxes doesn't
2207dd7cddfSDavid du Colombier * straddle a cache-line boundary.
2217dd7cddfSDavid du Colombier * The number of Ccb's should be less than the number of mailboxes to
2227dd7cddfSDavid du Colombier * ensure no queueing is necessary on mailbox allocation.
2237dd7cddfSDavid du Colombier */
2247dd7cddfSDavid du Colombier enum {
2257dd7cddfSDavid du Colombier NMbox = 8*8, /* number of Mbox's */
2267dd7cddfSDavid du Colombier NCcb = NMbox-1, /* number of Ccb's */
2277dd7cddfSDavid du Colombier };
2287dd7cddfSDavid du Colombier
22959cc4ca5SDavid du Colombier #define PADDR24(a, n) ((PADDR(a)+(n)) <= (1<<24))
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier static void
ccbfree(Ctlr * ctlr,Ccb * ccb)2327dd7cddfSDavid du Colombier ccbfree(Ctlr* ctlr, Ccb* ccb)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier lock(&ctlr->ccblock);
2357dd7cddfSDavid du Colombier if(ctlr->bus == 24)
2367dd7cddfSDavid du Colombier ((Ccb24*)ccb)->ccb = ctlr->ccb;
2377dd7cddfSDavid du Colombier else
2387dd7cddfSDavid du Colombier ((Ccb32*)ccb)->ccb = ctlr->ccb;
2397dd7cddfSDavid du Colombier if(ctlr->ccb == nil)
2407dd7cddfSDavid du Colombier wakeup(&ctlr->ccbr);
2417dd7cddfSDavid du Colombier ctlr->ccb = ccb;
2427dd7cddfSDavid du Colombier unlock(&ctlr->ccblock);
2437dd7cddfSDavid du Colombier }
2447dd7cddfSDavid du Colombier
2457dd7cddfSDavid du Colombier static int
ccbavailable(void * a)2467dd7cddfSDavid du Colombier ccbavailable(void* a)
2477dd7cddfSDavid du Colombier {
2487dd7cddfSDavid du Colombier return ((Ctlr*)a)->ccb != nil;
2497dd7cddfSDavid du Colombier }
2507dd7cddfSDavid du Colombier
2517dd7cddfSDavid du Colombier static Ccb*
ccballoc(Ctlr * ctlr)2527dd7cddfSDavid du Colombier ccballoc(Ctlr* ctlr)
2537dd7cddfSDavid du Colombier {
2547dd7cddfSDavid du Colombier Ccb *ccb;
2557dd7cddfSDavid du Colombier
2567dd7cddfSDavid du Colombier for(;;){
2577dd7cddfSDavid du Colombier lock(&ctlr->ccblock);
25859cc4ca5SDavid du Colombier if((ccb = ctlr->ccb) != nil){
2597dd7cddfSDavid du Colombier if(ctlr->bus == 24)
2607dd7cddfSDavid du Colombier ctlr->ccb = ((Ccb24*)ccb)->ccb;
2617dd7cddfSDavid du Colombier else
2627dd7cddfSDavid du Colombier ctlr->ccb = ((Ccb32*)ccb)->ccb;
2637dd7cddfSDavid du Colombier unlock(&ctlr->ccblock);
2647dd7cddfSDavid du Colombier break;
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier unlock(&ctlr->ccblock);
2687dd7cddfSDavid du Colombier qlock(&ctlr->ccbq);
2697dd7cddfSDavid du Colombier if(waserror()){
2707dd7cddfSDavid du Colombier qunlock(&ctlr->ccbq);
2717dd7cddfSDavid du Colombier continue;
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier sleep(&ctlr->ccbr, ccbavailable, ctlr);
2747dd7cddfSDavid du Colombier qunlock(&ctlr->ccbq);
2757dd7cddfSDavid du Colombier poperror();
2767dd7cddfSDavid du Colombier }
2777dd7cddfSDavid du Colombier
2787dd7cddfSDavid du Colombier return ccb;
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier
2817dd7cddfSDavid du Colombier static int
done24(void * arg)2827dd7cddfSDavid du Colombier done24(void* arg)
2837dd7cddfSDavid du Colombier {
2847dd7cddfSDavid du Colombier return ((Ccb24*)arg)->done;
2857dd7cddfSDavid du Colombier }
2867dd7cddfSDavid du Colombier
2877dd7cddfSDavid du Colombier static int
mylex24rio(SDreq * r)2887dd7cddfSDavid du Colombier mylex24rio(SDreq* r)
2897dd7cddfSDavid du Colombier {
2907dd7cddfSDavid du Colombier ulong p;
2917dd7cddfSDavid du Colombier Ctlr *ctlr;
2927dd7cddfSDavid du Colombier Ccb24 *ccb;
29359cc4ca5SDavid du Colombier Mbox24 *mb;
2947dd7cddfSDavid du Colombier uchar *data, lun, *sense;
2957dd7cddfSDavid du Colombier int d, n, btstat, sdstat, target;
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier ctlr = r->unit->dev->ctlr;
2987dd7cddfSDavid du Colombier target = r->unit->subno;
2997dd7cddfSDavid du Colombier lun = (r->cmd[1]>>5) & 0x07;
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier /*
3027dd7cddfSDavid du Colombier * Ctlr->cache holds the last completed Ccb for this target if it
3037dd7cddfSDavid du Colombier * returned 'check condition'.
3047dd7cddfSDavid du Colombier * If this command is a request-sense and there is valid sense data
3057dd7cddfSDavid du Colombier * from the last completed Ccb, return it immediately.
3067dd7cddfSDavid du Colombier */
3077dd7cddfSDavid du Colombier lock(&ctlr->cachelock);
30859cc4ca5SDavid du Colombier if((ccb = ctlr->cache[target]) != nil){
3097dd7cddfSDavid du Colombier ctlr->cache[target] = nil;
3107dd7cddfSDavid du Colombier if(r->cmd[0] == 0x03
3117dd7cddfSDavid du Colombier && ccb->sdstat == SDcheck && lun == ((ccb->cs[1]>>5) & 0x07)){
3127dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
3137dd7cddfSDavid du Colombier if(r->dlen){
3147dd7cddfSDavid du Colombier sense = &ccb->cs[ccb->cdblen];
3157dd7cddfSDavid du Colombier n = 8+sense[7];
3167dd7cddfSDavid du Colombier if(n > r->dlen)
3177dd7cddfSDavid du Colombier n = r->dlen;
3187dd7cddfSDavid du Colombier memmove(r->data, sense, n);
3197dd7cddfSDavid du Colombier r->rlen = n;
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier ccbfree(ctlr, (Ccb*)ccb);
3227dd7cddfSDavid du Colombier return SDok;
3237dd7cddfSDavid du Colombier }
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
3267dd7cddfSDavid du Colombier if(ccb == nil)
3277dd7cddfSDavid du Colombier ccb = ccballoc(ctlr);
3287dd7cddfSDavid du Colombier
3297dd7cddfSDavid du Colombier /*
3307dd7cddfSDavid du Colombier * Check if the transfer is to memory above the 24-bit limit the
3317dd7cddfSDavid du Colombier * controller can address. If it is, try to allocate a temporary
3327dd7cddfSDavid du Colombier * buffer as a staging area.
3337dd7cddfSDavid du Colombier */
3347dd7cddfSDavid du Colombier n = r->dlen;
3357dd7cddfSDavid du Colombier if(n && !PADDR24(r->data, n)){
3367dd7cddfSDavid du Colombier data = mallocz(n, 0);
3377dd7cddfSDavid du Colombier if(data == nil || !PADDR24(data, n)){
3387dd7cddfSDavid du Colombier if(data != nil){
3397dd7cddfSDavid du Colombier free(data);
3407dd7cddfSDavid du Colombier ccb->data = nil;
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier ccbfree(ctlr, (Ccb*)ccb);
3437dd7cddfSDavid du Colombier return SDmalloc;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier if(r->write)
34659cc4ca5SDavid du Colombier memmove(data, r->data, n);
34759cc4ca5SDavid du Colombier ccb->data = r->data;
3487dd7cddfSDavid du Colombier }
3497dd7cddfSDavid du Colombier else
3507dd7cddfSDavid du Colombier data = r->data;
3517dd7cddfSDavid du Colombier
3527dd7cddfSDavid du Colombier /*
3537dd7cddfSDavid du Colombier * Fill in the ccb.
3547dd7cddfSDavid du Colombier */
3557dd7cddfSDavid du Colombier ccb->opcode = Ordl;
3567dd7cddfSDavid du Colombier
3577dd7cddfSDavid du Colombier ccb->datadir = (target<<5)|lun;
3587dd7cddfSDavid du Colombier if(n == 0)
3597dd7cddfSDavid du Colombier ccb->datadir |= CCBdataout|CCBdatain;
3607dd7cddfSDavid du Colombier else if(!r->write)
3617dd7cddfSDavid du Colombier ccb->datadir |= CCBdatain;
3627dd7cddfSDavid du Colombier else
3637dd7cddfSDavid du Colombier ccb->datadir |= CCBdataout;
3647dd7cddfSDavid du Colombier
3657dd7cddfSDavid du Colombier ccb->cdblen = r->clen;
3667dd7cddfSDavid du Colombier ccb->senselen = 0xFF;
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier ccb->datalen[0] = n>>16;
3697dd7cddfSDavid du Colombier ccb->datalen[1] = n>>8;
3707dd7cddfSDavid du Colombier ccb->datalen[2] = n;
3712c16e87eSDavid du Colombier if(data == nil)
3722c16e87eSDavid du Colombier p = 0;
3732c16e87eSDavid du Colombier else
3747dd7cddfSDavid du Colombier p = PADDR(data);
3757dd7cddfSDavid du Colombier ccb->dataptr[0] = p>>16;
3767dd7cddfSDavid du Colombier ccb->dataptr[1] = p>>8;
3777dd7cddfSDavid du Colombier ccb->dataptr[2] = p;
3787dd7cddfSDavid du Colombier
3797dd7cddfSDavid du Colombier ccb->linkptr[0] = ccb->linkptr[1] = ccb->linkptr[2] = 0;
3807dd7cddfSDavid du Colombier ccb->linkid = 0;
3817dd7cddfSDavid du Colombier ccb->btstat = ccb->sdstat = 0;
3827dd7cddfSDavid du Colombier ccb->reserved[0] = ccb->reserved[1] = 0;
3837dd7cddfSDavid du Colombier
3847dd7cddfSDavid du Colombier memmove(ccb->cs, r->cmd, r->clen);
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier /*
3877dd7cddfSDavid du Colombier * There's one more mbox than there there is
3887dd7cddfSDavid du Colombier * ccb so there is always one free.
3897dd7cddfSDavid du Colombier */
3907dd7cddfSDavid du Colombier lock(&ctlr->mboxlock);
3917dd7cddfSDavid du Colombier mb = ctlr->mb;
3927dd7cddfSDavid du Colombier mb += ctlr->mbox;
3937dd7cddfSDavid du Colombier p = PADDR(ccb);
3947dd7cddfSDavid du Colombier mb->ccb[0] = p>>16;
3957dd7cddfSDavid du Colombier mb->ccb[1] = p>>8;
3967dd7cddfSDavid du Colombier mb->ccb[2] = p;
3977dd7cddfSDavid du Colombier mb->code = Mbostart;
3987dd7cddfSDavid du Colombier ctlr->mbox++;
3997dd7cddfSDavid du Colombier if(ctlr->mbox >= NMbox)
4007dd7cddfSDavid du Colombier ctlr->mbox = 0;
4017dd7cddfSDavid du Colombier
4027dd7cddfSDavid du Colombier /*
4037dd7cddfSDavid du Colombier * This command does not require Hardy
4047dd7cddfSDavid du Colombier * and doesn't generate a Cmdc interrupt.
4057dd7cddfSDavid du Colombier */
4067dd7cddfSDavid du Colombier ccb->done = 0;
4077dd7cddfSDavid du Colombier outb(ctlr->port+Rcpr, Cstart);
4087dd7cddfSDavid du Colombier unlock(&ctlr->mboxlock);
4097dd7cddfSDavid du Colombier
4107dd7cddfSDavid du Colombier /*
4117dd7cddfSDavid du Colombier * Wait for the request to complete and return the status.
4127dd7cddfSDavid du Colombier * Since the buffer is not reference counted cannot return
4137dd7cddfSDavid du Colombier * until the DMA is done writing into the buffer so the caller
4147dd7cddfSDavid du Colombier * cannot free the buffer prematurely.
4157dd7cddfSDavid du Colombier */
4167dd7cddfSDavid du Colombier while(waserror())
4177dd7cddfSDavid du Colombier ;
4187dd7cddfSDavid du Colombier sleep(ccb, done24, ccb);
4197dd7cddfSDavid du Colombier poperror();
4207dd7cddfSDavid du Colombier
4217dd7cddfSDavid du Colombier /*
4227dd7cddfSDavid du Colombier * Save the status and patch up the number of
4237dd7cddfSDavid du Colombier * bytes actually transferred.
4247dd7cddfSDavid du Colombier * There's a firmware bug on some 956C controllers
4257dd7cddfSDavid du Colombier * which causes the return count from a successful
4267dd7cddfSDavid du Colombier * READ CAPACITY not be updated, so fix it here.
4277dd7cddfSDavid du Colombier */
4287dd7cddfSDavid du Colombier sdstat = ccb->sdstat;
4297dd7cddfSDavid du Colombier btstat = ccb->btstat;
4307dd7cddfSDavid du Colombier
4317dd7cddfSDavid du Colombier d = ccb->datalen[0]<<16;
4327dd7cddfSDavid du Colombier d |= ccb->datalen[1]<<8;
4337dd7cddfSDavid du Colombier d |= ccb->datalen[2];
4347dd7cddfSDavid du Colombier if(ccb->cs[0] == 0x25 && sdstat == SDok)
4357dd7cddfSDavid du Colombier d = 0;
4367dd7cddfSDavid du Colombier n -= d;
4377dd7cddfSDavid du Colombier r->rlen = n;
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier /*
4407dd7cddfSDavid du Colombier * Tidy things up if a staging area was used for the data,
4417dd7cddfSDavid du Colombier */
44259cc4ca5SDavid du Colombier if(ccb->data != nil){
4437dd7cddfSDavid du Colombier if(sdstat == SDok && btstat == 0 && !r->write)
4447dd7cddfSDavid du Colombier memmove(ccb->data, data, n);
4457dd7cddfSDavid du Colombier free(data);
4467dd7cddfSDavid du Colombier ccb->data = nil;
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier
4497dd7cddfSDavid du Colombier /*
4507dd7cddfSDavid du Colombier * If there was a check-condition, save the
4517dd7cddfSDavid du Colombier * ccb for a possible request-sense command.
4527dd7cddfSDavid du Colombier */
4537dd7cddfSDavid du Colombier if(sdstat == SDcheck){
4547dd7cddfSDavid du Colombier if(r->flags & SDnosense){
4557dd7cddfSDavid du Colombier lock(&ctlr->cachelock);
4567dd7cddfSDavid du Colombier if(ctlr->cache[target])
4577dd7cddfSDavid du Colombier ccbfree(ctlr, ctlr->cache[target]);
4587dd7cddfSDavid du Colombier ctlr->cache[target] = (Ccb*)ccb;
4597dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
4607dd7cddfSDavid du Colombier return SDcheck;
4617dd7cddfSDavid du Colombier }
4627dd7cddfSDavid du Colombier sense = &ccb->cs[ccb->cdblen];
4637dd7cddfSDavid du Colombier n = 8+sense[7];
4647dd7cddfSDavid du Colombier if(n > sizeof(r->sense)-1)
4657dd7cddfSDavid du Colombier n = sizeof(r->sense)-1;
4667dd7cddfSDavid du Colombier memmove(r->sense, sense, n);
4677dd7cddfSDavid du Colombier r->flags |= SDvalidsense;
4687dd7cddfSDavid du Colombier }
4697dd7cddfSDavid du Colombier ccbfree(ctlr, (Ccb*)ccb);
4707dd7cddfSDavid du Colombier
4717dd7cddfSDavid du Colombier if(btstat){
4727dd7cddfSDavid du Colombier if(btstat == 0x11)
4737dd7cddfSDavid du Colombier return SDtimeout;
4747dd7cddfSDavid du Colombier return SDeio;
4757dd7cddfSDavid du Colombier }
4767dd7cddfSDavid du Colombier return sdstat;
4777dd7cddfSDavid du Colombier }
4787dd7cddfSDavid du Colombier
4797dd7cddfSDavid du Colombier static void
mylex24interrupt(Ureg *,void * arg)4807dd7cddfSDavid du Colombier mylex24interrupt(Ureg*, void* arg)
4817dd7cddfSDavid du Colombier {
4827dd7cddfSDavid du Colombier ulong pa;
4837dd7cddfSDavid du Colombier Ctlr *ctlr;
4847dd7cddfSDavid du Colombier Ccb24 *ccb;
4857dd7cddfSDavid du Colombier Mbox24 *mb, *mbox;
4867dd7cddfSDavid du Colombier int port, rinterrupt, rstatus;
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier ctlr = arg;
4897dd7cddfSDavid du Colombier port = ctlr->port;
4907dd7cddfSDavid du Colombier
4917dd7cddfSDavid du Colombier /*
4927dd7cddfSDavid du Colombier * Save and clear the interrupt(s). The only
4937dd7cddfSDavid du Colombier * interrupts expected are Cmdc, which is ignored,
4947dd7cddfSDavid du Colombier * and Imbl which means something completed.
4957dd7cddfSDavid du Colombier * There's one spurious interrupt left over from
4967dd7cddfSDavid du Colombier * initialisation, ignore it.
4977dd7cddfSDavid du Colombier */
4987dd7cddfSDavid du Colombier rinterrupt = inb(port+Rinterrupt);
4997dd7cddfSDavid du Colombier rstatus = inb(port+Rstatus);
5007dd7cddfSDavid du Colombier outb(port+Rcontrol, Rint);
5017dd7cddfSDavid du Colombier if((rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
5027dd7cddfSDavid du Colombier print("%s: interrupt 0x%2.2ux\n",
5037dd7cddfSDavid du Colombier ctlr->sdev->name, rinterrupt);
5047dd7cddfSDavid du Colombier if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
5057dd7cddfSDavid du Colombier print("%s: command invalid\n", ctlr->sdev->name);
5067dd7cddfSDavid du Colombier
5077dd7cddfSDavid du Colombier /*
5087dd7cddfSDavid du Colombier * Look for something in the mail.
5097dd7cddfSDavid du Colombier * If there is, save the status, free the mailbox
5107dd7cddfSDavid du Colombier * and wakeup whoever.
5117dd7cddfSDavid du Colombier */
5127dd7cddfSDavid du Colombier mb = ctlr->mb;
5137dd7cddfSDavid du Colombier for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
5147dd7cddfSDavid du Colombier pa = (mbox->ccb[0]<<16)|(mbox->ccb[1]<<8)|mbox->ccb[2];
5157dd7cddfSDavid du Colombier ccb = BPA2K(pa, BUSUNKNOWN);
5167dd7cddfSDavid du Colombier mbox->code = 0;
5177dd7cddfSDavid du Colombier ccb->done = 1;
5187dd7cddfSDavid du Colombier wakeup(ccb);
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier ctlr->mbix++;
5217dd7cddfSDavid du Colombier if(ctlr->mbix >= NMbox+NMbox)
5227dd7cddfSDavid du Colombier ctlr->mbix = NMbox;
5237dd7cddfSDavid du Colombier }
5247dd7cddfSDavid du Colombier }
5257dd7cddfSDavid du Colombier
5267dd7cddfSDavid du Colombier static int
done32(void * arg)5277dd7cddfSDavid du Colombier done32(void* arg)
5287dd7cddfSDavid du Colombier {
5297dd7cddfSDavid du Colombier return ((Ccb32*)arg)->done;
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier
5327dd7cddfSDavid du Colombier static int
mylex32rio(SDreq * r)5337dd7cddfSDavid du Colombier mylex32rio(SDreq* r)
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier ulong p;
5367dd7cddfSDavid du Colombier uchar lun;
5377dd7cddfSDavid du Colombier Ctlr *ctlr;
5387dd7cddfSDavid du Colombier Ccb32 *ccb;
5397dd7cddfSDavid du Colombier Mbox32 *mb;
5407dd7cddfSDavid du Colombier int d, n, btstat, sdstat, target;
5417dd7cddfSDavid du Colombier
5427dd7cddfSDavid du Colombier ctlr = r->unit->dev->ctlr;
5437dd7cddfSDavid du Colombier target = r->unit->subno;
5447dd7cddfSDavid du Colombier lun = (r->cmd[1]>>5) & 0x07;
5457dd7cddfSDavid du Colombier
5467dd7cddfSDavid du Colombier /*
5477dd7cddfSDavid du Colombier * Ctlr->cache holds the last completed Ccb for this target if it
5487dd7cddfSDavid du Colombier * returned 'check condition'.
5497dd7cddfSDavid du Colombier * If this command is a request-sense and there is valid sense data
5507dd7cddfSDavid du Colombier * from the last completed Ccb, return it immediately.
5517dd7cddfSDavid du Colombier */
5527dd7cddfSDavid du Colombier lock(&ctlr->cachelock);
55359cc4ca5SDavid du Colombier if((ccb = ctlr->cache[target]) != nil){
5547dd7cddfSDavid du Colombier ctlr->cache[target] = nil;
5557dd7cddfSDavid du Colombier if(r->cmd[0] == 0x03
5567dd7cddfSDavid du Colombier && ccb->sdstat == SDcheck && lun == (ccb->luntag & 0x07)){
5577dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
5587dd7cddfSDavid du Colombier if(r->dlen){
5597dd7cddfSDavid du Colombier n = 8+ccb->sense[7];
5607dd7cddfSDavid du Colombier if(n > r->dlen)
5617dd7cddfSDavid du Colombier n = r->dlen;
5627dd7cddfSDavid du Colombier memmove(r->data, ccb->sense, n);
5637dd7cddfSDavid du Colombier r->rlen = n;
5647dd7cddfSDavid du Colombier }
5657dd7cddfSDavid du Colombier ccbfree(ctlr, (Ccb*)ccb);
5667dd7cddfSDavid du Colombier return SDok;
5677dd7cddfSDavid du Colombier }
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
5707dd7cddfSDavid du Colombier if(ccb == nil)
5717dd7cddfSDavid du Colombier ccb = ccballoc(ctlr);
5727dd7cddfSDavid du Colombier
5737dd7cddfSDavid du Colombier /*
5747dd7cddfSDavid du Colombier * Fill in the ccb.
5757dd7cddfSDavid du Colombier */
5767dd7cddfSDavid du Colombier ccb->opcode = Ordl;
5777dd7cddfSDavid du Colombier
5787dd7cddfSDavid du Colombier n = r->dlen;
5797dd7cddfSDavid du Colombier if(n == 0)
58059cc4ca5SDavid du Colombier ccb->datadir = CCBdataout|CCBdatain;
5817dd7cddfSDavid du Colombier else if(!r->write)
58259cc4ca5SDavid du Colombier ccb->datadir = CCBdatain;
5837dd7cddfSDavid du Colombier else
58459cc4ca5SDavid du Colombier ccb->datadir = CCBdataout;
5857dd7cddfSDavid du Colombier
5867dd7cddfSDavid du Colombier ccb->cdblen = r->clen;
5877dd7cddfSDavid du Colombier
5887dd7cddfSDavid du Colombier ccb->datalen[0] = n;
5897dd7cddfSDavid du Colombier ccb->datalen[1] = n>>8;
5907dd7cddfSDavid du Colombier ccb->datalen[2] = n>>16;
5917dd7cddfSDavid du Colombier ccb->datalen[3] = n>>24;
5922c16e87eSDavid du Colombier if(r->data == nil)
5932c16e87eSDavid du Colombier p = 0;
5942c16e87eSDavid du Colombier else
5957dd7cddfSDavid du Colombier p = PADDR(r->data);
5967dd7cddfSDavid du Colombier ccb->dataptr[0] = p;
5977dd7cddfSDavid du Colombier ccb->dataptr[1] = p>>8;
5987dd7cddfSDavid du Colombier ccb->dataptr[2] = p>>16;
5997dd7cddfSDavid du Colombier ccb->dataptr[3] = p>>24;
6007dd7cddfSDavid du Colombier
6017dd7cddfSDavid du Colombier ccb->targetid = target;
6027dd7cddfSDavid du Colombier ccb->luntag = lun;
6037dd7cddfSDavid du Colombier if(r->unit->inquiry[7] & 0x02)
6046bfdd830SDavid du Colombier if(ctlr->wide)
6056bfdd830SDavid du Colombier ccb->datadir |= SQTag|TagEnable;
6066bfdd830SDavid du Colombier else
6077dd7cddfSDavid du Colombier ccb->luntag |= SQTag|TagEnable;
6087dd7cddfSDavid du Colombier memmove(ccb->cdb, r->cmd, r->clen);
6097dd7cddfSDavid du Colombier ccb->btstat = ccb->sdstat = 0;
6107dd7cddfSDavid du Colombier ccb->ccbctl = 0;
6117dd7cddfSDavid du Colombier
6127dd7cddfSDavid du Colombier /*
6137dd7cddfSDavid du Colombier * There's one more mbox than there there is
6147dd7cddfSDavid du Colombier * ccb so there is always one free.
6157dd7cddfSDavid du Colombier */
6167dd7cddfSDavid du Colombier lock(&ctlr->mboxlock);
6177dd7cddfSDavid du Colombier mb = ctlr->mb;
6187dd7cddfSDavid du Colombier mb += ctlr->mbox;
6197dd7cddfSDavid du Colombier p = PADDR(ccb);
6207dd7cddfSDavid du Colombier mb->ccb[0] = p;
6217dd7cddfSDavid du Colombier mb->ccb[1] = p>>8;
6227dd7cddfSDavid du Colombier mb->ccb[2] = p>>16;
6237dd7cddfSDavid du Colombier mb->ccb[3] = p>>24;
6247dd7cddfSDavid du Colombier mb->code = Mbostart;
6257dd7cddfSDavid du Colombier ctlr->mbox++;
6267dd7cddfSDavid du Colombier if(ctlr->mbox >= NMbox)
6277dd7cddfSDavid du Colombier ctlr->mbox = 0;
6287dd7cddfSDavid du Colombier
6297dd7cddfSDavid du Colombier /*
6307dd7cddfSDavid du Colombier * This command does not require Hardy
6317dd7cddfSDavid du Colombier * and doesn't generate a Cmdc interrupt.
6327dd7cddfSDavid du Colombier */
6337dd7cddfSDavid du Colombier ccb->done = 0;
6347dd7cddfSDavid du Colombier outb(ctlr->port+Rcpr, Cstart);
6357dd7cddfSDavid du Colombier unlock(&ctlr->mboxlock);
6367dd7cddfSDavid du Colombier
6377dd7cddfSDavid du Colombier /*
6387dd7cddfSDavid du Colombier * Wait for the request to complete and return the status.
6397dd7cddfSDavid du Colombier * Since the buffer is not reference counted cannot return
6407dd7cddfSDavid du Colombier * until the DMA is done writing into the buffer so the caller
6417dd7cddfSDavid du Colombier * cannot free the buffer prematurely.
6427dd7cddfSDavid du Colombier */
6437dd7cddfSDavid du Colombier while(waserror())
6447dd7cddfSDavid du Colombier ;
64580ee5cbfSDavid du Colombier sleep(ccb, done32, ccb);
6467dd7cddfSDavid du Colombier poperror();
6477dd7cddfSDavid du Colombier
6487dd7cddfSDavid du Colombier /*
6497dd7cddfSDavid du Colombier * Save the status and patch up the number of
6507dd7cddfSDavid du Colombier * bytes actually transferred.
6517dd7cddfSDavid du Colombier * There's a firmware bug on some 956C controllers
6527dd7cddfSDavid du Colombier * which causes the return count from a successful
6537dd7cddfSDavid du Colombier * READ CAPACITY not to be updated, so fix it here.
6547dd7cddfSDavid du Colombier */
6557dd7cddfSDavid du Colombier sdstat = ccb->sdstat;
6567dd7cddfSDavid du Colombier btstat = ccb->btstat;
6577dd7cddfSDavid du Colombier
6587dd7cddfSDavid du Colombier d = ccb->datalen[0];
6597dd7cddfSDavid du Colombier d |= (ccb->datalen[1]<<8);
6607dd7cddfSDavid du Colombier d |= (ccb->datalen[2]<<16);
6617dd7cddfSDavid du Colombier d |= (ccb->datalen[3]<<24);
6627dd7cddfSDavid du Colombier if(ccb->cdb[0] == 0x25 && sdstat == SDok)
6637dd7cddfSDavid du Colombier d = 0;
6647dd7cddfSDavid du Colombier n -= d;
6657dd7cddfSDavid du Colombier r->rlen = n;
6667dd7cddfSDavid du Colombier
6677dd7cddfSDavid du Colombier /*
6687dd7cddfSDavid du Colombier * If there was a check-condition, save the
6697dd7cddfSDavid du Colombier * ccb for a possible request-sense command.
6707dd7cddfSDavid du Colombier */
6717dd7cddfSDavid du Colombier if(sdstat == SDcheck){
6727dd7cddfSDavid du Colombier if(r->flags & SDnosense){
6737dd7cddfSDavid du Colombier lock(&ctlr->cachelock);
6747dd7cddfSDavid du Colombier if(ctlr->cache[target])
6757dd7cddfSDavid du Colombier ccbfree(ctlr, ctlr->cache[target]);
6767dd7cddfSDavid du Colombier ctlr->cache[target] = (Ccb*)ccb;
6777dd7cddfSDavid du Colombier unlock(&ctlr->cachelock);
6787dd7cddfSDavid du Colombier return SDcheck;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier n = 8+ccb->sense[7];
6817dd7cddfSDavid du Colombier if(n > sizeof(r->sense)-1)
6827dd7cddfSDavid du Colombier n = sizeof(r->sense)-1;
6837dd7cddfSDavid du Colombier memmove(r->sense, ccb->sense, n);
6847dd7cddfSDavid du Colombier r->flags |= SDvalidsense;
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier ccbfree(ctlr, (Ccb*)ccb);
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier if(btstat){
6897dd7cddfSDavid du Colombier if(btstat == 0x11)
6907dd7cddfSDavid du Colombier return SDtimeout;
6917dd7cddfSDavid du Colombier return SDeio;
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier return sdstat;
6947dd7cddfSDavid du Colombier }
6957dd7cddfSDavid du Colombier
6967dd7cddfSDavid du Colombier static void
mylex32interrupt(Ureg *,void * arg)6977dd7cddfSDavid du Colombier mylex32interrupt(Ureg*, void* arg)
6987dd7cddfSDavid du Colombier {
6997dd7cddfSDavid du Colombier ulong pa;
7007dd7cddfSDavid du Colombier Ctlr *ctlr;
7017dd7cddfSDavid du Colombier Ccb32 *ccb;
7027dd7cddfSDavid du Colombier Mbox32 *mb, *mbox;
7037dd7cddfSDavid du Colombier int port, rinterrupt, rstatus;
7047dd7cddfSDavid du Colombier
7057dd7cddfSDavid du Colombier ctlr = arg;
7067dd7cddfSDavid du Colombier port = ctlr->port;
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier /*
7097dd7cddfSDavid du Colombier * Save and clear the interrupt(s). The only
7107dd7cddfSDavid du Colombier * interrupts expected are Cmdc, which is ignored,
7117dd7cddfSDavid du Colombier * and Imbl which means something completed.
7127dd7cddfSDavid du Colombier * There's one spurious interrupt left over from
7137dd7cddfSDavid du Colombier * initialisation, ignore it.
714d649fdd7SDavid du Colombier * In order to share PCI IRQs, just ignore spurious interrupts.
7157dd7cddfSDavid du Colombier */
7167dd7cddfSDavid du Colombier rinterrupt = inb(port+Rinterrupt);
7177dd7cddfSDavid du Colombier rstatus = inb(port+Rstatus);
7187dd7cddfSDavid du Colombier outb(port+Rcontrol, Rint);
719d649fdd7SDavid du Colombier if(0 && (rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
7207dd7cddfSDavid du Colombier print("%s: interrupt 0x%2.2ux\n",
7217dd7cddfSDavid du Colombier ctlr->sdev->name, rinterrupt);
7227dd7cddfSDavid du Colombier if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
7237dd7cddfSDavid du Colombier print("%s: command invalid\n", ctlr->sdev->name);
7247dd7cddfSDavid du Colombier
7257dd7cddfSDavid du Colombier /*
7267dd7cddfSDavid du Colombier * Look for something in the mail.
7277dd7cddfSDavid du Colombier * If there is, free the mailbox and wakeup whoever.
7287dd7cddfSDavid du Colombier */
7297dd7cddfSDavid du Colombier mb = ctlr->mb;
7307dd7cddfSDavid du Colombier for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
7317dd7cddfSDavid du Colombier pa = (mbox->ccb[3]<<24)
7327dd7cddfSDavid du Colombier |(mbox->ccb[2]<<16)
7337dd7cddfSDavid du Colombier |(mbox->ccb[1]<<8)
7347dd7cddfSDavid du Colombier |mbox->ccb[0];
7357dd7cddfSDavid du Colombier if(ctlr->pcidev)
7367dd7cddfSDavid du Colombier ccb = BPA2K(pa, ctlr->pcidev->tbdf);
7377dd7cddfSDavid du Colombier else
7387dd7cddfSDavid du Colombier ccb = BPA2K(pa, BUSUNKNOWN);
7397dd7cddfSDavid du Colombier mbox->code = 0;
7407dd7cddfSDavid du Colombier ccb->done = 1;
7417dd7cddfSDavid du Colombier wakeup(ccb);
7427dd7cddfSDavid du Colombier
7437dd7cddfSDavid du Colombier ctlr->mbix++;
7447dd7cddfSDavid du Colombier if(ctlr->mbix >= NMbox+NMbox)
7457dd7cddfSDavid du Colombier ctlr->mbix = NMbox;
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier }
7487dd7cddfSDavid du Colombier
7497dd7cddfSDavid du Colombier static int
mylexrio(SDreq * r)7507dd7cddfSDavid du Colombier mylexrio(SDreq* r)
7517dd7cddfSDavid du Colombier {
752223a736eSDavid du Colombier int subno;
7537dd7cddfSDavid du Colombier Ctlr *ctlr;
7547dd7cddfSDavid du Colombier
755223a736eSDavid du Colombier subno = r->unit->subno;
7567dd7cddfSDavid du Colombier ctlr = r->unit->dev->ctlr;
757223a736eSDavid du Colombier if(subno == ctlr->id || (!ctlr->wide && subno >= 8))
7587dd7cddfSDavid du Colombier r->status = SDtimeout;
7597dd7cddfSDavid du Colombier else if(ctlr->bus == 24)
7607dd7cddfSDavid du Colombier r->status = mylex24rio(r);
7617dd7cddfSDavid du Colombier else
7627dd7cddfSDavid du Colombier r->status = mylex32rio(r);
7637dd7cddfSDavid du Colombier return r->status;
7647dd7cddfSDavid du Colombier }
7657dd7cddfSDavid du Colombier
7667dd7cddfSDavid du Colombier /*
7677dd7cddfSDavid du Colombier * Issue a command to a controller. The command and its length is
7687dd7cddfSDavid du Colombier * contained in cmd and cmdlen. If any data is to be
7697dd7cddfSDavid du Colombier * returned, datalen should be non-zero, and the returned data
7707dd7cddfSDavid du Colombier * will be placed in data.
7717dd7cddfSDavid du Colombier * If Cmdc is set, bail out, the invalid command will be handled
7727dd7cddfSDavid du Colombier * when the interrupt is processed.
7737dd7cddfSDavid du Colombier */
7747dd7cddfSDavid du Colombier static void
issueio(int port,uchar * cmd,int cmdlen,uchar * data,int datalen)7757dd7cddfSDavid du Colombier issueio(int port, uchar* cmd, int cmdlen, uchar* data, int datalen)
7767dd7cddfSDavid du Colombier {
7777dd7cddfSDavid du Colombier int len;
7787dd7cddfSDavid du Colombier
7797dd7cddfSDavid du Colombier if(cmd[0] != Cstart && cmd[0] != Ceombri){
7807dd7cddfSDavid du Colombier while(!(inb(port+Rstatus) & Hardy))
7817dd7cddfSDavid du Colombier ;
7827dd7cddfSDavid du Colombier }
7837dd7cddfSDavid du Colombier outb(port+Rcpr, cmd[0]);
7847dd7cddfSDavid du Colombier
7857dd7cddfSDavid du Colombier len = 1;
7867dd7cddfSDavid du Colombier while(len < cmdlen){
7877dd7cddfSDavid du Colombier if(!(inb(port+Rstatus) & Cprbsy)){
7887dd7cddfSDavid du Colombier outb(port+Rcpr, cmd[len]);
7897dd7cddfSDavid du Colombier len++;
7907dd7cddfSDavid du Colombier }
7917dd7cddfSDavid du Colombier if(inb(port+Rinterrupt) & Cmdc)
7927dd7cddfSDavid du Colombier return;
7937dd7cddfSDavid du Colombier }
7947dd7cddfSDavid du Colombier
7957dd7cddfSDavid du Colombier if(datalen){
7967dd7cddfSDavid du Colombier len = 0;
7977dd7cddfSDavid du Colombier while(len < datalen){
7987dd7cddfSDavid du Colombier if(inb(port+Rstatus) & Dirrdy){
7997dd7cddfSDavid du Colombier data[len] = inb(port+Rdatain);
8007dd7cddfSDavid du Colombier len++;
8017dd7cddfSDavid du Colombier }
8027dd7cddfSDavid du Colombier if(inb(port+Rinterrupt) & Cmdc)
8037dd7cddfSDavid du Colombier return;
8047dd7cddfSDavid du Colombier }
8057dd7cddfSDavid du Colombier }
8067dd7cddfSDavid du Colombier }
8077dd7cddfSDavid du Colombier
8087dd7cddfSDavid du Colombier /*
8097dd7cddfSDavid du Colombier * Issue a command to a controller, wait for it to complete then
8107dd7cddfSDavid du Colombier * try to reset the interrupt. Should only be called at initialisation.
8117dd7cddfSDavid du Colombier */
8127dd7cddfSDavid du Colombier static int
issue(Ctlr * ctlr,uchar * cmd,int cmdlen,uchar * data,int datalen)8137dd7cddfSDavid du Colombier issue(Ctlr* ctlr, uchar* cmd, int cmdlen, uchar* data, int datalen)
8147dd7cddfSDavid du Colombier {
8157dd7cddfSDavid du Colombier int port;
8167dd7cddfSDavid du Colombier uchar rinterrupt, rstatus;
8177dd7cddfSDavid du Colombier static Lock mylexissuelock;
8187dd7cddfSDavid du Colombier
8197dd7cddfSDavid du Colombier port = ctlr->port;
8207dd7cddfSDavid du Colombier
8217dd7cddfSDavid du Colombier ilock(&ctlr->issuelock);
8227dd7cddfSDavid du Colombier issueio(port, cmd, cmdlen, data, datalen);
8237dd7cddfSDavid du Colombier
8247dd7cddfSDavid du Colombier while(!((rinterrupt = inb(port+Rinterrupt)) & Cmdc))
8257dd7cddfSDavid du Colombier ;
8267dd7cddfSDavid du Colombier
8277dd7cddfSDavid du Colombier rstatus = inb(port+Rstatus);
8287dd7cddfSDavid du Colombier outb(port+Rcontrol, Rint);
8297dd7cddfSDavid du Colombier iunlock(&ctlr->issuelock);
8307dd7cddfSDavid du Colombier
8317dd7cddfSDavid du Colombier if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
8327dd7cddfSDavid du Colombier return 0;
8337dd7cddfSDavid du Colombier return 1;
8347dd7cddfSDavid du Colombier }
8357dd7cddfSDavid du Colombier
8367dd7cddfSDavid du Colombier static SDev*
mylexprobe(int port,int irq)8377dd7cddfSDavid du Colombier mylexprobe(int port, int irq)
8387dd7cddfSDavid du Colombier {
8397dd7cddfSDavid du Colombier SDev *sdev;
8407dd7cddfSDavid du Colombier Ctlr *ctlr;
8417dd7cddfSDavid du Colombier uchar cmd[6], data[256];
8427dd7cddfSDavid du Colombier int clen, dlen, timeo;
843*fececb92SDavid du Colombier static int count;
8447dd7cddfSDavid du Colombier
8457dd7cddfSDavid du Colombier if(ioalloc(port, 0x3, 0, "mylex") < 0)
8467dd7cddfSDavid du Colombier return nil;
8477dd7cddfSDavid du Colombier ctlr = nil;
8489a747e4fSDavid du Colombier sdev = nil;
8497dd7cddfSDavid du Colombier /*
8507dd7cddfSDavid du Colombier * Attempt to hard-reset the board and reset
8517dd7cddfSDavid du Colombier * the SCSI bus. If the board state doesn't settle to
8527dd7cddfSDavid du Colombier * idle with mailbox initialisation required, either
8537dd7cddfSDavid du Colombier * it isn't a compatible board or it's broken.
8547dd7cddfSDavid du Colombier * If the controller has SCAM set this can take a while.
8557dd7cddfSDavid du Colombier */
85680ee5cbfSDavid du Colombier if(getconf("*noscsireset") != nil)
85780ee5cbfSDavid du Colombier outb(port+Rcontrol, Rhard);
85880ee5cbfSDavid du Colombier else
8597dd7cddfSDavid du Colombier outb(port+Rcontrol, Rhard|Rsbus);
8607dd7cddfSDavid du Colombier for(timeo = 0; timeo < 100; timeo++){
8617dd7cddfSDavid du Colombier if(inb(port+Rstatus) == (Inreq|Hardy))
8627dd7cddfSDavid du Colombier break;
8637dd7cddfSDavid du Colombier delay(100);
8647dd7cddfSDavid du Colombier }
8657dd7cddfSDavid du Colombier if(inb(port+Rstatus) != (Inreq|Hardy)){
8667dd7cddfSDavid du Colombier buggery:
8677dd7cddfSDavid du Colombier if(ctlr != nil)
8687dd7cddfSDavid du Colombier free(ctlr);
8699a747e4fSDavid du Colombier if (sdev != nil)
8709a747e4fSDavid du Colombier free(sdev);
8717dd7cddfSDavid du Colombier iofree(port);
8727dd7cddfSDavid du Colombier return nil;
8737dd7cddfSDavid du Colombier }
8747dd7cddfSDavid du Colombier
8757dd7cddfSDavid du Colombier if((ctlr = malloc(sizeof(Ctlr))) == nil)
8767dd7cddfSDavid du Colombier goto buggery;
8777dd7cddfSDavid du Colombier ctlr->port = port;
8787dd7cddfSDavid du Colombier ctlr->irq = irq;
8797dd7cddfSDavid du Colombier ctlr->bus = 24;
8807dd7cddfSDavid du Colombier ctlr->wide = 0;
8817dd7cddfSDavid du Colombier
8827dd7cddfSDavid du Colombier /*
8837dd7cddfSDavid du Colombier * Try to determine if this is a 32-bit MultiMaster controller
8847dd7cddfSDavid du Colombier * by attempting to obtain the extended inquiry information;
8857dd7cddfSDavid du Colombier * this command is not implemented on Adaptec 154xx
8867dd7cddfSDavid du Colombier * controllers. If successful, the first byte of the returned
8877dd7cddfSDavid du Colombier * data is the host adapter bus type, 'E' for 32-bit EISA,
8887dd7cddfSDavid du Colombier * PCI and VLB buses.
8897dd7cddfSDavid du Colombier */
8907dd7cddfSDavid du Colombier cmd[0] = Ciesi;
8916bfdd830SDavid du Colombier cmd[1] = 14;
8927dd7cddfSDavid du Colombier clen = 2;
8937dd7cddfSDavid du Colombier dlen = 256;
8947dd7cddfSDavid du Colombier if(issue(ctlr, cmd, clen, data, dlen)){
8957dd7cddfSDavid du Colombier if(data[0] == 'E')
8967dd7cddfSDavid du Colombier ctlr->bus = 32;
8977dd7cddfSDavid du Colombier ctlr->wide = data[0x0D] & 0x01;
898*fececb92SDavid du Colombier /*
899*fececb92SDavid du Colombier * devsd doesn't pass us the `spec' argument, so
900*fececb92SDavid du Colombier * we'll assume that sd0 goes to the first scsi host
901*fececb92SDavid du Colombier * adapter found, etc.
902*fececb92SDavid du Colombier */
903*fececb92SDavid du Colombier print("#S/sd%d: mylex SCSI: port 0x%ux: %d-bit, ",
904*fececb92SDavid du Colombier count++, ctlr->port, ctlr->bus);
9056bfdd830SDavid du Colombier if (ctlr->wide)
906*fececb92SDavid du Colombier print("wide\n");
9076bfdd830SDavid du Colombier else
908*fececb92SDavid du Colombier print("narrow\n");
9097dd7cddfSDavid du Colombier }
9107dd7cddfSDavid du Colombier else{
9117dd7cddfSDavid du Colombier /*
9127dd7cddfSDavid du Colombier * Inconceivable though it may seem, a hard controller reset
9137dd7cddfSDavid du Colombier * is necessary here to clear out the command queue. Every
9147dd7cddfSDavid du Colombier * board seems to lock-up in a different way if you give an
9157dd7cddfSDavid du Colombier * invalid command and then try to clear out the
9167dd7cddfSDavid du Colombier * command/parameter and/or data-in register.
9177dd7cddfSDavid du Colombier * Soft reset doesn't do the job either. Fortunately no
9187dd7cddfSDavid du Colombier * serious initialisation has been done yet so there's nothing
9197dd7cddfSDavid du Colombier * to tidy up.
9207dd7cddfSDavid du Colombier */
9217dd7cddfSDavid du Colombier outb(port+Rcontrol, Rhard);
9227dd7cddfSDavid du Colombier for(timeo = 0; timeo < 100; timeo++){
9237dd7cddfSDavid du Colombier if(inb(port+Rstatus) == (Inreq|Hardy))
9247dd7cddfSDavid du Colombier break;
9257dd7cddfSDavid du Colombier delay(100);
9267dd7cddfSDavid du Colombier }
9277dd7cddfSDavid du Colombier if(inb(port+Rstatus) != (Inreq|Hardy))
9287dd7cddfSDavid du Colombier goto buggery;
9297dd7cddfSDavid du Colombier }
9307dd7cddfSDavid du Colombier
9317dd7cddfSDavid du Colombier /*
9327dd7cddfSDavid du Colombier * If the BIOS is enabled on the AHA-1542C/CF and BIOS options for
9337dd7cddfSDavid du Colombier * support of drives > 1Gb, dynamic scanning of the SCSI bus or more
9347dd7cddfSDavid du Colombier * than 2 drives under DOS 5.0 are enabled, the BIOS disables
9357dd7cddfSDavid du Colombier * accepting Cmbinit to protect against running with drivers which
9367dd7cddfSDavid du Colombier * don't support those options. In order to unlock the interface it
9377dd7cddfSDavid du Colombier * is necessary to read a lock-code using Cextbios and write it back
9387dd7cddfSDavid du Colombier * using Cmbienable; the lock-code is non-zero.
9397dd7cddfSDavid du Colombier */
9407dd7cddfSDavid du Colombier cmd[0] = Cinquiry;
9417dd7cddfSDavid du Colombier clen = 1;
9427dd7cddfSDavid du Colombier dlen = 4;
9437dd7cddfSDavid du Colombier if(issue(ctlr, cmd, clen, data, dlen) == 0)
9447dd7cddfSDavid du Colombier goto buggery;
9457dd7cddfSDavid du Colombier if(data[0] >= 0x43){
9467dd7cddfSDavid du Colombier cmd[0] = Cextbios;
9477dd7cddfSDavid du Colombier clen = 1;
9487dd7cddfSDavid du Colombier dlen = 2;
9497dd7cddfSDavid du Colombier if(issue(ctlr, cmd, clen, data, dlen) == 0)
9507dd7cddfSDavid du Colombier goto buggery;
9517dd7cddfSDavid du Colombier
9527dd7cddfSDavid du Colombier /*
9537dd7cddfSDavid du Colombier * Lock-code returned in data[1]. If it's non-zero write
9547dd7cddfSDavid du Colombier * it back along with bit 0 of byte 0 cleared to enable
9557dd7cddfSDavid du Colombier * mailbox initialisation.
9567dd7cddfSDavid du Colombier */
9577dd7cddfSDavid du Colombier if(data[1]){
9587dd7cddfSDavid du Colombier cmd[0] = Cmbienable;
9597dd7cddfSDavid du Colombier cmd[1] = 0;
9607dd7cddfSDavid du Colombier cmd[2] = data[1];
9617dd7cddfSDavid du Colombier clen = 3;
9627dd7cddfSDavid du Colombier if(issue(ctlr, cmd, clen, 0, 0) == 0)
9637dd7cddfSDavid du Colombier goto buggery;
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier }
9667dd7cddfSDavid du Colombier
9677dd7cddfSDavid du Colombier /*
9687dd7cddfSDavid du Colombier * Get the id, DMA and IRQ info from the board. This will
9697dd7cddfSDavid du Colombier * cause an interrupt which will hopefully not cause any
9707dd7cddfSDavid du Colombier * trouble because the interrupt number isn't known yet.
9717dd7cddfSDavid du Colombier * This is necessary as the DMA won't be set up if the
9727dd7cddfSDavid du Colombier * board has the BIOS disabled.
9737dd7cddfSDavid du Colombier *
9747dd7cddfSDavid du Colombier * If the IRQ is already known, this must be a 32-bit PCI
9757dd7cddfSDavid du Colombier * or EISA card, in which case the returned DMA and IRQ can
9767dd7cddfSDavid du Colombier * be ignored.
9777dd7cddfSDavid du Colombier */
9787dd7cddfSDavid du Colombier cmd[0] = Cinquire;
9797dd7cddfSDavid du Colombier clen = 1;
9807dd7cddfSDavid du Colombier dlen = 3;
9817dd7cddfSDavid du Colombier if(issue(ctlr, cmd, clen, data, dlen) == 0)
9827dd7cddfSDavid du Colombier goto buggery;
9837dd7cddfSDavid du Colombier
9847dd7cddfSDavid du Colombier ctlr->id = data[2] & 0x07;
9857dd7cddfSDavid du Colombier if(ctlr->irq < 0){
9867dd7cddfSDavid du Colombier switch(data[0]){ /* DMA Arbitration Priority */
9877dd7cddfSDavid du Colombier case 0x80: /* Channel 7 */
9887dd7cddfSDavid du Colombier outb(0xD6, 0xC3);
9897dd7cddfSDavid du Colombier outb(0xD4, 0x03);
9907dd7cddfSDavid du Colombier break;
9917dd7cddfSDavid du Colombier case 0x40: /* Channel 6 */
9927dd7cddfSDavid du Colombier outb(0xD6, 0xC2);
9937dd7cddfSDavid du Colombier outb(0xD4, 0x02);
9947dd7cddfSDavid du Colombier break;
9957dd7cddfSDavid du Colombier case 0x20: /* Channel 5 */
9967dd7cddfSDavid du Colombier outb(0xD6, 0xC1);
9977dd7cddfSDavid du Colombier outb(0xD4, 0x01);
9987dd7cddfSDavid du Colombier break;
9997dd7cddfSDavid du Colombier case 0x01: /* Channel 0 */
10007dd7cddfSDavid du Colombier outb(0x0B, 0xC0);
10017dd7cddfSDavid du Colombier outb(0x0A, 0x00);
10027dd7cddfSDavid du Colombier break;
10037dd7cddfSDavid du Colombier default:
100459cc4ca5SDavid du Colombier if(ctlr->bus == 24)
100559cc4ca5SDavid du Colombier goto buggery;
10067dd7cddfSDavid du Colombier break;
10077dd7cddfSDavid du Colombier }
10087dd7cddfSDavid du Colombier
10097dd7cddfSDavid du Colombier switch(data[1]){ /* Interrupt Channel */
10107dd7cddfSDavid du Colombier case 0x40:
10117dd7cddfSDavid du Colombier ctlr->irq = 15;
10127dd7cddfSDavid du Colombier break;
10137dd7cddfSDavid du Colombier case 0x20:
10147dd7cddfSDavid du Colombier ctlr->irq = 14;
10157dd7cddfSDavid du Colombier break;
10167dd7cddfSDavid du Colombier case 0x08:
10177dd7cddfSDavid du Colombier ctlr->irq = 12;
10187dd7cddfSDavid du Colombier break;
10197dd7cddfSDavid du Colombier case 0x04:
10207dd7cddfSDavid du Colombier ctlr->irq = 11;
10217dd7cddfSDavid du Colombier break;
10227dd7cddfSDavid du Colombier case 0x02:
10237dd7cddfSDavid du Colombier ctlr->irq = 10;
10247dd7cddfSDavid du Colombier break;
10257dd7cddfSDavid du Colombier case 0x01:
10267dd7cddfSDavid du Colombier ctlr->irq = 9;
10277dd7cddfSDavid du Colombier break;
10287dd7cddfSDavid du Colombier default:
10297dd7cddfSDavid du Colombier goto buggery;
10307dd7cddfSDavid du Colombier }
10317dd7cddfSDavid du Colombier }
10327dd7cddfSDavid du Colombier
10337dd7cddfSDavid du Colombier if((sdev = malloc(sizeof(SDev))) == nil)
10347dd7cddfSDavid du Colombier goto buggery;
10357dd7cddfSDavid du Colombier sdev->ifc = &sdmylexifc;
10367dd7cddfSDavid du Colombier sdev->ctlr = ctlr;
10374de34a7eSDavid du Colombier sdev->idno = '0';
10387dd7cddfSDavid du Colombier ctlr->sdev = sdev;
10397dd7cddfSDavid du Colombier if(!ctlr->wide)
10407dd7cddfSDavid du Colombier sdev->nunit = 8;
10417dd7cddfSDavid du Colombier else
10427dd7cddfSDavid du Colombier sdev->nunit = 16;
10437dd7cddfSDavid du Colombier
10447dd7cddfSDavid du Colombier return sdev;
10457dd7cddfSDavid du Colombier }
10467dd7cddfSDavid du Colombier
10477dd7cddfSDavid du Colombier static int mylexport[8] = {
10487dd7cddfSDavid du Colombier 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0x000, 0x000,
10497dd7cddfSDavid du Colombier };
10507dd7cddfSDavid du Colombier
10517dd7cddfSDavid du Colombier static SDev*
mylexpnp(void)10527dd7cddfSDavid du Colombier mylexpnp(void)
10537dd7cddfSDavid du Colombier {
10547dd7cddfSDavid du Colombier Pcidev *p;
10557dd7cddfSDavid du Colombier Ctlr *ctlr;
105659cc4ca5SDavid du Colombier ISAConf isa;
105759cc4ca5SDavid du Colombier int cfg, ctlrno, i, x;
10587dd7cddfSDavid du Colombier SDev *sdev, *head, *tail;
10597dd7cddfSDavid du Colombier
10607dd7cddfSDavid du Colombier p = nil;
10617dd7cddfSDavid du Colombier head = tail = nil;
10627dd7cddfSDavid du Colombier while(p = pcimatch(p, 0x104B, 0)){
10637dd7cddfSDavid du Colombier if((sdev = mylexprobe(p->mem[0].bar & ~0x01, p->intl)) == nil)
10647dd7cddfSDavid du Colombier continue;
10657dd7cddfSDavid du Colombier
10667dd7cddfSDavid du Colombier ctlr = sdev->ctlr;
10677dd7cddfSDavid du Colombier ctlr->pcidev = p;
10687dd7cddfSDavid du Colombier
10697dd7cddfSDavid du Colombier if(head != nil)
10707dd7cddfSDavid du Colombier tail->next = sdev;
10717dd7cddfSDavid du Colombier else
10727dd7cddfSDavid du Colombier head = sdev;
10737dd7cddfSDavid du Colombier tail = sdev;
10747dd7cddfSDavid du Colombier }
10757dd7cddfSDavid du Colombier
107659cc4ca5SDavid du Colombier if(strncmp(KADDR(0xFFFD9), "EISA", 4) == 0){
10777dd7cddfSDavid du Colombier for(cfg = 0x1000; cfg < MaxEISA*0x1000; cfg += 0x1000){
10787dd7cddfSDavid du Colombier x = 0;
10797dd7cddfSDavid du Colombier for(i = 0; i < 4; i++)
10807dd7cddfSDavid du Colombier x |= inb(cfg+CfgEISA+i)<<(i*8);
10817dd7cddfSDavid du Colombier if(x != 0x0142B30A && x != 0x0242B30A)
10827dd7cddfSDavid du Colombier continue;
10837dd7cddfSDavid du Colombier
10847dd7cddfSDavid du Colombier x = inb(cfg+0xC8C);
10857dd7cddfSDavid du Colombier if((sdev = mylexprobe(mylexport[x & 0x07], -1)) == nil)
10867dd7cddfSDavid du Colombier continue;
10877dd7cddfSDavid du Colombier
10887dd7cddfSDavid du Colombier if(head != nil)
10897dd7cddfSDavid du Colombier tail->next = sdev;
10907dd7cddfSDavid du Colombier else
10917dd7cddfSDavid du Colombier head = sdev;
10927dd7cddfSDavid du Colombier tail = sdev;
10937dd7cddfSDavid du Colombier }
109459cc4ca5SDavid du Colombier }
109559cc4ca5SDavid du Colombier
109659cc4ca5SDavid du Colombier for(ctlrno = 0; ctlrno < 4; ctlrno++){
109759cc4ca5SDavid du Colombier memset(&isa, 0, sizeof(isa));
109859cc4ca5SDavid du Colombier if(!isaconfig("scsi", ctlrno, &isa))
109959cc4ca5SDavid du Colombier continue;
110059cc4ca5SDavid du Colombier if(strcmp(isa.type, "aha1542"))
110159cc4ca5SDavid du Colombier continue;
110259cc4ca5SDavid du Colombier if((sdev = mylexprobe(isa.port, -1)) == nil)
110359cc4ca5SDavid du Colombier continue;
110459cc4ca5SDavid du Colombier
110559cc4ca5SDavid du Colombier if(head != nil)
110659cc4ca5SDavid du Colombier tail->next = sdev;
110759cc4ca5SDavid du Colombier else
110859cc4ca5SDavid du Colombier head = sdev;
110959cc4ca5SDavid du Colombier tail = sdev;
111059cc4ca5SDavid du Colombier }
11117dd7cddfSDavid du Colombier
11127dd7cddfSDavid du Colombier return head;
11137dd7cddfSDavid du Colombier }
11147dd7cddfSDavid du Colombier
11157dd7cddfSDavid du Colombier static int
mylex24enable(Ctlr * ctlr)11167dd7cddfSDavid du Colombier mylex24enable(Ctlr* ctlr)
11177dd7cddfSDavid du Colombier {
11187dd7cddfSDavid du Colombier ulong p;
11197dd7cddfSDavid du Colombier Ccb24 *ccb, *ccbp;
11207dd7cddfSDavid du Colombier uchar cmd[6], *v;
11217dd7cddfSDavid du Colombier int len;
11227dd7cddfSDavid du Colombier
11237dd7cddfSDavid du Colombier len = (sizeof(Mbox24)*NMbox*2)+(sizeof(Ccb24)*NCcb);
11247dd7cddfSDavid du Colombier v = xspanalloc(len, 32, 0);
11257dd7cddfSDavid du Colombier
11267dd7cddfSDavid du Colombier if(!PADDR24(ctlr, sizeof(Ctlr)) || !PADDR24(v, len))
11277dd7cddfSDavid du Colombier return 0;
11287dd7cddfSDavid du Colombier
11297dd7cddfSDavid du Colombier ctlr->mb = v;
11307dd7cddfSDavid du Colombier v += sizeof(Mbox24)*NMbox*2;
11317dd7cddfSDavid du Colombier
11327dd7cddfSDavid du Colombier ccb = (Ccb24*)v;
11337dd7cddfSDavid du Colombier for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
11347dd7cddfSDavid du Colombier ccbp->ccb = ctlr->ccb;
11357dd7cddfSDavid du Colombier ctlr->ccb = (Ccb*)ccbp;
11367dd7cddfSDavid du Colombier }
11377dd7cddfSDavid du Colombier
11387dd7cddfSDavid du Colombier /*
11397dd7cddfSDavid du Colombier * Initialise the software controller and
11407dd7cddfSDavid du Colombier * set the board scanning the mailboxes.
11417dd7cddfSDavid du Colombier */
11427dd7cddfSDavid du Colombier ctlr->mbix = NMbox;
11437dd7cddfSDavid du Colombier
11447dd7cddfSDavid du Colombier cmd[0] = Cinitialise;
11457dd7cddfSDavid du Colombier cmd[1] = NMbox;
11467dd7cddfSDavid du Colombier p = K2BPA(ctlr->mb, BUSUNKNOWN);
11477dd7cddfSDavid du Colombier cmd[2] = p>>16;
11487dd7cddfSDavid du Colombier cmd[3] = p>>8;
11497dd7cddfSDavid du Colombier cmd[4] = p;
11507dd7cddfSDavid du Colombier
115159cc4ca5SDavid du Colombier return issue(ctlr, cmd, 5, 0, 0);
11527dd7cddfSDavid du Colombier }
11537dd7cddfSDavid du Colombier
11547dd7cddfSDavid du Colombier static int
mylex32enable(Ctlr * ctlr)11557dd7cddfSDavid du Colombier mylex32enable(Ctlr* ctlr)
11567dd7cddfSDavid du Colombier {
11577dd7cddfSDavid du Colombier ulong p;
11587dd7cddfSDavid du Colombier Ccb32 *ccb, *ccbp;
11597dd7cddfSDavid du Colombier uchar cmd[6], *v;
11607dd7cddfSDavid du Colombier
11617dd7cddfSDavid du Colombier v = xspanalloc((sizeof(Mbox32)*NMbox*2)+(sizeof(Ccb32)*NCcb), 32, 0);
11627dd7cddfSDavid du Colombier
11637dd7cddfSDavid du Colombier ctlr->mb = v;
11647dd7cddfSDavid du Colombier v += sizeof(Mbox32)*NMbox*2;
11657dd7cddfSDavid du Colombier
11667dd7cddfSDavid du Colombier ccb = (Ccb32*)v;
11677dd7cddfSDavid du Colombier for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
11687dd7cddfSDavid du Colombier /*
11697dd7cddfSDavid du Colombier * Fill in some stuff that doesn't change.
11707dd7cddfSDavid du Colombier */
11717dd7cddfSDavid du Colombier ccbp->senselen = sizeof(ccbp->sense);
11727dd7cddfSDavid du Colombier p = PADDR(ccbp->sense);
11737dd7cddfSDavid du Colombier ccbp->senseptr[0] = p;
11747dd7cddfSDavid du Colombier ccbp->senseptr[1] = p>>8;
11757dd7cddfSDavid du Colombier ccbp->senseptr[2] = p>>16;
11767dd7cddfSDavid du Colombier ccbp->senseptr[3] = p>>24;
11777dd7cddfSDavid du Colombier
11787dd7cddfSDavid du Colombier ccbp->ccb = ctlr->ccb;
11797dd7cddfSDavid du Colombier ctlr->ccb = (Ccb*)ccbp;
11807dd7cddfSDavid du Colombier }
11817dd7cddfSDavid du Colombier
11827dd7cddfSDavid du Colombier /*
11837dd7cddfSDavid du Colombier * Attempt wide mode setup.
11847dd7cddfSDavid du Colombier */
11857dd7cddfSDavid du Colombier if(ctlr->wide){
11867dd7cddfSDavid du Colombier cmd[0] = Cwide;
11877dd7cddfSDavid du Colombier cmd[1] = 1;
11886bfdd830SDavid du Colombier if(!issue(ctlr, cmd, 2, 0, 0)) {
11897dd7cddfSDavid du Colombier ctlr->wide = 0;
1190*fececb92SDavid du Colombier print("mylex32enable: port 0x%ux: scsi wide-mode setup "
1191*fececb92SDavid du Colombier "failed on wide host adapter", ctlr->port);
11926bfdd830SDavid du Colombier }
11937dd7cddfSDavid du Colombier }
11947dd7cddfSDavid du Colombier
11957dd7cddfSDavid du Colombier /*
11967dd7cddfSDavid du Colombier * Initialise the software controller and
11977dd7cddfSDavid du Colombier * set the board scanning the mailboxes.
11987dd7cddfSDavid du Colombier */
11997dd7cddfSDavid du Colombier ctlr->mbix = NMbox;
12007dd7cddfSDavid du Colombier
12017dd7cddfSDavid du Colombier cmd[0] = Ciem;
12027dd7cddfSDavid du Colombier cmd[1] = NMbox;
12037dd7cddfSDavid du Colombier if(ctlr->pcidev)
12047dd7cddfSDavid du Colombier p = K2BPA(ctlr->mb, ctlr->tbdf);
12057dd7cddfSDavid du Colombier else
12067dd7cddfSDavid du Colombier p = K2BPA(ctlr->mb, BUSUNKNOWN);
12077dd7cddfSDavid du Colombier cmd[2] = p;
12087dd7cddfSDavid du Colombier cmd[3] = p>>8;
12097dd7cddfSDavid du Colombier cmd[4] = p>>16;
12107dd7cddfSDavid du Colombier cmd[5] = p>>24;
12117dd7cddfSDavid du Colombier
12127dd7cddfSDavid du Colombier return issue(ctlr, cmd, 6, 0, 0);
12137dd7cddfSDavid du Colombier }
12147dd7cddfSDavid du Colombier
12157dd7cddfSDavid du Colombier static int
mylexenable(SDev * sdev)12167dd7cddfSDavid du Colombier mylexenable(SDev* sdev)
12177dd7cddfSDavid du Colombier {
12187dd7cddfSDavid du Colombier int tbdf;
12197dd7cddfSDavid du Colombier Ctlr *ctlr;
12207dd7cddfSDavid du Colombier void (*interrupt)(Ureg*, void*);
12219a747e4fSDavid du Colombier char name[32];
12227dd7cddfSDavid du Colombier
12237dd7cddfSDavid du Colombier ctlr = sdev->ctlr;
12247dd7cddfSDavid du Colombier if(ctlr->cache == nil){
12257dd7cddfSDavid du Colombier if((ctlr->cache = malloc(sdev->nunit*sizeof(Ccb*))) == nil)
12267dd7cddfSDavid du Colombier return 0;
12277dd7cddfSDavid du Colombier }
12287dd7cddfSDavid du Colombier
12297dd7cddfSDavid du Colombier tbdf = BUSUNKNOWN;
12307dd7cddfSDavid du Colombier if(ctlr->bus == 32){
12317dd7cddfSDavid du Colombier if(ctlr->pcidev){
12327dd7cddfSDavid du Colombier tbdf = ctlr->pcidev->tbdf;
12337dd7cddfSDavid du Colombier pcisetbme(ctlr->pcidev);
12347dd7cddfSDavid du Colombier }
12357dd7cddfSDavid du Colombier if(!mylex32enable(ctlr))
12367dd7cddfSDavid du Colombier return 0;
12377dd7cddfSDavid du Colombier interrupt = mylex32interrupt;
12387dd7cddfSDavid du Colombier }
12397dd7cddfSDavid du Colombier else if(mylex24enable(ctlr))
12407dd7cddfSDavid du Colombier interrupt = mylex24interrupt;
12417dd7cddfSDavid du Colombier else
12427dd7cddfSDavid du Colombier return 0;
12437dd7cddfSDavid du Colombier
12449a747e4fSDavid du Colombier snprint(name, sizeof(name), "sd%c (%s)", sdev->idno, sdev->ifc->name);
12457dd7cddfSDavid du Colombier intrenable(ctlr->irq, interrupt, ctlr, tbdf, name);
12467dd7cddfSDavid du Colombier
12477dd7cddfSDavid du Colombier return 1;
12487dd7cddfSDavid du Colombier }
12497dd7cddfSDavid du Colombier
12507dd7cddfSDavid du Colombier SDifc sdmylexifc = {
12517dd7cddfSDavid du Colombier "mylex", /* name */
12527dd7cddfSDavid du Colombier
12537dd7cddfSDavid du Colombier mylexpnp, /* pnp */
12547dd7cddfSDavid du Colombier nil, /* legacy */
12557dd7cddfSDavid du Colombier mylexenable, /* enable */
12567dd7cddfSDavid du Colombier nil, /* disable */
12577dd7cddfSDavid du Colombier
12587dd7cddfSDavid du Colombier scsiverify, /* verify */
12597dd7cddfSDavid du Colombier scsionline, /* online */
12607dd7cddfSDavid du Colombier mylexrio, /* rio */
12617dd7cddfSDavid du Colombier nil, /* rctl */
12627dd7cddfSDavid du Colombier nil, /* wctl */
12637dd7cddfSDavid du Colombier
12647dd7cddfSDavid du Colombier scsibio, /* bio */
12659a747e4fSDavid du Colombier nil, /* probe */
12669a747e4fSDavid du Colombier nil, /* clear */
1267d649fdd7SDavid du Colombier nil, /* rtopctl */
1268d649fdd7SDavid du Colombier nil, /* wtopctl */
12697dd7cddfSDavid du Colombier };
1270