174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth * Mylex MultiMaster (Buslogic BT-*) SCSI Host Adapter
374a4d8c2SCharles.Forsyth * in both 24-bit and 32-bit mode.
474a4d8c2SCharles.Forsyth * 24-bit mode works for Adaptec AHA-154xx series too.
574a4d8c2SCharles.Forsyth *
674a4d8c2SCharles.Forsyth * To do:
774a4d8c2SCharles.Forsyth * allocate more Ccb's as needed, up to NMbox-1;
874a4d8c2SCharles.Forsyth * add nmbox and nccb to Ctlr struct for the above;
974a4d8c2SCharles.Forsyth * 64-bit LUN/explicit wide support necessary?
1074a4d8c2SCharles.Forsyth *
1174a4d8c2SCharles.Forsyth */
1274a4d8c2SCharles.Forsyth #include "u.h"
1374a4d8c2SCharles.Forsyth #include "lib.h"
1474a4d8c2SCharles.Forsyth #include "mem.h"
1574a4d8c2SCharles.Forsyth #include "dat.h"
1674a4d8c2SCharles.Forsyth #include "fns.h"
1774a4d8c2SCharles.Forsyth #include "io.h"
1874a4d8c2SCharles.Forsyth #include "ureg.h"
1974a4d8c2SCharles.Forsyth #include "error.h"
2074a4d8c2SCharles.Forsyth
2174a4d8c2SCharles.Forsyth #include "sd.h"
2274a4d8c2SCharles.Forsyth
2374a4d8c2SCharles.Forsyth #define waserror() (0)
2474a4d8c2SCharles.Forsyth #define poperror()
2574a4d8c2SCharles.Forsyth typedef struct QLock{ int r; } QLock;
2674a4d8c2SCharles.Forsyth typedef struct Rendez{ int r; } Rendez;
2774a4d8c2SCharles.Forsyth #define intrenable(irq, f, c, tbdf, name) setvec(VectorPIC+(irq), f, c);\
2874a4d8c2SCharles.Forsyth USED(tbdf);
2974a4d8c2SCharles.Forsyth
3074a4d8c2SCharles.Forsyth #define K2BPA(va, tbdf) PADDR(va)
3174a4d8c2SCharles.Forsyth #define BPA2K(pa, tbdf) KADDR(pa)
3274a4d8c2SCharles.Forsyth
3374a4d8c2SCharles.Forsyth extern SDifc sdmylexifc;
3474a4d8c2SCharles.Forsyth
3574a4d8c2SCharles.Forsyth enum { /* registers */
3674a4d8c2SCharles.Forsyth Rcontrol = 0x00, /* WO: control register */
3774a4d8c2SCharles.Forsyth Rstatus = 0x00, /* RO: status register */
3874a4d8c2SCharles.Forsyth Rcpr = 0x01, /* WO: command/parameter register */
3974a4d8c2SCharles.Forsyth Rdatain = 0x01, /* RO: data-in register */
4074a4d8c2SCharles.Forsyth Rinterrupt = 0x02, /* RO: interrupt register */
4174a4d8c2SCharles.Forsyth };
4274a4d8c2SCharles.Forsyth
4374a4d8c2SCharles.Forsyth enum { /* Rcontrol */
4474a4d8c2SCharles.Forsyth Rsbus = 0x10, /* SCSI Bus Reset */
4574a4d8c2SCharles.Forsyth Rint = 0x20, /* Interrupt Reset */
4674a4d8c2SCharles.Forsyth Rsoft = 0x40, /* Soft Reset */
4774a4d8c2SCharles.Forsyth Rhard = 0x80, /* Hard Reset */
4874a4d8c2SCharles.Forsyth };
4974a4d8c2SCharles.Forsyth
5074a4d8c2SCharles.Forsyth enum { /* Rstatus */
5174a4d8c2SCharles.Forsyth Cmdinv = 0x01, /* Command Invalid */
5274a4d8c2SCharles.Forsyth Dirrdy = 0x04, /* Data In Register Ready */
5374a4d8c2SCharles.Forsyth Cprbsy = 0x08, /* Command/Parameter Register Busy */
5474a4d8c2SCharles.Forsyth Hardy = 0x10, /* Host Adapter Ready */
5574a4d8c2SCharles.Forsyth Inreq = 0x20, /* Initialisation Required */
5674a4d8c2SCharles.Forsyth Dfail = 0x40, /* Diagnostic Failure */
5774a4d8c2SCharles.Forsyth Dact = 0x80, /* Diagnostic Active */
5874a4d8c2SCharles.Forsyth };
5974a4d8c2SCharles.Forsyth
6074a4d8c2SCharles.Forsyth enum { /* Rcpr */
6174a4d8c2SCharles.Forsyth Cinitialise = 0x01, /* Initialise Mailbox */
6274a4d8c2SCharles.Forsyth Cstart = 0x02, /* Start Mailbox Command */
6374a4d8c2SCharles.Forsyth Cinquiry = 0x04, /* Adapter Inquiry */
6474a4d8c2SCharles.Forsyth Ceombri = 0x05, /* Enable OMBR Interrupt */
6574a4d8c2SCharles.Forsyth Cinquire = 0x0B, /* Inquire Configuration */
6674a4d8c2SCharles.Forsyth Cextbios = 0x28, /* AHA-1542: extended BIOS info. */
6774a4d8c2SCharles.Forsyth Cmbienable = 0x29, /* AHA-1542: Mailbox interface enable */
6874a4d8c2SCharles.Forsyth Ciem = 0x81, /* Initialise Extended Mailbox */
6974a4d8c2SCharles.Forsyth Ciesi = 0x8D, /* Inquire Extended Setup Information */
7074a4d8c2SCharles.Forsyth Cerrm = 0x8F, /* Enable strict round-robin mode */
7174a4d8c2SCharles.Forsyth Cwide = 0x96, /* Wide CCB */
7274a4d8c2SCharles.Forsyth };
7374a4d8c2SCharles.Forsyth
7474a4d8c2SCharles.Forsyth enum { /* Rinterrupt */
7574a4d8c2SCharles.Forsyth Imbl = 0x01, /* Incoming Mailbox Loaded */
7674a4d8c2SCharles.Forsyth Mbor = 0x02, /* Mailbox Out Ready */
7774a4d8c2SCharles.Forsyth Cmdc = 0x04, /* Command Complete */
7874a4d8c2SCharles.Forsyth Rsts = 0x08, /* SCSI Reset State */
7974a4d8c2SCharles.Forsyth Intv = 0x80, /* Interrupt Valid */
8074a4d8c2SCharles.Forsyth };
8174a4d8c2SCharles.Forsyth
8274a4d8c2SCharles.Forsyth typedef struct {
8374a4d8c2SCharles.Forsyth uchar code; /* action/completion code */
8474a4d8c2SCharles.Forsyth uchar ccb[3]; /* CCB pointer (MSB, ..., LSB) */
8574a4d8c2SCharles.Forsyth } Mbox24;
8674a4d8c2SCharles.Forsyth
8774a4d8c2SCharles.Forsyth typedef struct {
8874a4d8c2SCharles.Forsyth uchar ccb[4]; /* CCB pointer (LSB, ..., MSB) */
8974a4d8c2SCharles.Forsyth uchar btstat; /* BT-7[45]7[SD] status */
9074a4d8c2SCharles.Forsyth uchar sdstat; /* SCSI device status */
9174a4d8c2SCharles.Forsyth uchar pad;
9274a4d8c2SCharles.Forsyth uchar code; /* action/completion code */
9374a4d8c2SCharles.Forsyth } Mbox32;
9474a4d8c2SCharles.Forsyth
9574a4d8c2SCharles.Forsyth enum { /* mailbox commands */
9674a4d8c2SCharles.Forsyth Mbfree = 0x00, /* Mailbox not in use */
9774a4d8c2SCharles.Forsyth
9874a4d8c2SCharles.Forsyth Mbostart = 0x01, /* Start a mailbox command */
9974a4d8c2SCharles.Forsyth Mboabort = 0x02, /* Abort a mailbox command */
10074a4d8c2SCharles.Forsyth
10174a4d8c2SCharles.Forsyth Mbiok = 0x01, /* CCB completed without error */
10274a4d8c2SCharles.Forsyth Mbiabort = 0x02, /* CCB aborted at request of host */
10374a4d8c2SCharles.Forsyth Mbinx = 0x03, /* Aborted CCB not found */
10474a4d8c2SCharles.Forsyth Mbierror = 0x04, /* CCB completed with error */
10574a4d8c2SCharles.Forsyth };
10674a4d8c2SCharles.Forsyth
10774a4d8c2SCharles.Forsyth typedef struct Ccb24 Ccb24;
10874a4d8c2SCharles.Forsyth typedef struct Ccb32 Ccb32;
10974a4d8c2SCharles.Forsyth typedef union Ccb Ccb;
11074a4d8c2SCharles.Forsyth
11174a4d8c2SCharles.Forsyth typedef struct Ccb24 {
11274a4d8c2SCharles.Forsyth uchar opcode; /* Operation code */
11374a4d8c2SCharles.Forsyth uchar datadir; /* Data direction control */
11474a4d8c2SCharles.Forsyth uchar cdblen; /* Length of CDB */
11574a4d8c2SCharles.Forsyth uchar senselen; /* Length of sense area */
11674a4d8c2SCharles.Forsyth uchar datalen[3]; /* Data length (MSB, ..., LSB) */
11774a4d8c2SCharles.Forsyth uchar dataptr[3]; /* Data pointer (MSB, ..., LSB) */
11874a4d8c2SCharles.Forsyth uchar linkptr[3]; /* Link pointer (MSB, ..., LSB) */
11974a4d8c2SCharles.Forsyth uchar linkid; /* command linking identifier */
12074a4d8c2SCharles.Forsyth uchar btstat; /* BT-* adapter status */
12174a4d8c2SCharles.Forsyth uchar sdstat; /* SCSI device status */
12274a4d8c2SCharles.Forsyth uchar reserved[2]; /* */
12374a4d8c2SCharles.Forsyth uchar cs[12+0xFF]; /* Command descriptor block + Sense */
12474a4d8c2SCharles.Forsyth
12574a4d8c2SCharles.Forsyth void* data; /* buffer if address > 24-bits */
12674a4d8c2SCharles.Forsyth
12774a4d8c2SCharles.Forsyth Rendez;
12874a4d8c2SCharles.Forsyth int done; /* command completed */
12974a4d8c2SCharles.Forsyth
13074a4d8c2SCharles.Forsyth Ccb* ccb; /* link on free list */
13174a4d8c2SCharles.Forsyth } Ccb24;
13274a4d8c2SCharles.Forsyth
13374a4d8c2SCharles.Forsyth
13474a4d8c2SCharles.Forsyth typedef struct Ccb32 {
13574a4d8c2SCharles.Forsyth uchar opcode; /* Operation code */
13674a4d8c2SCharles.Forsyth uchar datadir; /* Data direction control */
13774a4d8c2SCharles.Forsyth uchar cdblen; /* Length of CDB */
13874a4d8c2SCharles.Forsyth uchar senselen; /* Length of sense area */
13974a4d8c2SCharles.Forsyth uchar datalen[4]; /* Data length (LSB, ..., MSB) */
14074a4d8c2SCharles.Forsyth uchar dataptr[4]; /* Data pointer (LSB, ..., MSB) */
14174a4d8c2SCharles.Forsyth uchar reserved[2];
14274a4d8c2SCharles.Forsyth uchar btstat; /* BT-* adapter status */
14374a4d8c2SCharles.Forsyth uchar sdstat; /* SCSI device status */
14474a4d8c2SCharles.Forsyth uchar targetid; /* Target ID */
14574a4d8c2SCharles.Forsyth uchar luntag; /* LUN & tag */
14674a4d8c2SCharles.Forsyth uchar cdb[12]; /* Command descriptor block */
14774a4d8c2SCharles.Forsyth uchar ccbctl; /* CCB control */
14874a4d8c2SCharles.Forsyth uchar linkid; /* command linking identifier */
14974a4d8c2SCharles.Forsyth uchar linkptr[4]; /* Link pointer (LSB, ..., MSB) */
15074a4d8c2SCharles.Forsyth uchar senseptr[4]; /* Sense pointer (LSB, ..., MSB) */
15174a4d8c2SCharles.Forsyth uchar sense[0xFF]; /* Sense bytes */
15274a4d8c2SCharles.Forsyth
15374a4d8c2SCharles.Forsyth Rendez;
15474a4d8c2SCharles.Forsyth int done; /* command completed */
15574a4d8c2SCharles.Forsyth
15674a4d8c2SCharles.Forsyth Ccb* ccb; /* link on free list */
15774a4d8c2SCharles.Forsyth } Ccb32;
15874a4d8c2SCharles.Forsyth
15974a4d8c2SCharles.Forsyth typedef union Ccb {
16074a4d8c2SCharles.Forsyth Ccb24;
16174a4d8c2SCharles.Forsyth Ccb32;
16274a4d8c2SCharles.Forsyth } Ccb;
16374a4d8c2SCharles.Forsyth
16474a4d8c2SCharles.Forsyth enum { /* opcode */
16574a4d8c2SCharles.Forsyth OInitiator = 0x00, /* initiator CCB */
16674a4d8c2SCharles.Forsyth Ordl = 0x03, /* initiator CCB with
16774a4d8c2SCharles.Forsyth * residual data length returned
16874a4d8c2SCharles.Forsyth */
16974a4d8c2SCharles.Forsyth };
17074a4d8c2SCharles.Forsyth
17174a4d8c2SCharles.Forsyth enum { /* datadir */
17274a4d8c2SCharles.Forsyth CCBdatain = 0x08, /* inbound, length is checked */
17374a4d8c2SCharles.Forsyth CCBdataout = 0x10, /* outbound, length is checked */
17474a4d8c2SCharles.Forsyth };
17574a4d8c2SCharles.Forsyth
17674a4d8c2SCharles.Forsyth enum { /* btstat */
17774a4d8c2SCharles.Forsyth Eok = 0x00, /* normal completion with no errors */
17874a4d8c2SCharles.Forsyth };
17974a4d8c2SCharles.Forsyth
18074a4d8c2SCharles.Forsyth enum { /* luntag */
18174a4d8c2SCharles.Forsyth TagEnable = 0x20, /* Tag enable */
18274a4d8c2SCharles.Forsyth SQTag = 0x00, /* Simple Queue Tag */
18374a4d8c2SCharles.Forsyth HQTag = 0x40, /* Head of Queue Tag */
18474a4d8c2SCharles.Forsyth OQTag = 0x80, /* Ordered Queue Tag */
18574a4d8c2SCharles.Forsyth };
18674a4d8c2SCharles.Forsyth
18774a4d8c2SCharles.Forsyth enum { /* CCB control */
18874a4d8c2SCharles.Forsyth NoDisc = 0x08, /* No disconnect */
18974a4d8c2SCharles.Forsyth NoUnd = 0x10, /* No underrrun error report */
19074a4d8c2SCharles.Forsyth NoData = 0x20, /* No data transfer */
19174a4d8c2SCharles.Forsyth NoStat = 0x40, /* No CCB status if zero */
19274a4d8c2SCharles.Forsyth NoIntr = 0x80, /* No Interrupts */
19374a4d8c2SCharles.Forsyth };
19474a4d8c2SCharles.Forsyth
19574a4d8c2SCharles.Forsyth typedef struct {
19674a4d8c2SCharles.Forsyth int port; /* I/O port */
19774a4d8c2SCharles.Forsyth int id; /* adapter SCSI id */
19874a4d8c2SCharles.Forsyth int bus; /* 24 or 32 -bit */
19974a4d8c2SCharles.Forsyth int irq;
20074a4d8c2SCharles.Forsyth int wide;
20174a4d8c2SCharles.Forsyth Pcidev* pcidev;
20274a4d8c2SCharles.Forsyth SDev* sdev;
20374a4d8c2SCharles.Forsyth int spurious;
20474a4d8c2SCharles.Forsyth
20574a4d8c2SCharles.Forsyth Lock issuelock;
20674a4d8c2SCharles.Forsyth
20774a4d8c2SCharles.Forsyth Lock ccblock;
20874a4d8c2SCharles.Forsyth QLock ccbq;
20974a4d8c2SCharles.Forsyth Rendez ccbr;
21074a4d8c2SCharles.Forsyth
21174a4d8c2SCharles.Forsyth Lock mboxlock;
21274a4d8c2SCharles.Forsyth void* mb; /* mailbox out + mailbox in */
21374a4d8c2SCharles.Forsyth int mbox; /* current mailbox out index into mb */
21474a4d8c2SCharles.Forsyth int mbix; /* current mailbox in index into mb */
21574a4d8c2SCharles.Forsyth
21674a4d8c2SCharles.Forsyth Lock cachelock;
21774a4d8c2SCharles.Forsyth Ccb* ccb; /* list of free Ccb's */
21874a4d8c2SCharles.Forsyth Ccb** cache; /* last completed Ccb */
21974a4d8c2SCharles.Forsyth } Ctlr;
22074a4d8c2SCharles.Forsyth
22174a4d8c2SCharles.Forsyth /*
22274a4d8c2SCharles.Forsyth * The number of mailboxes should be a multiple of 8 (4 for Mbox32)
22374a4d8c2SCharles.Forsyth * to ensure the boundary between the out and in mailboxes doesn't
22474a4d8c2SCharles.Forsyth * straddle a cache-line boundary.
22574a4d8c2SCharles.Forsyth * The number of Ccb's should be less than the number of mailboxes to
22674a4d8c2SCharles.Forsyth * ensure no queueing is necessary on mailbox allocation.
22774a4d8c2SCharles.Forsyth */
22874a4d8c2SCharles.Forsyth enum {
22974a4d8c2SCharles.Forsyth NMbox = 8*8, /* number of Mbox's */
23074a4d8c2SCharles.Forsyth NCcb = NMbox-1, /* number of Ccb's */
23174a4d8c2SCharles.Forsyth };
23274a4d8c2SCharles.Forsyth
23374a4d8c2SCharles.Forsyth #define PADDR24(a, n) ((PADDR(a)+(n)) <= (1<<24))
23474a4d8c2SCharles.Forsyth
23574a4d8c2SCharles.Forsyth static void
ccbfree(Ctlr * ctlr,Ccb * ccb)23674a4d8c2SCharles.Forsyth ccbfree(Ctlr* ctlr, Ccb* ccb)
23774a4d8c2SCharles.Forsyth {
23874a4d8c2SCharles.Forsyth lock(&ctlr->ccblock);
23974a4d8c2SCharles.Forsyth if(ctlr->bus == 24)
24074a4d8c2SCharles.Forsyth ((Ccb24*)ccb)->ccb = ctlr->ccb;
24174a4d8c2SCharles.Forsyth else
24274a4d8c2SCharles.Forsyth ((Ccb32*)ccb)->ccb = ctlr->ccb;
24374a4d8c2SCharles.Forsyth if(ctlr->ccb == nil)
24474a4d8c2SCharles.Forsyth wakeup(&ctlr->ccbr);
24574a4d8c2SCharles.Forsyth ctlr->ccb = ccb;
24674a4d8c2SCharles.Forsyth unlock(&ctlr->ccblock);
24774a4d8c2SCharles.Forsyth }
24874a4d8c2SCharles.Forsyth
24974a4d8c2SCharles.Forsyth static int
ccbavailable(void * a)25074a4d8c2SCharles.Forsyth ccbavailable(void* a)
25174a4d8c2SCharles.Forsyth {
25274a4d8c2SCharles.Forsyth return ((Ctlr*)a)->ccb != nil;
25374a4d8c2SCharles.Forsyth }
25474a4d8c2SCharles.Forsyth
25574a4d8c2SCharles.Forsyth static Ccb*
ccballoc(Ctlr * ctlr)25674a4d8c2SCharles.Forsyth ccballoc(Ctlr* ctlr)
25774a4d8c2SCharles.Forsyth {
25874a4d8c2SCharles.Forsyth Ccb *ccb;
25974a4d8c2SCharles.Forsyth
26074a4d8c2SCharles.Forsyth for(;;){
26174a4d8c2SCharles.Forsyth lock(&ctlr->ccblock);
26274a4d8c2SCharles.Forsyth if((ccb = ctlr->ccb) != nil){
26374a4d8c2SCharles.Forsyth if(ctlr->bus == 24)
26474a4d8c2SCharles.Forsyth ctlr->ccb = ((Ccb24*)ccb)->ccb;
26574a4d8c2SCharles.Forsyth else
26674a4d8c2SCharles.Forsyth ctlr->ccb = ((Ccb32*)ccb)->ccb;
26774a4d8c2SCharles.Forsyth unlock(&ctlr->ccblock);
26874a4d8c2SCharles.Forsyth break;
26974a4d8c2SCharles.Forsyth }
27074a4d8c2SCharles.Forsyth
27174a4d8c2SCharles.Forsyth unlock(&ctlr->ccblock);
27274a4d8c2SCharles.Forsyth qlock(&ctlr->ccbq);
27374a4d8c2SCharles.Forsyth if(waserror()){
27474a4d8c2SCharles.Forsyth qunlock(&ctlr->ccbq);
27574a4d8c2SCharles.Forsyth continue;
27674a4d8c2SCharles.Forsyth }
27774a4d8c2SCharles.Forsyth sleep(&ctlr->ccbr, ccbavailable, ctlr);
27874a4d8c2SCharles.Forsyth qunlock(&ctlr->ccbq);
27974a4d8c2SCharles.Forsyth poperror();
28074a4d8c2SCharles.Forsyth }
28174a4d8c2SCharles.Forsyth
28274a4d8c2SCharles.Forsyth return ccb;
28374a4d8c2SCharles.Forsyth }
28474a4d8c2SCharles.Forsyth
28574a4d8c2SCharles.Forsyth static int
done24(void * arg)28674a4d8c2SCharles.Forsyth done24(void* arg)
28774a4d8c2SCharles.Forsyth {
28874a4d8c2SCharles.Forsyth return ((Ccb24*)arg)->done;
28974a4d8c2SCharles.Forsyth }
29074a4d8c2SCharles.Forsyth
29174a4d8c2SCharles.Forsyth static int
mylex24rio(SDreq * r)29274a4d8c2SCharles.Forsyth mylex24rio(SDreq* r)
29374a4d8c2SCharles.Forsyth {
29474a4d8c2SCharles.Forsyth ulong p;
29574a4d8c2SCharles.Forsyth Ctlr *ctlr;
29674a4d8c2SCharles.Forsyth Ccb24 *ccb;
29774a4d8c2SCharles.Forsyth Mbox24 *mb;
29874a4d8c2SCharles.Forsyth uchar *data, lun, *sense;
29974a4d8c2SCharles.Forsyth int d, n, btstat, sdstat, target;
30074a4d8c2SCharles.Forsyth
30174a4d8c2SCharles.Forsyth ctlr = r->unit->dev->ctlr;
30274a4d8c2SCharles.Forsyth target = r->unit->subno;
30374a4d8c2SCharles.Forsyth lun = (r->cmd[1]>>5) & 0x07;
30474a4d8c2SCharles.Forsyth
30574a4d8c2SCharles.Forsyth /*
30674a4d8c2SCharles.Forsyth * Ctlr->cache holds the last completed Ccb for this target if it
30774a4d8c2SCharles.Forsyth * returned 'check condition'.
30874a4d8c2SCharles.Forsyth * If this command is a request-sense and there is valid sense data
30974a4d8c2SCharles.Forsyth * from the last completed Ccb, return it immediately.
31074a4d8c2SCharles.Forsyth */
31174a4d8c2SCharles.Forsyth lock(&ctlr->cachelock);
31274a4d8c2SCharles.Forsyth if((ccb = ctlr->cache[target]) != nil){
31374a4d8c2SCharles.Forsyth ctlr->cache[target] = nil;
31474a4d8c2SCharles.Forsyth if(r->cmd[0] == 0x03
31574a4d8c2SCharles.Forsyth && ccb->sdstat == SDcheck && lun == ((ccb->cs[1]>>5) & 0x07)){
31674a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
31774a4d8c2SCharles.Forsyth if(r->dlen){
31874a4d8c2SCharles.Forsyth sense = &ccb->cs[ccb->cdblen];
31974a4d8c2SCharles.Forsyth n = 8+sense[7];
32074a4d8c2SCharles.Forsyth if(n > r->dlen)
32174a4d8c2SCharles.Forsyth n = r->dlen;
32274a4d8c2SCharles.Forsyth memmove(r->data, sense, n);
32374a4d8c2SCharles.Forsyth r->rlen = n;
32474a4d8c2SCharles.Forsyth }
32574a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
32674a4d8c2SCharles.Forsyth return SDok;
32774a4d8c2SCharles.Forsyth }
32874a4d8c2SCharles.Forsyth }
32974a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
33074a4d8c2SCharles.Forsyth if(ccb == nil)
33174a4d8c2SCharles.Forsyth ccb = ccballoc(ctlr);
33274a4d8c2SCharles.Forsyth
33374a4d8c2SCharles.Forsyth /*
33474a4d8c2SCharles.Forsyth * Check if the transfer is to memory above the 24-bit limit the
33574a4d8c2SCharles.Forsyth * controller can address. If it is, try to allocate a temporary
33674a4d8c2SCharles.Forsyth * buffer as a staging area.
33774a4d8c2SCharles.Forsyth */
33874a4d8c2SCharles.Forsyth n = r->dlen;
33974a4d8c2SCharles.Forsyth if(n && !PADDR24(r->data, n)){
34074a4d8c2SCharles.Forsyth data = mallocz(n, 0);
34174a4d8c2SCharles.Forsyth if(data == nil || !PADDR24(data, n)){
34274a4d8c2SCharles.Forsyth if(data != nil){
34374a4d8c2SCharles.Forsyth free(data);
34474a4d8c2SCharles.Forsyth ccb->data = nil;
34574a4d8c2SCharles.Forsyth }
34674a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
34774a4d8c2SCharles.Forsyth return SDmalloc;
34874a4d8c2SCharles.Forsyth }
34974a4d8c2SCharles.Forsyth if(r->write)
35074a4d8c2SCharles.Forsyth memmove(data, r->data, n);
35174a4d8c2SCharles.Forsyth ccb->data = r->data;
35274a4d8c2SCharles.Forsyth }
35374a4d8c2SCharles.Forsyth else
35474a4d8c2SCharles.Forsyth data = r->data;
35574a4d8c2SCharles.Forsyth
35674a4d8c2SCharles.Forsyth /*
35774a4d8c2SCharles.Forsyth * Fill in the ccb.
35874a4d8c2SCharles.Forsyth */
35974a4d8c2SCharles.Forsyth ccb->opcode = Ordl;
36074a4d8c2SCharles.Forsyth
36174a4d8c2SCharles.Forsyth ccb->datadir = (target<<5)|lun;
36274a4d8c2SCharles.Forsyth if(n == 0)
36374a4d8c2SCharles.Forsyth ccb->datadir |= CCBdataout|CCBdatain;
36474a4d8c2SCharles.Forsyth else if(!r->write)
36574a4d8c2SCharles.Forsyth ccb->datadir |= CCBdatain;
36674a4d8c2SCharles.Forsyth else
36774a4d8c2SCharles.Forsyth ccb->datadir |= CCBdataout;
36874a4d8c2SCharles.Forsyth
36974a4d8c2SCharles.Forsyth ccb->cdblen = r->clen;
37074a4d8c2SCharles.Forsyth ccb->senselen = 0xFF;
37174a4d8c2SCharles.Forsyth
37274a4d8c2SCharles.Forsyth ccb->datalen[0] = n>>16;
37374a4d8c2SCharles.Forsyth ccb->datalen[1] = n>>8;
37474a4d8c2SCharles.Forsyth ccb->datalen[2] = n;
37574a4d8c2SCharles.Forsyth p = PADDR(data);
37674a4d8c2SCharles.Forsyth ccb->dataptr[0] = p>>16;
37774a4d8c2SCharles.Forsyth ccb->dataptr[1] = p>>8;
37874a4d8c2SCharles.Forsyth ccb->dataptr[2] = p;
37974a4d8c2SCharles.Forsyth
38074a4d8c2SCharles.Forsyth ccb->linkptr[0] = ccb->linkptr[1] = ccb->linkptr[2] = 0;
38174a4d8c2SCharles.Forsyth ccb->linkid = 0;
38274a4d8c2SCharles.Forsyth ccb->btstat = ccb->sdstat = 0;
38374a4d8c2SCharles.Forsyth ccb->reserved[0] = ccb->reserved[1] = 0;
38474a4d8c2SCharles.Forsyth
38574a4d8c2SCharles.Forsyth memmove(ccb->cs, r->cmd, r->clen);
38674a4d8c2SCharles.Forsyth
38774a4d8c2SCharles.Forsyth /*
38874a4d8c2SCharles.Forsyth * There's one more mbox than there there is
38974a4d8c2SCharles.Forsyth * ccb so there is always one free.
39074a4d8c2SCharles.Forsyth */
39174a4d8c2SCharles.Forsyth lock(&ctlr->mboxlock);
39274a4d8c2SCharles.Forsyth mb = ctlr->mb;
39374a4d8c2SCharles.Forsyth mb += ctlr->mbox;
39474a4d8c2SCharles.Forsyth p = PADDR(ccb);
39574a4d8c2SCharles.Forsyth mb->ccb[0] = p>>16;
39674a4d8c2SCharles.Forsyth mb->ccb[1] = p>>8;
39774a4d8c2SCharles.Forsyth mb->ccb[2] = p;
39874a4d8c2SCharles.Forsyth mb->code = Mbostart;
39974a4d8c2SCharles.Forsyth ctlr->mbox++;
40074a4d8c2SCharles.Forsyth if(ctlr->mbox >= NMbox)
40174a4d8c2SCharles.Forsyth ctlr->mbox = 0;
40274a4d8c2SCharles.Forsyth
40374a4d8c2SCharles.Forsyth /*
40474a4d8c2SCharles.Forsyth * This command does not require Hardy
40574a4d8c2SCharles.Forsyth * and doesn't generate a Cmdc interrupt.
40674a4d8c2SCharles.Forsyth */
40774a4d8c2SCharles.Forsyth ccb->done = 0;
40874a4d8c2SCharles.Forsyth outb(ctlr->port+Rcpr, Cstart);
40974a4d8c2SCharles.Forsyth unlock(&ctlr->mboxlock);
41074a4d8c2SCharles.Forsyth
41174a4d8c2SCharles.Forsyth /*
41274a4d8c2SCharles.Forsyth * Wait for the request to complete and return the status.
41374a4d8c2SCharles.Forsyth * Since the buffer is not reference counted cannot return
41474a4d8c2SCharles.Forsyth * until the DMA is done writing into the buffer so the caller
41574a4d8c2SCharles.Forsyth * cannot free the buffer prematurely.
41674a4d8c2SCharles.Forsyth */
41774a4d8c2SCharles.Forsyth while(waserror())
41874a4d8c2SCharles.Forsyth ;
41974a4d8c2SCharles.Forsyth tsleep(ccb, done24, ccb, 30*1000);
42074a4d8c2SCharles.Forsyth poperror();
42174a4d8c2SCharles.Forsyth
42274a4d8c2SCharles.Forsyth if(!done24(ccb)){
42374a4d8c2SCharles.Forsyth print("%s: %d/%d: sd24rio timeout\n",
42474a4d8c2SCharles.Forsyth "sdmylex"/*ctlr->sdev->name*/, target, r->lun);
42574a4d8c2SCharles.Forsyth if(ccb->data != nil){
42674a4d8c2SCharles.Forsyth free(data);
42774a4d8c2SCharles.Forsyth ccb->data = nil;
42874a4d8c2SCharles.Forsyth }
42974a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
43074a4d8c2SCharles.Forsyth
43174a4d8c2SCharles.Forsyth return SDtimeout;
43274a4d8c2SCharles.Forsyth }
43374a4d8c2SCharles.Forsyth
43474a4d8c2SCharles.Forsyth /*
43574a4d8c2SCharles.Forsyth * Save the status and patch up the number of
43674a4d8c2SCharles.Forsyth * bytes actually transferred.
43774a4d8c2SCharles.Forsyth * There's a firmware bug on some 956C controllers
43874a4d8c2SCharles.Forsyth * which causes the return count from a successful
43974a4d8c2SCharles.Forsyth * READ CAPACITY not be updated, so fix it here.
44074a4d8c2SCharles.Forsyth */
44174a4d8c2SCharles.Forsyth sdstat = ccb->sdstat;
44274a4d8c2SCharles.Forsyth btstat = ccb->btstat;
44374a4d8c2SCharles.Forsyth
44474a4d8c2SCharles.Forsyth d = ccb->datalen[0]<<16;
44574a4d8c2SCharles.Forsyth d |= ccb->datalen[1]<<8;
44674a4d8c2SCharles.Forsyth d |= ccb->datalen[2];
44774a4d8c2SCharles.Forsyth if(ccb->cs[0] == 0x25 && sdstat == SDok)
44874a4d8c2SCharles.Forsyth d = 0;
44974a4d8c2SCharles.Forsyth n -= d;
45074a4d8c2SCharles.Forsyth r->rlen = n;
45174a4d8c2SCharles.Forsyth
45274a4d8c2SCharles.Forsyth /*
45374a4d8c2SCharles.Forsyth * Tidy things up if a staging area was used for the data,
45474a4d8c2SCharles.Forsyth */
45574a4d8c2SCharles.Forsyth if(ccb->data != nil){
45674a4d8c2SCharles.Forsyth if(sdstat == SDok && btstat == 0 && !r->write)
45774a4d8c2SCharles.Forsyth memmove(ccb->data, data, n);
45874a4d8c2SCharles.Forsyth free(data);
45974a4d8c2SCharles.Forsyth ccb->data = nil;
46074a4d8c2SCharles.Forsyth }
46174a4d8c2SCharles.Forsyth
46274a4d8c2SCharles.Forsyth /*
46374a4d8c2SCharles.Forsyth * If there was a check-condition, save the
46474a4d8c2SCharles.Forsyth * ccb for a possible request-sense command.
46574a4d8c2SCharles.Forsyth */
46674a4d8c2SCharles.Forsyth if(sdstat == SDcheck){
46774a4d8c2SCharles.Forsyth if(r->flags & SDnosense){
46874a4d8c2SCharles.Forsyth lock(&ctlr->cachelock);
46974a4d8c2SCharles.Forsyth if(ctlr->cache[target])
47074a4d8c2SCharles.Forsyth ccbfree(ctlr, ctlr->cache[target]);
47174a4d8c2SCharles.Forsyth ctlr->cache[target] = (Ccb*)ccb;
47274a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
47374a4d8c2SCharles.Forsyth return SDcheck;
47474a4d8c2SCharles.Forsyth }
47574a4d8c2SCharles.Forsyth sense = &ccb->cs[ccb->cdblen];
47674a4d8c2SCharles.Forsyth n = 8+sense[7];
47774a4d8c2SCharles.Forsyth if(n > sizeof(r->sense)-1)
47874a4d8c2SCharles.Forsyth n = sizeof(r->sense)-1;
47974a4d8c2SCharles.Forsyth memmove(r->sense, sense, n);
48074a4d8c2SCharles.Forsyth r->flags |= SDvalidsense;
48174a4d8c2SCharles.Forsyth }
48274a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
48374a4d8c2SCharles.Forsyth
48474a4d8c2SCharles.Forsyth if(btstat){
48574a4d8c2SCharles.Forsyth if(btstat == 0x11)
48674a4d8c2SCharles.Forsyth return SDtimeout;
48774a4d8c2SCharles.Forsyth return SDeio;
48874a4d8c2SCharles.Forsyth }
48974a4d8c2SCharles.Forsyth return sdstat;
49074a4d8c2SCharles.Forsyth }
49174a4d8c2SCharles.Forsyth
49274a4d8c2SCharles.Forsyth static void
mylex24interrupt(Ureg *,void * arg)49374a4d8c2SCharles.Forsyth mylex24interrupt(Ureg*, void* arg)
49474a4d8c2SCharles.Forsyth {
49574a4d8c2SCharles.Forsyth ulong pa;
49674a4d8c2SCharles.Forsyth Ctlr *ctlr;
49774a4d8c2SCharles.Forsyth Ccb24 *ccb;
49874a4d8c2SCharles.Forsyth Mbox24 *mb, *mbox;
49974a4d8c2SCharles.Forsyth int port, rinterrupt, rstatus;
50074a4d8c2SCharles.Forsyth
50174a4d8c2SCharles.Forsyth ctlr = arg;
50274a4d8c2SCharles.Forsyth port = ctlr->port;
50374a4d8c2SCharles.Forsyth
50474a4d8c2SCharles.Forsyth /*
50574a4d8c2SCharles.Forsyth * Save and clear the interrupt(s). The only
50674a4d8c2SCharles.Forsyth * interrupts expected are Cmdc, which is ignored,
50774a4d8c2SCharles.Forsyth * and Imbl which means something completed.
50874a4d8c2SCharles.Forsyth * There's one spurious interrupt left over from
50974a4d8c2SCharles.Forsyth * initialisation, ignore it.
51074a4d8c2SCharles.Forsyth */
51174a4d8c2SCharles.Forsyth rinterrupt = inb(port+Rinterrupt);
51274a4d8c2SCharles.Forsyth rstatus = inb(port+Rstatus);
51374a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rint);
51474a4d8c2SCharles.Forsyth if((rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
51574a4d8c2SCharles.Forsyth print("%s: interrupt 0x%2.2ux\n",
51674a4d8c2SCharles.Forsyth "sdmylex"/*ctlr->sdev->name*/, rinterrupt);
51774a4d8c2SCharles.Forsyth if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
51874a4d8c2SCharles.Forsyth print("%s: command invalid\n", "sdmylex"/*ctlr->sdev->name*/);
51974a4d8c2SCharles.Forsyth
52074a4d8c2SCharles.Forsyth /*
52174a4d8c2SCharles.Forsyth * Look for something in the mail.
52274a4d8c2SCharles.Forsyth * If there is, save the status, free the mailbox
52374a4d8c2SCharles.Forsyth * and wakeup whoever.
52474a4d8c2SCharles.Forsyth */
52574a4d8c2SCharles.Forsyth mb = ctlr->mb;
52674a4d8c2SCharles.Forsyth for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
52774a4d8c2SCharles.Forsyth pa = (mbox->ccb[0]<<16)|(mbox->ccb[1]<<8)|mbox->ccb[2];
52874a4d8c2SCharles.Forsyth ccb = BPA2K(pa, BUSUNKNOWN);
52974a4d8c2SCharles.Forsyth mbox->code = 0;
53074a4d8c2SCharles.Forsyth ccb->done = 1;
53174a4d8c2SCharles.Forsyth wakeup(ccb);
53274a4d8c2SCharles.Forsyth
53374a4d8c2SCharles.Forsyth ctlr->mbix++;
53474a4d8c2SCharles.Forsyth if(ctlr->mbix >= NMbox+NMbox)
53574a4d8c2SCharles.Forsyth ctlr->mbix = NMbox;
53674a4d8c2SCharles.Forsyth }
53774a4d8c2SCharles.Forsyth }
53874a4d8c2SCharles.Forsyth
53974a4d8c2SCharles.Forsyth static int
done32(void * arg)54074a4d8c2SCharles.Forsyth done32(void* arg)
54174a4d8c2SCharles.Forsyth {
54274a4d8c2SCharles.Forsyth return ((Ccb32*)arg)->done;
54374a4d8c2SCharles.Forsyth }
54474a4d8c2SCharles.Forsyth
54574a4d8c2SCharles.Forsyth static int
mylex32rio(SDreq * r)54674a4d8c2SCharles.Forsyth mylex32rio(SDreq* r)
54774a4d8c2SCharles.Forsyth {
54874a4d8c2SCharles.Forsyth ulong p;
54974a4d8c2SCharles.Forsyth uchar lun;
55074a4d8c2SCharles.Forsyth Ctlr *ctlr;
55174a4d8c2SCharles.Forsyth Ccb32 *ccb;
55274a4d8c2SCharles.Forsyth Mbox32 *mb;
55374a4d8c2SCharles.Forsyth int d, n, btstat, sdstat, target;
55474a4d8c2SCharles.Forsyth
55574a4d8c2SCharles.Forsyth ctlr = r->unit->dev->ctlr;
55674a4d8c2SCharles.Forsyth target = r->unit->subno;
55774a4d8c2SCharles.Forsyth lun = (r->cmd[1]>>5) & 0x07;
55874a4d8c2SCharles.Forsyth
55974a4d8c2SCharles.Forsyth /*
56074a4d8c2SCharles.Forsyth * Ctlr->cache holds the last completed Ccb for this target if it
56174a4d8c2SCharles.Forsyth * returned 'check condition'.
56274a4d8c2SCharles.Forsyth * If this command is a request-sense and there is valid sense data
56374a4d8c2SCharles.Forsyth * from the last completed Ccb, return it immediately.
56474a4d8c2SCharles.Forsyth */
56574a4d8c2SCharles.Forsyth lock(&ctlr->cachelock);
56674a4d8c2SCharles.Forsyth if((ccb = ctlr->cache[target]) != nil){
56774a4d8c2SCharles.Forsyth ctlr->cache[target] = nil;
56874a4d8c2SCharles.Forsyth if(r->cmd[0] == 0x03
56974a4d8c2SCharles.Forsyth && ccb->sdstat == SDcheck && lun == (ccb->luntag & 0x07)){
57074a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
57174a4d8c2SCharles.Forsyth if(r->dlen){
57274a4d8c2SCharles.Forsyth n = 8+ccb->sense[7];
57374a4d8c2SCharles.Forsyth if(n > r->dlen)
57474a4d8c2SCharles.Forsyth n = r->dlen;
57574a4d8c2SCharles.Forsyth memmove(r->data, ccb->sense, n);
57674a4d8c2SCharles.Forsyth r->rlen = n;
57774a4d8c2SCharles.Forsyth }
57874a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
57974a4d8c2SCharles.Forsyth return SDok;
58074a4d8c2SCharles.Forsyth }
58174a4d8c2SCharles.Forsyth }
58274a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
58374a4d8c2SCharles.Forsyth if(ccb == nil)
58474a4d8c2SCharles.Forsyth ccb = ccballoc(ctlr);
58574a4d8c2SCharles.Forsyth
58674a4d8c2SCharles.Forsyth /*
58774a4d8c2SCharles.Forsyth * Fill in the ccb.
58874a4d8c2SCharles.Forsyth */
58974a4d8c2SCharles.Forsyth ccb->opcode = Ordl;
59074a4d8c2SCharles.Forsyth
59174a4d8c2SCharles.Forsyth n = r->dlen;
59274a4d8c2SCharles.Forsyth if(n == 0)
59374a4d8c2SCharles.Forsyth ccb->datadir = CCBdataout|CCBdatain;
59474a4d8c2SCharles.Forsyth else if(!r->write)
59574a4d8c2SCharles.Forsyth ccb->datadir = CCBdatain;
59674a4d8c2SCharles.Forsyth else
59774a4d8c2SCharles.Forsyth ccb->datadir = CCBdataout;
59874a4d8c2SCharles.Forsyth
59974a4d8c2SCharles.Forsyth ccb->cdblen = r->clen;
60074a4d8c2SCharles.Forsyth
60174a4d8c2SCharles.Forsyth ccb->datalen[0] = n;
60274a4d8c2SCharles.Forsyth ccb->datalen[1] = n>>8;
60374a4d8c2SCharles.Forsyth ccb->datalen[2] = n>>16;
60474a4d8c2SCharles.Forsyth ccb->datalen[3] = n>>24;
60574a4d8c2SCharles.Forsyth p = PADDR(r->data);
60674a4d8c2SCharles.Forsyth ccb->dataptr[0] = p;
60774a4d8c2SCharles.Forsyth ccb->dataptr[1] = p>>8;
60874a4d8c2SCharles.Forsyth ccb->dataptr[2] = p>>16;
60974a4d8c2SCharles.Forsyth ccb->dataptr[3] = p>>24;
61074a4d8c2SCharles.Forsyth
61174a4d8c2SCharles.Forsyth ccb->targetid = target;
61274a4d8c2SCharles.Forsyth ccb->luntag = lun;
61374a4d8c2SCharles.Forsyth if(r->unit->inquiry[7] & 0x02)
61474a4d8c2SCharles.Forsyth ccb->luntag |= SQTag|TagEnable;
61574a4d8c2SCharles.Forsyth memmove(ccb->cdb, r->cmd, r->clen);
61674a4d8c2SCharles.Forsyth ccb->btstat = ccb->sdstat = 0;
61774a4d8c2SCharles.Forsyth ccb->ccbctl = 0;
61874a4d8c2SCharles.Forsyth
61974a4d8c2SCharles.Forsyth /*
62074a4d8c2SCharles.Forsyth * There's one more mbox than there there is
62174a4d8c2SCharles.Forsyth * ccb so there is always one free.
62274a4d8c2SCharles.Forsyth */
62374a4d8c2SCharles.Forsyth lock(&ctlr->mboxlock);
62474a4d8c2SCharles.Forsyth mb = ctlr->mb;
62574a4d8c2SCharles.Forsyth mb += ctlr->mbox;
62674a4d8c2SCharles.Forsyth p = PADDR(ccb);
62774a4d8c2SCharles.Forsyth mb->ccb[0] = p;
62874a4d8c2SCharles.Forsyth mb->ccb[1] = p>>8;
62974a4d8c2SCharles.Forsyth mb->ccb[2] = p>>16;
63074a4d8c2SCharles.Forsyth mb->ccb[3] = p>>24;
63174a4d8c2SCharles.Forsyth mb->code = Mbostart;
63274a4d8c2SCharles.Forsyth ctlr->mbox++;
63374a4d8c2SCharles.Forsyth if(ctlr->mbox >= NMbox)
63474a4d8c2SCharles.Forsyth ctlr->mbox = 0;
63574a4d8c2SCharles.Forsyth
63674a4d8c2SCharles.Forsyth /*
63774a4d8c2SCharles.Forsyth * This command does not require Hardy
63874a4d8c2SCharles.Forsyth * and doesn't generate a Cmdc interrupt.
63974a4d8c2SCharles.Forsyth */
64074a4d8c2SCharles.Forsyth ccb->done = 0;
64174a4d8c2SCharles.Forsyth outb(ctlr->port+Rcpr, Cstart);
64274a4d8c2SCharles.Forsyth unlock(&ctlr->mboxlock);
64374a4d8c2SCharles.Forsyth
64474a4d8c2SCharles.Forsyth /*
64574a4d8c2SCharles.Forsyth * Wait for the request to complete and return the status.
64674a4d8c2SCharles.Forsyth * Since the buffer is not reference counted cannot return
64774a4d8c2SCharles.Forsyth * until the DMA is done writing into the buffer so the caller
64874a4d8c2SCharles.Forsyth * cannot free the buffer prematurely.
64974a4d8c2SCharles.Forsyth */
65074a4d8c2SCharles.Forsyth while(waserror())
65174a4d8c2SCharles.Forsyth ;
65274a4d8c2SCharles.Forsyth tsleep(ccb, done32, ccb, 30*1000);
65374a4d8c2SCharles.Forsyth poperror();
65474a4d8c2SCharles.Forsyth
65574a4d8c2SCharles.Forsyth if(!done32(ccb)){
65674a4d8c2SCharles.Forsyth print("%s: %d/%d: sd32rio timeout\n",
65774a4d8c2SCharles.Forsyth "sdmylex"/*ctlr->sdev->name*/, target, r->lun);
65874a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
65974a4d8c2SCharles.Forsyth
66074a4d8c2SCharles.Forsyth return SDtimeout;
66174a4d8c2SCharles.Forsyth }
66274a4d8c2SCharles.Forsyth
66374a4d8c2SCharles.Forsyth /*
66474a4d8c2SCharles.Forsyth * Save the status and patch up the number of
66574a4d8c2SCharles.Forsyth * bytes actually transferred.
66674a4d8c2SCharles.Forsyth * There's a firmware bug on some 956C controllers
66774a4d8c2SCharles.Forsyth * which causes the return count from a successful
66874a4d8c2SCharles.Forsyth * READ CAPACITY not to be updated, so fix it here.
66974a4d8c2SCharles.Forsyth */
67074a4d8c2SCharles.Forsyth sdstat = ccb->sdstat;
67174a4d8c2SCharles.Forsyth btstat = ccb->btstat;
67274a4d8c2SCharles.Forsyth
67374a4d8c2SCharles.Forsyth d = ccb->datalen[0];
67474a4d8c2SCharles.Forsyth d |= (ccb->datalen[1]<<8);
67574a4d8c2SCharles.Forsyth d |= (ccb->datalen[2]<<16);
67674a4d8c2SCharles.Forsyth d |= (ccb->datalen[3]<<24);
67774a4d8c2SCharles.Forsyth if(ccb->cdb[0] == 0x25 && sdstat == SDok)
67874a4d8c2SCharles.Forsyth d = 0;
67974a4d8c2SCharles.Forsyth n -= d;
68074a4d8c2SCharles.Forsyth r->rlen = n;
68174a4d8c2SCharles.Forsyth
68274a4d8c2SCharles.Forsyth /*
68374a4d8c2SCharles.Forsyth * If there was a check-condition, save the
68474a4d8c2SCharles.Forsyth * ccb for a possible request-sense command.
68574a4d8c2SCharles.Forsyth */
68674a4d8c2SCharles.Forsyth if(sdstat == SDcheck){
68774a4d8c2SCharles.Forsyth if(r->flags & SDnosense){
68874a4d8c2SCharles.Forsyth lock(&ctlr->cachelock);
68974a4d8c2SCharles.Forsyth if(ctlr->cache[target])
69074a4d8c2SCharles.Forsyth ccbfree(ctlr, ctlr->cache[target]);
69174a4d8c2SCharles.Forsyth ctlr->cache[target] = (Ccb*)ccb;
69274a4d8c2SCharles.Forsyth unlock(&ctlr->cachelock);
69374a4d8c2SCharles.Forsyth return SDcheck;
69474a4d8c2SCharles.Forsyth }
69574a4d8c2SCharles.Forsyth n = 8+ccb->sense[7];
69674a4d8c2SCharles.Forsyth if(n > sizeof(r->sense)-1)
69774a4d8c2SCharles.Forsyth n = sizeof(r->sense)-1;
69874a4d8c2SCharles.Forsyth memmove(r->sense, ccb->sense, n);
69974a4d8c2SCharles.Forsyth r->flags |= SDvalidsense;
70074a4d8c2SCharles.Forsyth }
70174a4d8c2SCharles.Forsyth ccbfree(ctlr, (Ccb*)ccb);
70274a4d8c2SCharles.Forsyth
70374a4d8c2SCharles.Forsyth if(btstat){
70474a4d8c2SCharles.Forsyth if(btstat == 0x11)
70574a4d8c2SCharles.Forsyth return SDtimeout;
70674a4d8c2SCharles.Forsyth return SDeio;
70774a4d8c2SCharles.Forsyth }
70874a4d8c2SCharles.Forsyth return sdstat;
70974a4d8c2SCharles.Forsyth }
71074a4d8c2SCharles.Forsyth
71174a4d8c2SCharles.Forsyth static void
mylex32interrupt(Ureg *,void * arg)71274a4d8c2SCharles.Forsyth mylex32interrupt(Ureg*, void* arg)
71374a4d8c2SCharles.Forsyth {
71474a4d8c2SCharles.Forsyth ulong pa;
71574a4d8c2SCharles.Forsyth Ctlr *ctlr;
71674a4d8c2SCharles.Forsyth Ccb32 *ccb;
71774a4d8c2SCharles.Forsyth Mbox32 *mb, *mbox;
71874a4d8c2SCharles.Forsyth int port, rinterrupt, rstatus;
71974a4d8c2SCharles.Forsyth
72074a4d8c2SCharles.Forsyth ctlr = arg;
72174a4d8c2SCharles.Forsyth port = ctlr->port;
72274a4d8c2SCharles.Forsyth
72374a4d8c2SCharles.Forsyth /*
72474a4d8c2SCharles.Forsyth * Save and clear the interrupt(s). The only
72574a4d8c2SCharles.Forsyth * interrupts expected are Cmdc, which is ignored,
72674a4d8c2SCharles.Forsyth * and Imbl which means something completed.
72774a4d8c2SCharles.Forsyth * There's one spurious interrupt left over from
72874a4d8c2SCharles.Forsyth * initialisation, ignore it.
72974a4d8c2SCharles.Forsyth */
73074a4d8c2SCharles.Forsyth rinterrupt = inb(port+Rinterrupt);
73174a4d8c2SCharles.Forsyth rstatus = inb(port+Rstatus);
73274a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rint);
73374a4d8c2SCharles.Forsyth if((rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)
73474a4d8c2SCharles.Forsyth print("%s: interrupt 0x%2.2ux\n",
73574a4d8c2SCharles.Forsyth "sdmylex"/*ctlr->sdev->name*/, rinterrupt);
73674a4d8c2SCharles.Forsyth if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
73774a4d8c2SCharles.Forsyth print("%s: command invalid\n", "sdmylex"/*ctlr->sdev->name*/);
73874a4d8c2SCharles.Forsyth
73974a4d8c2SCharles.Forsyth /*
74074a4d8c2SCharles.Forsyth * Look for something in the mail.
74174a4d8c2SCharles.Forsyth * If there is, free the mailbox and wakeup whoever.
74274a4d8c2SCharles.Forsyth */
74374a4d8c2SCharles.Forsyth mb = ctlr->mb;
74474a4d8c2SCharles.Forsyth for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){
74574a4d8c2SCharles.Forsyth pa = (mbox->ccb[3]<<24)
74674a4d8c2SCharles.Forsyth |(mbox->ccb[2]<<16)
74774a4d8c2SCharles.Forsyth |(mbox->ccb[1]<<8)
74874a4d8c2SCharles.Forsyth |mbox->ccb[0];
74974a4d8c2SCharles.Forsyth if(ctlr->pcidev)
75074a4d8c2SCharles.Forsyth ccb = BPA2K(pa, ctlr->pcidev->tbdf);
75174a4d8c2SCharles.Forsyth else
75274a4d8c2SCharles.Forsyth ccb = BPA2K(pa, BUSUNKNOWN);
75374a4d8c2SCharles.Forsyth mbox->code = 0;
75474a4d8c2SCharles.Forsyth ccb->done = 1;
75574a4d8c2SCharles.Forsyth wakeup(ccb);
75674a4d8c2SCharles.Forsyth
75774a4d8c2SCharles.Forsyth ctlr->mbix++;
75874a4d8c2SCharles.Forsyth if(ctlr->mbix >= NMbox+NMbox)
75974a4d8c2SCharles.Forsyth ctlr->mbix = NMbox;
76074a4d8c2SCharles.Forsyth }
76174a4d8c2SCharles.Forsyth }
76274a4d8c2SCharles.Forsyth
76374a4d8c2SCharles.Forsyth static int
mylexrio(SDreq * r)76474a4d8c2SCharles.Forsyth mylexrio(SDreq* r)
76574a4d8c2SCharles.Forsyth {
76674a4d8c2SCharles.Forsyth int subno;
76774a4d8c2SCharles.Forsyth Ctlr *ctlr;
76874a4d8c2SCharles.Forsyth
76974a4d8c2SCharles.Forsyth subno = r->unit->subno;
77074a4d8c2SCharles.Forsyth ctlr = r->unit->dev->ctlr;
77174a4d8c2SCharles.Forsyth if(subno == ctlr->id || (!ctlr->wide && subno >= 8))
77274a4d8c2SCharles.Forsyth r->status = SDtimeout;
77374a4d8c2SCharles.Forsyth else if(ctlr->bus == 24)
77474a4d8c2SCharles.Forsyth r->status = mylex24rio(r);
77574a4d8c2SCharles.Forsyth else
77674a4d8c2SCharles.Forsyth r->status = mylex32rio(r);
77774a4d8c2SCharles.Forsyth return r->status;
77874a4d8c2SCharles.Forsyth }
77974a4d8c2SCharles.Forsyth
78074a4d8c2SCharles.Forsyth /*
78174a4d8c2SCharles.Forsyth * Issue a command to a controller. The command and its length is
78274a4d8c2SCharles.Forsyth * contained in cmd and cmdlen. If any data is to be
78374a4d8c2SCharles.Forsyth * returned, datalen should be non-zero, and the returned data
78474a4d8c2SCharles.Forsyth * will be placed in data.
78574a4d8c2SCharles.Forsyth * If Cmdc is set, bail out, the invalid command will be handled
78674a4d8c2SCharles.Forsyth * when the interrupt is processed.
78774a4d8c2SCharles.Forsyth */
78874a4d8c2SCharles.Forsyth static void
issueio(int port,uchar * cmd,int cmdlen,uchar * data,int datalen)78974a4d8c2SCharles.Forsyth issueio(int port, uchar* cmd, int cmdlen, uchar* data, int datalen)
79074a4d8c2SCharles.Forsyth {
79174a4d8c2SCharles.Forsyth int len;
79274a4d8c2SCharles.Forsyth
79374a4d8c2SCharles.Forsyth if(cmd[0] != Cstart && cmd[0] != Ceombri){
79474a4d8c2SCharles.Forsyth while(!(inb(port+Rstatus) & Hardy))
79574a4d8c2SCharles.Forsyth ;
79674a4d8c2SCharles.Forsyth }
79774a4d8c2SCharles.Forsyth outb(port+Rcpr, cmd[0]);
79874a4d8c2SCharles.Forsyth
79974a4d8c2SCharles.Forsyth len = 1;
80074a4d8c2SCharles.Forsyth while(len < cmdlen){
80174a4d8c2SCharles.Forsyth if(!(inb(port+Rstatus) & Cprbsy)){
80274a4d8c2SCharles.Forsyth outb(port+Rcpr, cmd[len]);
80374a4d8c2SCharles.Forsyth len++;
80474a4d8c2SCharles.Forsyth }
80574a4d8c2SCharles.Forsyth if(inb(port+Rinterrupt) & Cmdc)
80674a4d8c2SCharles.Forsyth return;
80774a4d8c2SCharles.Forsyth }
80874a4d8c2SCharles.Forsyth
80974a4d8c2SCharles.Forsyth if(datalen){
81074a4d8c2SCharles.Forsyth len = 0;
81174a4d8c2SCharles.Forsyth while(len < datalen){
81274a4d8c2SCharles.Forsyth if(inb(port+Rstatus) & Dirrdy){
81374a4d8c2SCharles.Forsyth data[len] = inb(port+Rdatain);
81474a4d8c2SCharles.Forsyth len++;
81574a4d8c2SCharles.Forsyth }
81674a4d8c2SCharles.Forsyth if(inb(port+Rinterrupt) & Cmdc)
81774a4d8c2SCharles.Forsyth return;
81874a4d8c2SCharles.Forsyth }
81974a4d8c2SCharles.Forsyth }
82074a4d8c2SCharles.Forsyth }
82174a4d8c2SCharles.Forsyth
82274a4d8c2SCharles.Forsyth /*
82374a4d8c2SCharles.Forsyth * Issue a command to a controller, wait for it to complete then
82474a4d8c2SCharles.Forsyth * try to reset the interrupt. Should only be called at initialisation.
82574a4d8c2SCharles.Forsyth */
82674a4d8c2SCharles.Forsyth static int
issue(Ctlr * ctlr,uchar * cmd,int cmdlen,uchar * data,int datalen)82774a4d8c2SCharles.Forsyth issue(Ctlr* ctlr, uchar* cmd, int cmdlen, uchar* data, int datalen)
82874a4d8c2SCharles.Forsyth {
82974a4d8c2SCharles.Forsyth int port;
83074a4d8c2SCharles.Forsyth uchar rinterrupt, rstatus;
83174a4d8c2SCharles.Forsyth static Lock mylexissuelock;
83274a4d8c2SCharles.Forsyth
83374a4d8c2SCharles.Forsyth port = ctlr->port;
83474a4d8c2SCharles.Forsyth
83574a4d8c2SCharles.Forsyth ilock(&ctlr->issuelock);
83674a4d8c2SCharles.Forsyth issueio(port, cmd, cmdlen, data, datalen);
83774a4d8c2SCharles.Forsyth
83874a4d8c2SCharles.Forsyth while(!((rinterrupt = inb(port+Rinterrupt)) & Cmdc))
83974a4d8c2SCharles.Forsyth ;
84074a4d8c2SCharles.Forsyth
84174a4d8c2SCharles.Forsyth rstatus = inb(port+Rstatus);
84274a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rint);
84374a4d8c2SCharles.Forsyth iunlock(&ctlr->issuelock);
84474a4d8c2SCharles.Forsyth
84574a4d8c2SCharles.Forsyth if((rinterrupt & Cmdc) && (rstatus & Cmdinv))
84674a4d8c2SCharles.Forsyth return 0;
84774a4d8c2SCharles.Forsyth return 1;
84874a4d8c2SCharles.Forsyth }
84974a4d8c2SCharles.Forsyth
85074a4d8c2SCharles.Forsyth static SDev*
mylexprobe(int port,int irq)85174a4d8c2SCharles.Forsyth mylexprobe(int port, int irq)
85274a4d8c2SCharles.Forsyth {
85374a4d8c2SCharles.Forsyth SDev *sdev;
85474a4d8c2SCharles.Forsyth Ctlr *ctlr;
85574a4d8c2SCharles.Forsyth uchar cmd[6], data[256];
85674a4d8c2SCharles.Forsyth int clen, dlen, timeo;
85774a4d8c2SCharles.Forsyth
85874a4d8c2SCharles.Forsyth if(ioalloc(port, 0x3, 0, "mylex") < 0)
85974a4d8c2SCharles.Forsyth return nil;
86074a4d8c2SCharles.Forsyth ctlr = nil;
86174a4d8c2SCharles.Forsyth
86274a4d8c2SCharles.Forsyth /*
86374a4d8c2SCharles.Forsyth * Attempt to hard-reset the board and reset
86474a4d8c2SCharles.Forsyth * the SCSI bus. If the board state doesn't settle to
86574a4d8c2SCharles.Forsyth * idle with mailbox initialisation required, either
86674a4d8c2SCharles.Forsyth * it isn't a compatible board or it's broken.
86774a4d8c2SCharles.Forsyth * If the controller has SCAM set this can take a while.
86874a4d8c2SCharles.Forsyth */
86974a4d8c2SCharles.Forsyth if(getconf("*noscsireset") != nil)
87074a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rhard);
87174a4d8c2SCharles.Forsyth else
87274a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rhard|Rsbus);
87374a4d8c2SCharles.Forsyth for(timeo = 0; timeo < 100; timeo++){
87474a4d8c2SCharles.Forsyth if(inb(port+Rstatus) == (Inreq|Hardy))
87574a4d8c2SCharles.Forsyth break;
87674a4d8c2SCharles.Forsyth delay(100);
87774a4d8c2SCharles.Forsyth }
87874a4d8c2SCharles.Forsyth if(inb(port+Rstatus) != (Inreq|Hardy)){
87974a4d8c2SCharles.Forsyth buggery:
88074a4d8c2SCharles.Forsyth if(ctlr != nil)
88174a4d8c2SCharles.Forsyth free(ctlr);
88274a4d8c2SCharles.Forsyth iofree(port);
88374a4d8c2SCharles.Forsyth return nil;
88474a4d8c2SCharles.Forsyth }
88574a4d8c2SCharles.Forsyth
88674a4d8c2SCharles.Forsyth if((ctlr = malloc(sizeof(Ctlr))) == nil)
88774a4d8c2SCharles.Forsyth goto buggery;
88874a4d8c2SCharles.Forsyth ctlr->port = port;
88974a4d8c2SCharles.Forsyth ctlr->irq = irq;
89074a4d8c2SCharles.Forsyth ctlr->bus = 24;
89174a4d8c2SCharles.Forsyth ctlr->wide = 0;
89274a4d8c2SCharles.Forsyth
89374a4d8c2SCharles.Forsyth /*
89474a4d8c2SCharles.Forsyth * Try to determine if this is a 32-bit MultiMaster controller
89574a4d8c2SCharles.Forsyth * by attempting to obtain the extended inquiry information;
89674a4d8c2SCharles.Forsyth * this command is not implemented on Adaptec 154xx
89774a4d8c2SCharles.Forsyth * controllers. If successful, the first byte of the returned
89874a4d8c2SCharles.Forsyth * data is the host adapter bus type, 'E' for 32-bit EISA,
89974a4d8c2SCharles.Forsyth * PCI and VLB buses.
90074a4d8c2SCharles.Forsyth */
90174a4d8c2SCharles.Forsyth cmd[0] = Ciesi;
902*8a8c2d74SCharles.Forsyth cmd[1] = 14;
90374a4d8c2SCharles.Forsyth clen = 2;
90474a4d8c2SCharles.Forsyth dlen = 256;
90574a4d8c2SCharles.Forsyth if(issue(ctlr, cmd, clen, data, dlen)){
90674a4d8c2SCharles.Forsyth if(data[0] == 'E')
90774a4d8c2SCharles.Forsyth ctlr->bus = 32;
90874a4d8c2SCharles.Forsyth ctlr->wide = data[0x0D] & 0x01;
90974a4d8c2SCharles.Forsyth }
91074a4d8c2SCharles.Forsyth else{
91174a4d8c2SCharles.Forsyth /*
91274a4d8c2SCharles.Forsyth * Inconceivable though it may seem, a hard controller reset
91374a4d8c2SCharles.Forsyth * is necessary here to clear out the command queue. Every
91474a4d8c2SCharles.Forsyth * board seems to lock-up in a different way if you give an
91574a4d8c2SCharles.Forsyth * invalid command and then try to clear out the
91674a4d8c2SCharles.Forsyth * command/parameter and/or data-in register.
91774a4d8c2SCharles.Forsyth * Soft reset doesn't do the job either. Fortunately no
91874a4d8c2SCharles.Forsyth * serious initialisation has been done yet so there's nothing
91974a4d8c2SCharles.Forsyth * to tidy up.
92074a4d8c2SCharles.Forsyth */
92174a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rhard);
92274a4d8c2SCharles.Forsyth for(timeo = 0; timeo < 100; timeo++){
92374a4d8c2SCharles.Forsyth if(inb(port+Rstatus) == (Inreq|Hardy))
92474a4d8c2SCharles.Forsyth break;
92574a4d8c2SCharles.Forsyth delay(100);
92674a4d8c2SCharles.Forsyth }
92774a4d8c2SCharles.Forsyth if(inb(port+Rstatus) != (Inreq|Hardy))
92874a4d8c2SCharles.Forsyth goto buggery;
92974a4d8c2SCharles.Forsyth }
93074a4d8c2SCharles.Forsyth
93174a4d8c2SCharles.Forsyth /*
93274a4d8c2SCharles.Forsyth * If the BIOS is enabled on the AHA-1542C/CF and BIOS options for
93374a4d8c2SCharles.Forsyth * support of drives > 1Gb, dynamic scanning of the SCSI bus or more
93474a4d8c2SCharles.Forsyth * than 2 drives under DOS 5.0 are enabled, the BIOS disables
93574a4d8c2SCharles.Forsyth * accepting Cmbinit to protect against running with drivers which
93674a4d8c2SCharles.Forsyth * don't support those options. In order to unlock the interface it
93774a4d8c2SCharles.Forsyth * is necessary to read a lock-code using Cextbios and write it back
93874a4d8c2SCharles.Forsyth * using Cmbienable; the lock-code is non-zero.
93974a4d8c2SCharles.Forsyth */
94074a4d8c2SCharles.Forsyth cmd[0] = Cinquiry;
94174a4d8c2SCharles.Forsyth clen = 1;
94274a4d8c2SCharles.Forsyth dlen = 4;
94374a4d8c2SCharles.Forsyth if(issue(ctlr, cmd, clen, data, dlen) == 0)
94474a4d8c2SCharles.Forsyth goto buggery;
94574a4d8c2SCharles.Forsyth if(data[0] >= 0x43){
94674a4d8c2SCharles.Forsyth cmd[0] = Cextbios;
94774a4d8c2SCharles.Forsyth clen = 1;
94874a4d8c2SCharles.Forsyth dlen = 2;
94974a4d8c2SCharles.Forsyth if(issue(ctlr, cmd, clen, data, dlen) == 0)
95074a4d8c2SCharles.Forsyth goto buggery;
95174a4d8c2SCharles.Forsyth
95274a4d8c2SCharles.Forsyth /*
95374a4d8c2SCharles.Forsyth * Lock-code returned in data[1]. If it's non-zero write
95474a4d8c2SCharles.Forsyth * it back along with bit 0 of byte 0 cleared to enable
95574a4d8c2SCharles.Forsyth * mailbox initialisation.
95674a4d8c2SCharles.Forsyth */
95774a4d8c2SCharles.Forsyth if(data[1]){
95874a4d8c2SCharles.Forsyth cmd[0] = Cmbienable;
95974a4d8c2SCharles.Forsyth cmd[1] = 0;
96074a4d8c2SCharles.Forsyth cmd[2] = data[1];
96174a4d8c2SCharles.Forsyth clen = 3;
96274a4d8c2SCharles.Forsyth if(issue(ctlr, cmd, clen, 0, 0) == 0)
96374a4d8c2SCharles.Forsyth goto buggery;
96474a4d8c2SCharles.Forsyth }
96574a4d8c2SCharles.Forsyth }
96674a4d8c2SCharles.Forsyth
96774a4d8c2SCharles.Forsyth /*
96874a4d8c2SCharles.Forsyth * Get the id, DMA and IRQ info from the board. This will
96974a4d8c2SCharles.Forsyth * cause an interrupt which will hopefully not cause any
97074a4d8c2SCharles.Forsyth * trouble because the interrupt number isn't known yet.
97174a4d8c2SCharles.Forsyth * This is necessary as the DMA won't be set up if the
97274a4d8c2SCharles.Forsyth * board has the BIOS disabled.
97374a4d8c2SCharles.Forsyth *
97474a4d8c2SCharles.Forsyth * If the IRQ is already known, this must be a 32-bit PCI
97574a4d8c2SCharles.Forsyth * or EISA card, in which case the returned DMA and IRQ can
97674a4d8c2SCharles.Forsyth * be ignored.
97774a4d8c2SCharles.Forsyth */
97874a4d8c2SCharles.Forsyth cmd[0] = Cinquire;
97974a4d8c2SCharles.Forsyth clen = 1;
98074a4d8c2SCharles.Forsyth dlen = 3;
98174a4d8c2SCharles.Forsyth if(issue(ctlr, cmd, clen, data, dlen) == 0)
98274a4d8c2SCharles.Forsyth goto buggery;
98374a4d8c2SCharles.Forsyth
98474a4d8c2SCharles.Forsyth ctlr->id = data[2] & 0x07;
98574a4d8c2SCharles.Forsyth if(ctlr->irq < 0){
98674a4d8c2SCharles.Forsyth switch(data[0]){ /* DMA Arbitration Priority */
98774a4d8c2SCharles.Forsyth case 0x80: /* Channel 7 */
98874a4d8c2SCharles.Forsyth outb(0xD6, 0xC3);
98974a4d8c2SCharles.Forsyth outb(0xD4, 0x03);
99074a4d8c2SCharles.Forsyth break;
99174a4d8c2SCharles.Forsyth case 0x40: /* Channel 6 */
99274a4d8c2SCharles.Forsyth outb(0xD6, 0xC2);
99374a4d8c2SCharles.Forsyth outb(0xD4, 0x02);
99474a4d8c2SCharles.Forsyth break;
99574a4d8c2SCharles.Forsyth case 0x20: /* Channel 5 */
99674a4d8c2SCharles.Forsyth outb(0xD6, 0xC1);
99774a4d8c2SCharles.Forsyth outb(0xD4, 0x01);
99874a4d8c2SCharles.Forsyth break;
99974a4d8c2SCharles.Forsyth case 0x01: /* Channel 0 */
100074a4d8c2SCharles.Forsyth outb(0x0B, 0xC0);
100174a4d8c2SCharles.Forsyth outb(0x0A, 0x00);
100274a4d8c2SCharles.Forsyth break;
100374a4d8c2SCharles.Forsyth default:
100474a4d8c2SCharles.Forsyth if(ctlr->bus == 24)
100574a4d8c2SCharles.Forsyth goto buggery;
100674a4d8c2SCharles.Forsyth break;
100774a4d8c2SCharles.Forsyth }
100874a4d8c2SCharles.Forsyth
100974a4d8c2SCharles.Forsyth switch(data[1]){ /* Interrupt Channel */
101074a4d8c2SCharles.Forsyth case 0x40:
101174a4d8c2SCharles.Forsyth ctlr->irq = 15;
101274a4d8c2SCharles.Forsyth break;
101374a4d8c2SCharles.Forsyth case 0x20:
101474a4d8c2SCharles.Forsyth ctlr->irq = 14;
101574a4d8c2SCharles.Forsyth break;
101674a4d8c2SCharles.Forsyth case 0x08:
101774a4d8c2SCharles.Forsyth ctlr->irq = 12;
101874a4d8c2SCharles.Forsyth break;
101974a4d8c2SCharles.Forsyth case 0x04:
102074a4d8c2SCharles.Forsyth ctlr->irq = 11;
102174a4d8c2SCharles.Forsyth break;
102274a4d8c2SCharles.Forsyth case 0x02:
102374a4d8c2SCharles.Forsyth ctlr->irq = 10;
102474a4d8c2SCharles.Forsyth break;
102574a4d8c2SCharles.Forsyth case 0x01:
102674a4d8c2SCharles.Forsyth ctlr->irq = 9;
102774a4d8c2SCharles.Forsyth break;
102874a4d8c2SCharles.Forsyth default:
102974a4d8c2SCharles.Forsyth goto buggery;
103074a4d8c2SCharles.Forsyth }
103174a4d8c2SCharles.Forsyth }
103274a4d8c2SCharles.Forsyth
103374a4d8c2SCharles.Forsyth if((sdev = malloc(sizeof(SDev))) == nil)
103474a4d8c2SCharles.Forsyth goto buggery;
103574a4d8c2SCharles.Forsyth sdev->ifc = &sdmylexifc;
103674a4d8c2SCharles.Forsyth sdev->ctlr = ctlr;
103774a4d8c2SCharles.Forsyth ctlr->sdev = sdev;
103874a4d8c2SCharles.Forsyth if(!ctlr->wide)
103974a4d8c2SCharles.Forsyth sdev->nunit = 8;
104074a4d8c2SCharles.Forsyth else
104174a4d8c2SCharles.Forsyth sdev->nunit = 16;
104274a4d8c2SCharles.Forsyth
104374a4d8c2SCharles.Forsyth return sdev;
104474a4d8c2SCharles.Forsyth }
104574a4d8c2SCharles.Forsyth
104674a4d8c2SCharles.Forsyth static int mylexport[8] = {
104774a4d8c2SCharles.Forsyth 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0x000, 0x000,
104874a4d8c2SCharles.Forsyth };
104974a4d8c2SCharles.Forsyth
105074a4d8c2SCharles.Forsyth static SDev*
mylexpnp(void)105174a4d8c2SCharles.Forsyth mylexpnp(void)
105274a4d8c2SCharles.Forsyth {
105374a4d8c2SCharles.Forsyth Pcidev *p;
105474a4d8c2SCharles.Forsyth Ctlr *ctlr;
105574a4d8c2SCharles.Forsyth ISAConf isa;
105674a4d8c2SCharles.Forsyth int cfg, ctlrno, i, x;
105774a4d8c2SCharles.Forsyth SDev *sdev, *head, *tail;
105874a4d8c2SCharles.Forsyth
105974a4d8c2SCharles.Forsyth p = nil;
106074a4d8c2SCharles.Forsyth head = tail = nil;
106174a4d8c2SCharles.Forsyth while(p = pcimatch(p, 0x104B, 0)){
106274a4d8c2SCharles.Forsyth if((sdev = mylexprobe(p->mem[0].bar & ~0x01, p->intl)) == nil)
106374a4d8c2SCharles.Forsyth continue;
106474a4d8c2SCharles.Forsyth
106574a4d8c2SCharles.Forsyth ctlr = sdev->ctlr;
106674a4d8c2SCharles.Forsyth ctlr->pcidev = p;
106774a4d8c2SCharles.Forsyth
106874a4d8c2SCharles.Forsyth if(head != nil)
106974a4d8c2SCharles.Forsyth tail->next = sdev;
107074a4d8c2SCharles.Forsyth else
107174a4d8c2SCharles.Forsyth head = sdev;
107274a4d8c2SCharles.Forsyth tail = sdev;
107374a4d8c2SCharles.Forsyth }
107474a4d8c2SCharles.Forsyth
107574a4d8c2SCharles.Forsyth if(strncmp(KADDR(0xFFFD9), "EISA", 4) == 0){
107674a4d8c2SCharles.Forsyth for(cfg = 0x1000; cfg < MaxEISA*0x1000; cfg += 0x1000){
107774a4d8c2SCharles.Forsyth x = 0;
107874a4d8c2SCharles.Forsyth for(i = 0; i < 4; i++)
107974a4d8c2SCharles.Forsyth x |= inb(cfg+CfgEISA+i)<<(i*8);
108074a4d8c2SCharles.Forsyth if(x != 0x0142B30A && x != 0x0242B30A)
108174a4d8c2SCharles.Forsyth continue;
108274a4d8c2SCharles.Forsyth
108374a4d8c2SCharles.Forsyth x = inb(cfg+0xC8C);
108474a4d8c2SCharles.Forsyth if((sdev = mylexprobe(mylexport[x & 0x07], -1)) == nil)
108574a4d8c2SCharles.Forsyth continue;
108674a4d8c2SCharles.Forsyth
108774a4d8c2SCharles.Forsyth if(head != nil)
108874a4d8c2SCharles.Forsyth tail->next = sdev;
108974a4d8c2SCharles.Forsyth else
109074a4d8c2SCharles.Forsyth head = sdev;
109174a4d8c2SCharles.Forsyth tail = sdev;
109274a4d8c2SCharles.Forsyth }
109374a4d8c2SCharles.Forsyth }
109474a4d8c2SCharles.Forsyth
109574a4d8c2SCharles.Forsyth for(ctlrno = 0; ctlrno < 4; ctlrno++){
109674a4d8c2SCharles.Forsyth memset(&isa, 0, sizeof(isa));
109774a4d8c2SCharles.Forsyth if(!isaconfig("scsi", ctlrno, &isa))
109874a4d8c2SCharles.Forsyth continue;
109974a4d8c2SCharles.Forsyth if(strcmp(isa.type, "aha1542"))
110074a4d8c2SCharles.Forsyth continue;
110174a4d8c2SCharles.Forsyth if((sdev = mylexprobe(isa.port, -1)) == nil)
110274a4d8c2SCharles.Forsyth continue;
110374a4d8c2SCharles.Forsyth
110474a4d8c2SCharles.Forsyth if(head != nil)
110574a4d8c2SCharles.Forsyth tail->next = sdev;
110674a4d8c2SCharles.Forsyth else
110774a4d8c2SCharles.Forsyth head = sdev;
110874a4d8c2SCharles.Forsyth tail = sdev;
110974a4d8c2SCharles.Forsyth }
111074a4d8c2SCharles.Forsyth
111174a4d8c2SCharles.Forsyth return head;
111274a4d8c2SCharles.Forsyth }
111374a4d8c2SCharles.Forsyth
111474a4d8c2SCharles.Forsyth static SDev*
mylexid(SDev * sdev)111574a4d8c2SCharles.Forsyth mylexid(SDev* sdev)
111674a4d8c2SCharles.Forsyth {
111774a4d8c2SCharles.Forsyth return scsiid(sdev, &sdmylexifc);
111874a4d8c2SCharles.Forsyth }
111974a4d8c2SCharles.Forsyth
112074a4d8c2SCharles.Forsyth static int
mylex24enable(Ctlr * ctlr)112174a4d8c2SCharles.Forsyth mylex24enable(Ctlr* ctlr)
112274a4d8c2SCharles.Forsyth {
112374a4d8c2SCharles.Forsyth ulong p;
112474a4d8c2SCharles.Forsyth Ccb24 *ccb, *ccbp;
112574a4d8c2SCharles.Forsyth uchar cmd[6], *v;
112674a4d8c2SCharles.Forsyth int len;
112774a4d8c2SCharles.Forsyth
112874a4d8c2SCharles.Forsyth len = (sizeof(Mbox24)*NMbox*2)+(sizeof(Ccb24)*NCcb);
112974a4d8c2SCharles.Forsyth v = xspanalloc(len, 32, 0);
113074a4d8c2SCharles.Forsyth
113174a4d8c2SCharles.Forsyth if(!PADDR24(ctlr, sizeof(Ctlr)) || !PADDR24(v, len))
113274a4d8c2SCharles.Forsyth return 0;
113374a4d8c2SCharles.Forsyth
113474a4d8c2SCharles.Forsyth ctlr->mb = v;
113574a4d8c2SCharles.Forsyth v += sizeof(Mbox24)*NMbox*2;
113674a4d8c2SCharles.Forsyth
113774a4d8c2SCharles.Forsyth ccb = (Ccb24*)v;
113874a4d8c2SCharles.Forsyth for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
113974a4d8c2SCharles.Forsyth ccbp->ccb = ctlr->ccb;
114074a4d8c2SCharles.Forsyth ctlr->ccb = (Ccb*)ccbp;
114174a4d8c2SCharles.Forsyth }
114274a4d8c2SCharles.Forsyth
114374a4d8c2SCharles.Forsyth /*
114474a4d8c2SCharles.Forsyth * Initialise the software controller and
114574a4d8c2SCharles.Forsyth * set the board scanning the mailboxes.
114674a4d8c2SCharles.Forsyth */
114774a4d8c2SCharles.Forsyth ctlr->mbix = NMbox;
114874a4d8c2SCharles.Forsyth
114974a4d8c2SCharles.Forsyth cmd[0] = Cinitialise;
115074a4d8c2SCharles.Forsyth cmd[1] = NMbox;
115174a4d8c2SCharles.Forsyth p = K2BPA(ctlr->mb, BUSUNKNOWN);
115274a4d8c2SCharles.Forsyth cmd[2] = p>>16;
115374a4d8c2SCharles.Forsyth cmd[3] = p>>8;
115474a4d8c2SCharles.Forsyth cmd[4] = p;
115574a4d8c2SCharles.Forsyth
115674a4d8c2SCharles.Forsyth return issue(ctlr, cmd, 5, 0, 0);
115774a4d8c2SCharles.Forsyth }
115874a4d8c2SCharles.Forsyth
115974a4d8c2SCharles.Forsyth static int
mylex32enable(Ctlr * ctlr)116074a4d8c2SCharles.Forsyth mylex32enable(Ctlr* ctlr)
116174a4d8c2SCharles.Forsyth {
116274a4d8c2SCharles.Forsyth ulong p;
116374a4d8c2SCharles.Forsyth Ccb32 *ccb, *ccbp;
116474a4d8c2SCharles.Forsyth uchar cmd[6], *v;
116574a4d8c2SCharles.Forsyth
116674a4d8c2SCharles.Forsyth v = xspanalloc((sizeof(Mbox32)*NMbox*2)+(sizeof(Ccb32)*NCcb), 32, 0);
116774a4d8c2SCharles.Forsyth
116874a4d8c2SCharles.Forsyth ctlr->mb = v;
116974a4d8c2SCharles.Forsyth v += sizeof(Mbox32)*NMbox*2;
117074a4d8c2SCharles.Forsyth
117174a4d8c2SCharles.Forsyth ccb = (Ccb32*)v;
117274a4d8c2SCharles.Forsyth for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){
117374a4d8c2SCharles.Forsyth /*
117474a4d8c2SCharles.Forsyth * Fill in some stuff that doesn't change.
117574a4d8c2SCharles.Forsyth */
117674a4d8c2SCharles.Forsyth ccbp->senselen = sizeof(ccbp->sense);
117774a4d8c2SCharles.Forsyth p = PADDR(ccbp->sense);
117874a4d8c2SCharles.Forsyth ccbp->senseptr[0] = p;
117974a4d8c2SCharles.Forsyth ccbp->senseptr[1] = p>>8;
118074a4d8c2SCharles.Forsyth ccbp->senseptr[2] = p>>16;
118174a4d8c2SCharles.Forsyth ccbp->senseptr[3] = p>>24;
118274a4d8c2SCharles.Forsyth
118374a4d8c2SCharles.Forsyth ccbp->ccb = ctlr->ccb;
118474a4d8c2SCharles.Forsyth ctlr->ccb = (Ccb*)ccbp;
118574a4d8c2SCharles.Forsyth }
118674a4d8c2SCharles.Forsyth
118774a4d8c2SCharles.Forsyth /*
118874a4d8c2SCharles.Forsyth * Attempt wide mode setup.
118974a4d8c2SCharles.Forsyth */
119074a4d8c2SCharles.Forsyth if(ctlr->wide){
119174a4d8c2SCharles.Forsyth cmd[0] = Cwide;
119274a4d8c2SCharles.Forsyth cmd[1] = 1;
119374a4d8c2SCharles.Forsyth if(!issue(ctlr, cmd, 2, 0, 0))
119474a4d8c2SCharles.Forsyth ctlr->wide = 0;
119574a4d8c2SCharles.Forsyth }
119674a4d8c2SCharles.Forsyth
119774a4d8c2SCharles.Forsyth /*
119874a4d8c2SCharles.Forsyth * Initialise the software controller and
119974a4d8c2SCharles.Forsyth * set the board scanning the mailboxes.
120074a4d8c2SCharles.Forsyth */
120174a4d8c2SCharles.Forsyth ctlr->mbix = NMbox;
120274a4d8c2SCharles.Forsyth
120374a4d8c2SCharles.Forsyth cmd[0] = Ciem;
120474a4d8c2SCharles.Forsyth cmd[1] = NMbox;
120574a4d8c2SCharles.Forsyth if(ctlr->pcidev)
120674a4d8c2SCharles.Forsyth p = K2BPA(ctlr->mb, ctlr->tbdf);
120774a4d8c2SCharles.Forsyth else
120874a4d8c2SCharles.Forsyth p = K2BPA(ctlr->mb, BUSUNKNOWN);
120974a4d8c2SCharles.Forsyth cmd[2] = p;
121074a4d8c2SCharles.Forsyth cmd[3] = p>>8;
121174a4d8c2SCharles.Forsyth cmd[4] = p>>16;
121274a4d8c2SCharles.Forsyth cmd[5] = p>>24;
121374a4d8c2SCharles.Forsyth
121474a4d8c2SCharles.Forsyth return issue(ctlr, cmd, 6, 0, 0);
121574a4d8c2SCharles.Forsyth }
121674a4d8c2SCharles.Forsyth
121774a4d8c2SCharles.Forsyth static int
mylexenable(SDev * sdev)121874a4d8c2SCharles.Forsyth mylexenable(SDev* sdev)
121974a4d8c2SCharles.Forsyth {
122074a4d8c2SCharles.Forsyth int tbdf;
122174a4d8c2SCharles.Forsyth Ctlr *ctlr;
122274a4d8c2SCharles.Forsyth void (*interrupt)(Ureg*, void*);
122374a4d8c2SCharles.Forsyth char name[NAMELEN];
122474a4d8c2SCharles.Forsyth
122574a4d8c2SCharles.Forsyth ctlr = sdev->ctlr;
122674a4d8c2SCharles.Forsyth if(ctlr->cache == nil){
122774a4d8c2SCharles.Forsyth if((ctlr->cache = malloc(sdev->nunit*sizeof(Ccb*))) == nil)
122874a4d8c2SCharles.Forsyth return 0;
122974a4d8c2SCharles.Forsyth }
123074a4d8c2SCharles.Forsyth
123174a4d8c2SCharles.Forsyth tbdf = BUSUNKNOWN;
123274a4d8c2SCharles.Forsyth if(ctlr->bus == 32){
123374a4d8c2SCharles.Forsyth if(ctlr->pcidev){
123474a4d8c2SCharles.Forsyth tbdf = ctlr->pcidev->tbdf;
123574a4d8c2SCharles.Forsyth pcisetbme(ctlr->pcidev);
123674a4d8c2SCharles.Forsyth }
123774a4d8c2SCharles.Forsyth if(!mylex32enable(ctlr))
123874a4d8c2SCharles.Forsyth return 0;
123974a4d8c2SCharles.Forsyth interrupt = mylex32interrupt;
124074a4d8c2SCharles.Forsyth }
124174a4d8c2SCharles.Forsyth else if(mylex24enable(ctlr))
124274a4d8c2SCharles.Forsyth interrupt = mylex24interrupt;
124374a4d8c2SCharles.Forsyth else
124474a4d8c2SCharles.Forsyth return 0;
124574a4d8c2SCharles.Forsyth
124674a4d8c2SCharles.Forsyth snprint(name, NAMELEN, "sd%c (%s)", sdev->idno, sdev->ifc->name);
124774a4d8c2SCharles.Forsyth intrenable(ctlr->irq, interrupt, ctlr, tbdf, name);
124874a4d8c2SCharles.Forsyth
124974a4d8c2SCharles.Forsyth return 1;
125074a4d8c2SCharles.Forsyth }
125174a4d8c2SCharles.Forsyth
125274a4d8c2SCharles.Forsyth static int
mylexdisable(SDev * sdev)125374a4d8c2SCharles.Forsyth mylexdisable(SDev* sdev)
125474a4d8c2SCharles.Forsyth {
125574a4d8c2SCharles.Forsyth Ctlr *ctlr;
125674a4d8c2SCharles.Forsyth int port, timeo;
125774a4d8c2SCharles.Forsyth
125874a4d8c2SCharles.Forsyth ctlr = sdev->ctlr;
125974a4d8c2SCharles.Forsyth port = ctlr->port;
126074a4d8c2SCharles.Forsyth
126174a4d8c2SCharles.Forsyth if(getconf("*noscsireset") != nil)
126274a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rhard);
126374a4d8c2SCharles.Forsyth else
126474a4d8c2SCharles.Forsyth outb(port+Rcontrol, Rhard|Rsbus);
126574a4d8c2SCharles.Forsyth for(timeo = 0; timeo < 100; timeo++){
126674a4d8c2SCharles.Forsyth if(inb(port+Rstatus) == (Inreq|Hardy))
126774a4d8c2SCharles.Forsyth break;
126874a4d8c2SCharles.Forsyth delay(100);
126974a4d8c2SCharles.Forsyth }
127074a4d8c2SCharles.Forsyth if(inb(port+Rstatus) != (Inreq|Hardy))
127174a4d8c2SCharles.Forsyth return 0;
127274a4d8c2SCharles.Forsyth
127374a4d8c2SCharles.Forsyth return 1;
127474a4d8c2SCharles.Forsyth }
127574a4d8c2SCharles.Forsyth
127674a4d8c2SCharles.Forsyth SDifc sdmylexifc = {
127774a4d8c2SCharles.Forsyth "mylex", /* name */
127874a4d8c2SCharles.Forsyth
127974a4d8c2SCharles.Forsyth mylexpnp, /* pnp */
128074a4d8c2SCharles.Forsyth nil, /* legacy */
128174a4d8c2SCharles.Forsyth mylexid, /* id */
128274a4d8c2SCharles.Forsyth mylexenable, /* enable */
128374a4d8c2SCharles.Forsyth mylexdisable, /* disable */
128474a4d8c2SCharles.Forsyth
128574a4d8c2SCharles.Forsyth scsiverify, /* verify */
128674a4d8c2SCharles.Forsyth scsionline, /* online */
128774a4d8c2SCharles.Forsyth mylexrio, /* rio */
128874a4d8c2SCharles.Forsyth nil, /* rctl */
128974a4d8c2SCharles.Forsyth nil, /* wctl */
129074a4d8c2SCharles.Forsyth
129174a4d8c2SCharles.Forsyth scsibio, /* bio */
129274a4d8c2SCharles.Forsyth };
1293