sc->sc_link.openings = 4;
sc->sc_link.openings = 1;
struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, u_long));void bt_queue_ccb __P((struct bt_softc *, struct bt_ccb *));void bt_collect_mbo __P((struct bt_softc *));void bt_start_ccbs __P((struct bt_softc *));void bt_done __P((struct bt_softc *, struct bt_ccb *));int bt_find __P((struct isa_attach_args *, struct bt_softc *));void bt_init __P((struct bt_softc *));void bt_inquire_setup_information __P((struct bt_softc *));void btminphys __P((struct buf *));int bt_scsi_cmd __P((struct scsi_xfer *));int bt_poll __P((struct bt_softc *, struct scsi_xfer *, int));void bt_timeout __P((void *arg));struct scsi_adapter bt_switch = {	bt_scsi_cmd,	btminphys,	0,	0,};/* the below structure is so we have a default dev struct for out link struct */struct scsi_device bt_dev = {	NULL,			/* Use default error handler */	NULL,			/* have a queue, served by this */	NULL,			/* have no async handler */	NULL,			/* Use default 'done' routine */};int	btprobe __P((struct device *, void *, void *));void	btattach __P((struct device *, struct device *, void *));int	btprint __P((void *, char *));struct cfattach btl_ca = {	sizeof(struct bt_softc), btprobe, btattach};struct cfdriver btl_cd = {	NULL, "bt", DV_DULL};#define BT_RESET_TIMEOUT	2000	/* time to wait for reset (mSec) */#define	BT_ABORT_TIMEOUT	2000	/* time to wait for abort (mSec) *//* * bt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf) * * Activate Adapter command *    icnt:   number of args (outbound bytes including opcode) *    ibuf:   argument buffer *    ocnt:   number of expected returned bytes *    obuf:   result buffer *    wait:   number of seconds to wait for response * * Performs an adapter command through the ports.  Not to be confused with a * scsi command, which is read in via the dma; one of the adapter commands * tells it to read in a scsi command. */intbt_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)	int iobase;	struct bt_softc *sc;	int icnt, ocnt;	u_char *ibuf, *obuf;{	const char *name;	register int i;	int wait;	u_char sts;	u_char opcode = ibuf[0];	if (sc != NULL)		name = sc->sc_dev.dv_xname;	else		name = "(bt probe)";	/*	 * Calculate a reasonable timeout for the command.	 */	switch (opcode) {	case BT_INQUIRE_DEVICES:		wait = 15 * 20000;		break;	default:		wait = 1 * 20000;		break;	}	/*	 * Wait for the adapter to go idle, unless it's one of	 * the commands which don't need this	 */	if (opcode != BT_MBO_INTR_EN) {		for (i = 20000; i; i--) {	/* 1 sec? */			sts = isa_inb(iobase + BT_STAT_PORT);			if (sts & BT_STAT_IDLE)				break;			delay(50);		}		if (!i) {			printf("%s: bt_cmd, host not idle(0x%x)\n",			    name, sts);			return ENXIO;		}	}	/*	 * Now that it is idle, if we expect output, preflush the	 * queue feeding to us.	 */	if (ocnt) {		while ((isa_inb(iobase + BT_STAT_PORT)) & BT_STAT_DF)			isa_inb(iobase + BT_DATA_PORT);	}	/*	 * Output the command and the number of arguments given	 * for each byte, first check the port is empty.	 */	while (icnt--) {		for (i = wait; i; i--) {			sts = isa_inb(iobase + BT_STAT_PORT);			if (!(sts & BT_STAT_CDF))				break;			delay(50);		}		if (!i) {			if (opcode != BT_INQUIRE_REVISION &&			    opcode != BT_INQUIRE_REVISION_3)				printf("%s: bt_cmd, cmd/data port full\n", name);			isa_outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST);			return ENXIO;		}		isa_outb(iobase + BT_CMD_PORT, *ibuf++);	}	/*	 * If we expect input, loop that many times, each time,	 * looking for the data register to have valid data	 */	while (ocnt--) {		for (i = wait; i; i--) {			sts = isa_inb(iobase + BT_STAT_PORT);			if (sts & BT_STAT_DF)				break;			delay(50);		}		if (!i) {			if (opcode != BT_INQUIRE_REVISION &&			    opcode != BT_INQUIRE_REVISION_3)				printf("%s: bt_cmd, cmd/data port empty %d\n",				    name, ocnt);			isa_outb(iobase + BT_CTRL_PORT, BT_CTRL_SRST);			return ENXIO;		}		*obuf++ = isa_inb(iobase + BT_DATA_PORT);	}	/*	 * Wait for the board to report a finished instruction.	 * We may get an extra interrupt for the HACC signal, but this is	 * unimportant.	 */	if (opcode != BT_MBO_INTR_EN) {		for (i = 20000; i; i--) {	/* 1 sec? */			sts = isa_inb(iobase + BT_INTR_PORT);			/* XXX Need to save this in the interrupt handler? */			if (sts & BT_INTR_HACC)				break;			delay(50);		}		if (!i) {			printf("%s: bt_cmd, host not finished(0x%x)\n",			    name, sts);			return ENXIO;		}	}	isa_outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST);	return 0;}/* * Check if the device can be found at the port given * and if so, set it up ready for further work * as an argument, takes the isa_device structure from * autoconf.c */intbtprobe(parent, match, aux)	struct device *parent;	void *match, *aux;{	register struct isa_attach_args *ia = aux;#ifdef NEWCONFIG	if (ia->ia_iobase == IOBASEUNK)		return 0;#endif	/* See if there is a unit at this location. */	if (bt_find(ia, NULL) != 0)		return 0;	ia->ia_msize = 0;	ia->ia_iosize = 4;	/* IRQ and DRQ set by bt_find(). */	return 1;}intbtprint(aux, name)	void *aux;	char *name;{	if (name != NULL)		printf("%s: scsibus ", name);	return UNCONF;}/* * Attach all the sub-devices we can find */voidbtattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	struct isa_attach_args *ia = aux;	struct bt_softc *sc = (void *)self;	struct bt_ccb *ccb;	struct bt_buf *buf;	u_int bouncearea;	u_int bouncebase;	u_int bouncesize;	if (bt_find(ia, sc) != 0)		panic("btattach: bt_find of %s failed", self->dv_xname);	sc->sc_iobase = ia->ia_iobase;	/*	 * create mbox area	 */	if (cputype == DESKSTATION_TYNE) {		bouncebase = TYNE_V_BOUNCE;		bouncesize = TYNE_S_BOUNCE;	} else {		bouncesize = TYNE_S_BOUNCE; /* Good enough? XXX */		bouncebase = (u_int) malloc( bouncesize, M_DEVBUF, M_NOWAIT);    }	bouncearea = bouncebase + sizeof(struct bt_mbx);	sc->sc_mbx = (struct bt_mbx *)bouncebase;	bt_inquire_setup_information(sc);	bt_init(sc);	TAILQ_INIT(&sc->sc_free_ccb);	TAILQ_INIT(&sc->sc_free_buf);	TAILQ_INIT(&sc->sc_waiting_ccb);	/*	 * fill up with ccb's	 */	while (sc->sc_numccbs < BT_CCB_MAX) {		ccb = (struct bt_ccb *)bouncearea;		bouncearea +=  sizeof(struct bt_ccb);		bt_init_ccb(sc, ccb);		TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);		sc->sc_numccbs++;	}	/*	 * fill up with bufs's	 */	while ((bouncearea + sizeof(struct bt_buf)) < bouncebase + bouncesize) {		buf = (struct bt_buf *)bouncearea;		bouncearea +=  sizeof(struct bt_buf);		TAILQ_INSERT_HEAD(&sc->sc_free_buf, buf, chain);	}	/*	 * fill in the prototype scsi_link.	 */	sc->sc_link.adapter_softc = sc;	sc->sc_link.adapter_target = sc->sc_scsi_dev;	sc->sc_link.adapter = &bt_switch;	sc->sc_link.device = &bt_dev;	sc->sc_link.openings = 4;#ifdef NEWCONFIG	isa_establish(&sc->sc_id, &sc->sc_dev);#endif	sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,	    IPL_BIO, btintr, sc, sc->sc_dev.dv_xname);	/*	 * ask the adapter what subunits are present	 */	config_found(self, &sc->sc_link, btprint);}integrate voidbt_finish_ccbs(sc)	struct bt_softc *sc;{	struct bt_mbx_in *wmbi;	struct bt_ccb *ccb;	int i;	wmbi = wmbx->tmbi;	if (wmbi->stat == BT_MBI_FREE) {		for (i = 0; i < BT_MBX_SIZE; i++) {			if (wmbi->stat != BT_MBI_FREE) {				printf("%s: mbi not in round-robin order\n",				    sc->sc_dev.dv_xname);				goto AGAIN;			}			bt_nextmbx(wmbi, wmbx, mbi);		}#ifdef BTDIAGnot		printf("%s: mbi interrupt with no full mailboxes\n",		    sc->sc_dev.dv_xname);#endif		return;	}AGAIN:	do {		ccb = bt_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));		if (!ccb) {			printf("%s: bad mbi ccb pointer; skipping\n",			    sc->sc_dev.dv_xname);			goto next;		}#ifdef BTDEBUG		if (bt_debug) {			u_char *cp = &ccb->scsi_cmd;			printf("op=%x %x %x %x %x %x\n",			    cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);			printf("stat %x for mbi addr = 0x%08x, ",			    wmbi->stat, wmbi);			printf("ccb addr = 0x%x\n", ccb);		}#endif /* BTDEBUG */		switch (wmbi->stat) {		case BT_MBI_OK:		case BT_MBI_ERROR:			if ((ccb->flags & CCB_ABORT) != 0) {				/*				 * If we already started an abort, wait for it				 * to complete before clearing the CCB.  We				 * could instead just clear CCB_SENDING, but				 * what if the mailbox was already received?				 * The worst that happens here is that we clear				 * the CCB a bit later than we need to.  BFD.				 */				goto next;			}			break;		case BT_MBI_ABORT:		case BT_MBI_UNKNOWN:			/*			 * Even if the CCB wasn't found, we clear it anyway.			 * See preceeding comment.			 */			break;		default:			printf("%s: bad mbi status %02x; skipping\n",			    sc->sc_dev.dv_xname, wmbi->stat);			goto next;		}		untimeout(bt_timeout, ccb);		bt_done(sc, ccb);	next:		wmbi->stat = BT_MBI_FREE;		bt_nextmbx(wmbi, wmbx, mbi);	} while (wmbi->stat != BT_MBI_FREE);	wmbx->tmbi = wmbi;}/* * Catch an interrupt from the adaptor */intbtintr(arg)	void *arg;{	struct bt_softc *sc = arg;	int iobase = sc->sc_iobase;	u_char sts;#ifdef BTDEBUG	printf("%s: btintr ", sc->sc_dev.dv_xname);#endif /* BTDEBUG */	/*	 * First acknowlege the interrupt, Then if it's not telling about	 * a completed operation just return.	 */	sts = isa_inb(iobase + BT_INTR_PORT);	if ((sts & BT_INTR_ANYINTR) == 0)		return 0;	isa_outb(iobase + BT_CTRL_PORT, BT_CTRL_IRST);#ifdef BTDIAG	/* Make sure we clear CCB_SENDING before finishing a CCB. */	bt_collect_mbo(sc);#endif	/* Mail box out empty? */	if (sts & BT_INTR_MBOA) {		struct bt_toggle toggle;		toggle.cmd.opcode = BT_MBO_INTR_EN;		toggle.cmd.enable = 0;		bt_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0,		    (u_char *)0);		bt_start_ccbs(sc);	}	/* Mail box in full? */	if (sts & BT_INTR_MBIF)		bt_finish_ccbs(sc);	return 1;}integrate voidbt_reset_ccb(sc, ccb)	struct bt_softc *sc;	struct bt_ccb *ccb;{	ccb->flags = 0;}/* * A ccb is put onto the free list. */voidbt_free_ccb(sc, ccb)	struct bt_softc *sc;	struct bt_ccb *ccb;{	int s;	s = splbio();	bt_reset_ccb(sc, ccb);	TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);	/*	 * If there were none, wake anybody waiting for one to come free,	 * starting with queued entries.	 */	if (ccb->chain.tqe_next == 0)		wakeup(&sc->sc_free_ccb);	splx(s);}/* * A buf is put onto the free list. */voidbt_free_buf(sc, buf)	struct bt_softc *sc;	struct bt_buf *buf;{	int s;	s = splbio();	TAILQ_INSERT_HEAD(&sc->sc_free_buf, buf, chain);	/*	 * If there were none, wake anybody waiting for one to come free,	 * starting with queued entries.	 */	if (buf->chain.tqe_next == 0)		wakeup(&sc->sc_free_buf);	splx(s);}integrate voidbt_init_ccb(sc, ccb)	struct bt_softc *sc;	struct bt_ccb *ccb;{	int hashnum;	bzero(ccb, sizeof(struct bt_ccb));	/*	 * put in the phystokv hash table	 * Never gets taken out.	 */	ccb->hashkey = KVTOPHYS(ccb);	hashnum = CCB_HASH(ccb->hashkey);	ccb->nexthash = sc->sc_ccbhash[hashnum];	sc->sc_ccbhash[hashnum] = ccb;	bt_reset_ccb(sc, ccb);}/* * Get a free ccb * * If there are none, either return an error or sleep. */struct bt_ccb *bt_get_ccb(sc, flags)	struct bt_softc *sc;	int flags;{	struct bt_ccb *ccb;	int s;	s = splbio();	/*	 * If we can and have to, sleep waiting for one to come free.	 */	for (;;) {		ccb = sc->sc_free_ccb.tqh_first;		if (ccb) {			TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);			break;		}		if ((flags & SCSI_NOSLEEP) != 0)			goto out;		tsleep(&sc->sc_free_ccb, PRIBIO, "btccb", 0);	}	ccb->flags |= CCB_ALLOC;out:	splx(s);	return ccb;}/* * Get a free buf * * If there are none, either return an error or sleep. */struct bt_buf *bt_get_buf(sc, flags)	struct bt_softc *sc;	int flags;{	struct bt_buf *buf;	int s;	s = splbio();	/*	 * If we can and have to, sleep waiting for one to come free.	 */	for (;;) {		buf = sc->sc_free_buf.tqh_first;		if (buf) {			TAILQ_REMOVE(&sc->sc_free_buf, buf, chain);			break;		}		if ((flags & SCSI_NOSLEEP) != 0)			goto out;		tsleep(&sc->sc_free_buf, PRIBIO, "btbuf", 0);	}out:	splx(s);	return buf;}/* * Given a physical address, find the ccb that it corresponds to. */struct bt_ccb *bt_ccb_phys_kv(sc, ccb_phys)	struct bt_softc *sc;	u_long ccb_phys;{	int hashnum = CCB_HASH(ccb_phys);	struct bt_ccb *ccb = sc->sc_ccbhash[hashnum];	while (ccb) {		if (ccb->hashkey == ccb_phys)			break;		ccb = ccb->nexthash;	}	return ccb;}