isadma_copyfrombuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
struct aha_ccb *aha_ccb_phys_kv __P((struct aha_softc *, u_long));void aha_queue_ccb __P((struct aha_softc *, struct aha_ccb *));void aha_collect_mbo __P((struct aha_softc *));void aha_start_ccbs __P((struct aha_softc *));void aha_done __P((struct aha_softc *, struct aha_ccb *));int aha_find __P((struct isa_attach_args *, struct aha_softc *));void aha_init __P((struct aha_softc *));void aha_inquire_setup_information __P((struct aha_softc *));void ahaminphys __P((struct buf *));int aha_scsi_cmd __P((struct scsi_xfer *));int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int));void aha_timeout __P((void *arg));struct scsi_adapter aha_switch = {	aha_scsi_cmd,	ahaminphys,	0,	0,};/* the below structure is so we have a default dev struct for out link struct */struct scsi_device aha_dev = {	NULL,			/* Use default error handler */	NULL,			/* have a queue, served by this */	NULL,			/* have no async handler */	NULL,			/* Use default 'done' routine */};int	ahaprobe __P((struct device *, void *, void *));void	ahaattach __P((struct device *, struct device *, void *));int	ahaprint __P((void *, char *));struct cfattach aha_ca = {	sizeof(struct aha_softc), ahaprobe, ahaattach};struct cfdriver aha_cd = {	NULL, "aha", DV_DULL};#define AHA_RESET_TIMEOUT	2000	/* time to wait for reset (mSec) */#define	AHA_ABORT_TIMEOUT	2000	/* time to wait for abort (mSec) */#include "bt.h"/* * aha_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. */intaha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)	int iobase;	struct aha_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 = "(aha probe)";	/*	 * Calculate a reasonable timeout for the command.	 */	switch (opcode) {	case AHA_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 != AHA_MBO_INTR_EN) {		for (i = 20000; i; i--) {	/* 1 sec? */			sts = inb(iobase + AHA_STAT_PORT);			if (sts & AHA_STAT_IDLE)				break;			delay(50);		}		if (!i) {			printf("%s: aha_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 ((inb(iobase + AHA_STAT_PORT)) & AHA_STAT_DF)			inb(iobase + AHA_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 = inb(iobase + AHA_STAT_PORT);			if (!(sts & AHA_STAT_CDF))				break;			delay(50);		}		if (!i) {			if (opcode != AHA_INQUIRE_REVISION)				printf("%s: aha_cmd, cmd/data port full\n", name);			outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);			return ENXIO;		}		outb(iobase + AHA_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 = inb(iobase + AHA_STAT_PORT);			if (sts & AHA_STAT_DF)				break;			delay(50);		}		if (!i) {			if (opcode != AHA_INQUIRE_REVISION)				printf("%s: aha_cmd, cmd/data port empty %d\n",				    name, ocnt);			outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);			return ENXIO;		}		*obuf++ = inb(iobase + AHA_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 != AHA_MBO_INTR_EN) {		for (i = 20000; i; i--) {	/* 1 sec? */			sts = inb(iobase + AHA_INTR_PORT);			/* XXX Need to save this in the interrupt handler? */			if (sts & AHA_INTR_HACC)				break;			delay(50);		}		if (!i) {			printf("%s: aha_cmd, host not finished(0x%x)\n",			    name, sts);			return ENXIO;		}	}	outb(iobase + AHA_CTRL_PORT, AHA_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 */intahaprobe(parent, match, aux)	struct device *parent;	void *match, *aux;{	register struct isa_attach_args *ia = aux;#if NBT > 0	extern int btports[], nbtports;	int i;	for (i = 0; i < nbtports; i++)		if (btports[i] == ia->ia_iobase)			return 0;#endif#ifdef NEWCONFIG	if (ia->ia_iobase == IOBASEUNK)		return 0;#endif	/* See if there is a unit at this location. */	if (aha_find(ia, NULL) != 0)		return 0;	ia->ia_msize = 0;	ia->ia_iosize = 4;	/* IRQ and DRQ set by aha_find(). */	return 1;}intahaprint(aux, name)	void *aux;	char *name;{	if (name != NULL)		printf("%s: scsibus ", name);	return UNCONF;}/* * Attach all the sub-devices we can find */voidahaattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	struct isa_attach_args *ia = aux;	struct aha_softc *sc = (void *)self;	if (aha_find(ia, sc) != 0)		panic("ahaattach: aha_find of %s failed", self->dv_xname);	sc->sc_iobase = ia->ia_iobase;	if (sc->sc_drq != DRQUNK)		isadma_cascade(sc->sc_drq);	aha_inquire_setup_information(sc);	aha_init(sc);	TAILQ_INIT(&sc->sc_free_ccb);	TAILQ_INIT(&sc->sc_waiting_ccb);	/*	 * 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 = &aha_switch;	sc->sc_link.device = &aha_dev;	sc->sc_link.openings = 2;#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, ahaintr, sc, sc->sc_dev.dv_xname);	/*	 * ask the adapter what subunits are present	 */	config_found(self, &sc->sc_link, ahaprint);}integrate voidaha_finish_ccbs(sc)	struct aha_softc *sc;{	struct aha_mbx_in *wmbi;	struct aha_ccb *ccb;	int i;	wmbi = wmbx->tmbi;	if (wmbi->stat == AHA_MBI_FREE) {		for (i = 0; i < AHA_MBX_SIZE; i++) {			if (wmbi->stat != AHA_MBI_FREE) {				printf("%s: mbi not in round-robin order\n",				    sc->sc_dev.dv_xname);				goto AGAIN;			}			aha_nextmbx(wmbi, wmbx, mbi);		}#ifdef AHADIAGnot		printf("%s: mbi interrupt with no full mailboxes\n",		    sc->sc_dev.dv_xname);#endif		return;	}AGAIN:	do {		ccb = aha_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 AHADEBUG		if (aha_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 /* AHADEBUG */		switch (wmbi->stat) {		case AHA_MBI_OK:		case AHA_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 AHA_MBI_ABORT:		case AHA_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(aha_timeout, ccb);		aha_done(sc, ccb);	next:		wmbi->stat = AHA_MBI_FREE;		aha_nextmbx(wmbi, wmbx, mbi);	} while (wmbi->stat != AHA_MBI_FREE);	wmbx->tmbi = wmbi;}/* * Catch an interrupt from the adaptor */intahaintr(arg)	void *arg;{	struct aha_softc *sc = arg;	int iobase = sc->sc_iobase;	u_char sts;#ifdef AHADEBUG	printf("%s: ahaintr ", sc->sc_dev.dv_xname);#endif /*AHADEBUG */	/*	 * First acknowlege the interrupt, Then if it's not telling about	 * a completed operation just return.	 */	sts = inb(iobase + AHA_INTR_PORT);	if ((sts & AHA_INTR_ANYINTR) == 0)		return 0;	outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);#ifdef AHADIAG	/* Make sure we clear CCB_SENDING before finishing a CCB. */	aha_collect_mbo(sc);#endif	/* Mail box out empty? */	if (sts & AHA_INTR_MBOA) {		struct aha_toggle toggle;		toggle.cmd.opcode = AHA_MBO_INTR_EN;		toggle.cmd.enable = 0;		aha_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0,		    (u_char *)0);		aha_start_ccbs(sc);	}	/* Mail box in full? */	if (sts & AHA_INTR_MBIF)		aha_finish_ccbs(sc);	return 1;}integrate voidaha_reset_ccb(sc, ccb)	struct aha_softc *sc;	struct aha_ccb *ccb;{	ccb->flags = 0;}/* * A ccb is put onto the free list. */voidaha_free_ccb(sc, ccb)	struct aha_softc *sc;	struct aha_ccb *ccb;{	int s, hashnum;	struct aha_ccb **hashccb;	s = splbio();	if (ccb->ccb_phys[0].addr)	        isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);	/* remove from hash table */	hashnum = CCB_HASH(ccb->ccb_phys[0].addr);	hashccb = &sc->sc_ccbhash[hashnum];	while (*hashccb) {		if ((*hashccb)->ccb_phys[0].addr == ccb->ccb_phys[0].addr) {			*hashccb = (*hashccb)->nexthash;			break;		}		hashccb = &(*hashccb)->nexthash;	}	aha_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);}integrate voidaha_init_ccb(sc, ccb)	struct aha_softc *sc;	struct aha_ccb *ccb;{	bzero(ccb, sizeof(struct aha_ccb));	aha_reset_ccb(sc, ccb);}/* * Get a free ccb * * If there are none, see if we can allocate a new one.  If so, put it in * the hash table too otherwise either return an error or sleep. */struct aha_ccb *aha_get_ccb(sc, flags)	struct aha_softc *sc;	int flags;{	struct aha_ccb *ccb;	int hashnum, mflags, s;	s = splbio();	if (flags & SCSI_NOSLEEP)		mflags = ISADMA_MAP_BOUNCE;	else		mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;	/*	 * If we can and have to, sleep waiting for one to come free	 * but only if we can't allocate a new one.	 */	for (;;) {		ccb = sc->sc_free_ccb.tqh_first;		if (ccb) {			TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);			break;		}		if (sc->sc_numccbs < AHA_CCB_MAX) {			ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb),			    M_TEMP, M_NOWAIT);			if (!ccb) {				printf("%s: can't malloc ccb\n",				    sc->sc_dev.dv_xname);				goto out;			}			aha_init_ccb(sc, ccb);			sc->sc_numccbs++;			break;		}		if ((flags & SCSI_NOSLEEP) != 0)			goto out;		tsleep(&sc->sc_free_ccb, PRIBIO, "ahaccb", 0);	}	ccb->flags |= CCB_ALLOC;	if (isadma_map((caddr_t)ccb, CCB_PHYS_SIZE, ccb->ccb_phys,	    mflags | ISADMA_MAP_CONTIG) == 1) {		hashnum = CCB_HASH(ccb->ccb_phys[0].addr);		ccb->nexthash = sc->sc_ccbhash[hashnum];		sc->sc_ccbhash[hashnum] = ccb;	} else {		ccb->ccb_phys[0].addr = 0;		aha_free_ccb(sc, ccb);		ccb = 0;	}out:	splx(s);	return (ccb);}/* * Given a physical address, find the ccb that it corresponds to. */struct aha_ccb *aha_ccb_phys_kv(sc, ccb_phys)	struct aha_softc *sc;	u_long ccb_phys;{	int hashnum = CCB_HASH(ccb_phys);	struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];	while (ccb) {		if (ccb->ccb_phys[0].addr == ccb_phys)			break;		ccb = ccb->nexthash;	}	return ccb;}