xref: /inferno-os/os/boot/pc/sdmylex.c (revision 8a8c2d742b51525f66c2210e3c8a251de10022ff)
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