ahb.c revision 117126
139219Sgibbs/*
239219Sgibbs * CAM SCSI device driver for the Adaptec 174X SCSI Host adapter
339219Sgibbs *
439219Sgibbs * Copyright (c) 1998 Justin T. Gibbs
539219Sgibbs * All rights reserved.
639219Sgibbs *
739219Sgibbs * Redistribution and use in source and binary forms, with or without
839219Sgibbs * modification, are permitted provided that the following conditions
939219Sgibbs * are met:
1039219Sgibbs * 1. Redistributions of source code must retain the above copyright
1139219Sgibbs *    notice immediately at the beginning of the file, without modification,
1239219Sgibbs *    this list of conditions, and the following disclaimer.
1339219Sgibbs * 2. The name of the author may not be used to endorse or promote products
1439219Sgibbs *    derived from this software without specific prior written permission.
1539219Sgibbs *
1639219Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739219Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839219Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939219Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2039219Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139219Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239219Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339219Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439219Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539219Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639219Sgibbs * SUCH DAMAGE.
2739219Sgibbs *
2850477Speter * $FreeBSD: head/sys/dev/ahb/ahb.c 117126 2003-07-01 15:52:06Z scottl $
2939219Sgibbs */
3039219Sgibbs
3139219Sgibbs#include <sys/param.h>
3239219Sgibbs#include <sys/systm.h>
3339219Sgibbs#include <sys/kernel.h>
3439219Sgibbs#include <sys/malloc.h>
3545791Speter#include <sys/module.h>
36117126Sscottl#include <sys/lock.h>
37117126Sscottl#include <sys/mutex.h>
3845791Speter#include <sys/bus.h>
3939219Sgibbs
4039219Sgibbs#include <machine/bus_pio.h>
4139219Sgibbs#include <machine/bus.h>
4245791Speter#include <machine/resource.h>
4345791Speter#include <sys/rman.h>
4439219Sgibbs
4539219Sgibbs#include <cam/cam.h>
4639219Sgibbs#include <cam/cam_ccb.h>
4739219Sgibbs#include <cam/cam_sim.h>
4839219Sgibbs#include <cam/cam_xpt_sim.h>
4939219Sgibbs#include <cam/cam_debug.h>
5039219Sgibbs
5139219Sgibbs#include <cam/scsi/scsi_message.h>
5239219Sgibbs
5355953Speter#include <dev/eisa/eisaconf.h>
5439219Sgibbs
5555953Speter#include <dev/ahb/ahbreg.h>
5639219Sgibbs
5739219Sgibbs#define ccb_ecb_ptr spriv_ptr0
5839219Sgibbs#define ccb_ahb_ptr spriv_ptr1
5939219Sgibbs
6039219Sgibbs#define ahb_inb(ahb, port)				\
6139219Sgibbs	bus_space_read_1((ahb)->tag, (ahb)->bsh, port)
6239219Sgibbs
6339219Sgibbs#define ahb_inl(ahb, port)				\
6439219Sgibbs	bus_space_read_4((ahb)->tag, (ahb)->bsh, port)
6539219Sgibbs
6639219Sgibbs#define ahb_outb(ahb, port, value)			\
6739219Sgibbs	bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value)
6839219Sgibbs
6939219Sgibbs#define ahb_outl(ahb, port, value)			\
7039219Sgibbs	bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value)
7139219Sgibbs
7239219Sgibbsstatic const char		*ahbmatch(eisa_id_t type);
7356177Snyanstatic struct ahb_softc		*ahballoc(u_long unit, struct resource *res);
7439219Sgibbsstatic void			 ahbfree(struct ahb_softc *ahb);
7539219Sgibbsstatic int			 ahbreset(struct ahb_softc *ahb);
7639219Sgibbsstatic void			 ahbmapecbs(void *arg, bus_dma_segment_t *segs,
7739219Sgibbs					    int nseg, int error);
7839219Sgibbsstatic int			 ahbxptattach(struct ahb_softc *ahb);
7939219Sgibbsstatic void			 ahbhandleimmed(struct ahb_softc *ahb,
8039219Sgibbs						u_int32_t mbox, u_int intstat);
8139219Sgibbsstatic void			 ahbcalcresid(struct ahb_softc *ahb,
8239219Sgibbs					      struct ecb *ecb, union ccb *ccb);
8339219Sgibbsstatic __inline void		 ahbdone(struct ahb_softc *ahb, u_int32_t mbox,
8439219Sgibbs					 u_int intstat);
8539219Sgibbsstatic void			 ahbintr(void *arg);
8639219Sgibbsstatic bus_dmamap_callback_t	 ahbexecuteecb;
8739219Sgibbsstatic void			 ahbaction(struct cam_sim *sim, union ccb *ccb);
8839219Sgibbsstatic void			 ahbpoll(struct cam_sim *sim);
8939219Sgibbs
9039219Sgibbs/* Our timeout handler */
9145967Sgibbsstatic timeout_t ahbtimeout;
9239219Sgibbs
9339219Sgibbsstatic __inline struct ecb*	ahbecbget(struct ahb_softc *ahb);
9439219Sgibbsstatic __inline void	 	ahbecbfree(struct ahb_softc* ahb,
9539219Sgibbs					   struct ecb* ecb);
9639219Sgibbsstatic __inline u_int32_t	ahbecbvtop(struct ahb_softc *ahb,
9739219Sgibbs					   struct ecb *ecb);
9839219Sgibbsstatic __inline struct ecb*	ahbecbptov(struct ahb_softc *ahb,
9939219Sgibbs					   u_int32_t ecb_addr);
10039219Sgibbsstatic __inline u_int32_t	ahbstatuspaddr(u_int32_t ecb_paddr);
10139219Sgibbsstatic __inline u_int32_t	ahbsensepaddr(u_int32_t ecb_paddr);
10239219Sgibbsstatic __inline u_int32_t	ahbsgpaddr(u_int32_t ecb_paddr);
10339219Sgibbsstatic __inline void		ahbqueuembox(struct ahb_softc *ahb,
10439219Sgibbs					     u_int32_t mboxval,
10539219Sgibbs					     u_int attn_code);
10639219Sgibbs
10739219Sgibbsstatic __inline struct ecb*
10839219Sgibbsahbecbget(struct ahb_softc *ahb)
10939219Sgibbs{
11039219Sgibbs	struct	ecb* ecb;
11139219Sgibbs	int	s;
11239219Sgibbs
11339219Sgibbs	s = splcam();
11439219Sgibbs	if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL)
11539219Sgibbs		SLIST_REMOVE_HEAD(&ahb->free_ecbs, links);
11639219Sgibbs	splx(s);
11739219Sgibbs
11839219Sgibbs	return (ecb);
11939219Sgibbs}
12039219Sgibbs
12139219Sgibbsstatic __inline void
12239219Sgibbsahbecbfree(struct ahb_softc* ahb, struct ecb* ecb)
12339219Sgibbs{
12439219Sgibbs	int s;
12539219Sgibbs
12639219Sgibbs	s = splcam();
12739219Sgibbs	ecb->state = ECB_FREE;
12839219Sgibbs	SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links);
12939219Sgibbs	splx(s);
13039219Sgibbs}
13139219Sgibbs
13239219Sgibbsstatic __inline u_int32_t
13339219Sgibbsahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb)
13439219Sgibbs{
13539219Sgibbs	return (ahb->ecb_physbase
13639219Sgibbs	      + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));
13739219Sgibbs}
13839219Sgibbs
13939219Sgibbsstatic __inline struct ecb*
14039219Sgibbsahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr)
14139219Sgibbs{
14239219Sgibbs	return (ahb->ecb_array
14339219Sgibbs	      + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase));
14439219Sgibbs}
14539219Sgibbs
14639219Sgibbsstatic __inline u_int32_t
14739219Sgibbsahbstatuspaddr(u_int32_t ecb_paddr)
14839219Sgibbs{
14939219Sgibbs	return (ecb_paddr + offsetof(struct ecb, status));
15039219Sgibbs}
15139219Sgibbs
15239219Sgibbsstatic __inline u_int32_t
15339219Sgibbsahbsensepaddr(u_int32_t ecb_paddr)
15439219Sgibbs{
15539219Sgibbs	return (ecb_paddr + offsetof(struct ecb, sense));
15639219Sgibbs}
15739219Sgibbs
15839219Sgibbsstatic __inline u_int32_t
15939219Sgibbsahbsgpaddr(u_int32_t ecb_paddr)
16039219Sgibbs{
16139219Sgibbs	return (ecb_paddr + offsetof(struct ecb, sg_list));
16239219Sgibbs}
16339219Sgibbs
16439219Sgibbsstatic __inline void
16539219Sgibbsahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code)
16639219Sgibbs{
16739219Sgibbs	u_int loopmax = 300;
16839219Sgibbs	while (--loopmax) {
16939219Sgibbs		u_int status;
17039219Sgibbs
17139219Sgibbs		status = ahb_inb(ahb, HOSTSTAT);
17243312Sdillon		if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY))
17343316Sgibbs		   == HOSTSTAT_MBOX_EMPTY)
17439219Sgibbs			break;
17539219Sgibbs		DELAY(20);
17639219Sgibbs	}
17739219Sgibbs	if (loopmax == 0)
17839324Sgibbs		panic("ahb%ld: adapter not taking commands\n", ahb->unit);
17939219Sgibbs
18039219Sgibbs	ahb_outl(ahb, MBOXOUT0, mboxval);
18139219Sgibbs	ahb_outb(ahb, ATTN, attn_code);
18239219Sgibbs}
18339219Sgibbs
18439219Sgibbsstatic const char *
18539219Sgibbsahbmatch(eisa_id_t type)
18639219Sgibbs{
18739219Sgibbs	switch(type & 0xfffffe00) {
18839219Sgibbs		case EISA_DEVICE_ID_ADAPTEC_1740:
18939219Sgibbs			return ("Adaptec 174x SCSI host adapter");
19039219Sgibbs			break;
19139219Sgibbs		default:
19239219Sgibbs			break;
19339219Sgibbs	}
19439219Sgibbs	return (NULL);
19539219Sgibbs}
19639219Sgibbs
19739219Sgibbsstatic int
19845791Speterahbprobe(device_t dev)
19939219Sgibbs{
20045791Speter	const char *desc;
20139219Sgibbs	u_int32_t iobase;
20239219Sgibbs	u_int32_t irq;
20345791Speter	u_int8_t  intdef;
20449360Smdodd	int shared;
20539219Sgibbs
20645791Speter	desc = ahbmatch(eisa_get_id(dev));
20745791Speter	if (!desc)
20845791Speter	    return (ENXIO);
20945791Speter	device_set_desc(dev, desc);
21039219Sgibbs
21145791Speter	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) +
21245791Speter	    AHB_EISA_SLOT_OFFSET;
21339219Sgibbs
21445791Speter	eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE);
21539219Sgibbs
21645791Speter	intdef = inb(INTDEF + iobase);
21745791Speter	switch (intdef & 0x7) {
21845791Speter	case INT9:
21945791Speter	    irq = 9;
22045791Speter	    break;
22145791Speter	case INT10:
22245791Speter	    irq = 10;
22345791Speter	    break;
22445791Speter	case INT11:
22545791Speter	    irq = 11;
22645791Speter	    break;
22745791Speter	case INT12:
22845791Speter	    irq = 12;
22945791Speter	    break;
23045791Speter	case INT14:
23145791Speter	    irq = 14;
23245791Speter	    break;
23345791Speter	case INT15:
23445791Speter	    irq = 15;
23545791Speter	    break;
23645791Speter	default:
23745791Speter	    printf("Adaptec 174X at slot %d: illegal "
23845791Speter		   "irq setting %d\n", eisa_get_slot(dev),
23945791Speter		   (intdef & 0x7));
24045791Speter	    irq = 0;
24145791Speter	    break;
24239219Sgibbs	}
24345791Speter	if (irq == 0)
24445791Speter	    return ENXIO;
24545791Speter
24649360Smdodd	shared = (inb(INTDEF + iobase) & INTLEVEL) ?
24749360Smdodd		 EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE;
24845791Speter
24949360Smdodd	eisa_add_intr(dev, irq, shared);
25049360Smdodd
25145791Speter	return 0;
25239219Sgibbs}
25339219Sgibbs
25439219Sgibbsstatic int
25545791Speterahbattach(device_t dev)
25639219Sgibbs{
25739219Sgibbs	/*
25839219Sgibbs	 * find unit and check we have that many defined
25939219Sgibbs	 */
26039219Sgibbs	struct	    ahb_softc *ahb;
26139219Sgibbs	struct	    ecb* next_ecb;
26245791Speter	struct	    resource *io = 0;
26345791Speter	struct	    resource *irq = 0;
26449360Smdodd	int	    rid;
26545791Speter	void	    *ih;
26639219Sgibbs
26745791Speter	rid = 0;
26845791Speter	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
26945791Speter				0, ~0, 1, RF_ACTIVE);
27045791Speter	if (!io) {
27145791Speter		device_printf(dev, "No I/O space?!\n");
27245791Speter		return ENOMEM;
27339219Sgibbs	}
27439219Sgibbs
27556177Snyan	if ((ahb = ahballoc(device_get_unit(dev), io)) == NULL) {
27645791Speter		goto error_exit2;
27739219Sgibbs	}
27839219Sgibbs
27939219Sgibbs	if (ahbreset(ahb) != 0)
28045791Speter		goto error_exit;
28139219Sgibbs
28245791Speter	rid = 0;
28345791Speter	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
28449360Smdodd				 0, ~0, 1, RF_ACTIVE);
28545791Speter	if (!irq) {
28645791Speter		device_printf(dev, "Can't allocate interrupt\n");
28745791Speter		goto error_exit;
28839219Sgibbs	}
28939219Sgibbs
29039219Sgibbs	/*
29139219Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
29261686Salex	 * accessible memory allocations and memory mappings we will
29339219Sgibbs	 * need to perform during normal operation.
29439219Sgibbs	 */
29539219Sgibbs	/* DMA tag for mapping buffers into device visible space. */
29639219Sgibbs	/* XXX Should be a child of the EISA bus dma tag */
297112782Smdodd	if (bus_dma_tag_create(	/* parent	*/ NULL,
298112782Smdodd				/* alignment	*/ 1,
299112782Smdodd				/* boundary	*/ 0,
300112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
301112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
302112782Smdodd				/* filter	*/ NULL,
303112782Smdodd				/* filterarg	*/ NULL,
304112782Smdodd				/* maxsize	*/ MAXBSIZE,
305112782Smdodd				/* nsegments	*/ AHB_NSEG,
306112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
307112782Smdodd				/* flags	*/ BUS_DMA_ALLOCNOW,
308117126Sscottl				/* lockfunc	*/ busdma_lock_mutex,
309117126Sscottl				/* lockarg	*/ &Giant,
310112782Smdodd				&ahb->buffer_dmat) != 0)
31139219Sgibbs		goto error_exit;
31239219Sgibbs
31339219Sgibbs	ahb->init_level++;
31439219Sgibbs
31539219Sgibbs	/* DMA tag for our ccb structures and ha inquiry data */
316112782Smdodd	if (bus_dma_tag_create(	/* parent	*/ NULL,
317112782Smdodd				/* alignment	*/ 1,
318112782Smdodd				/* boundary	*/ 0,
319112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
320112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
321112782Smdodd				/* filter	*/ NULL,
322112782Smdodd				/* filterarg	*/ NULL,
323112782Smdodd				/* maxsize	*/ (AHB_NECB *
324112782Smdodd						    sizeof(struct ecb))
325112782Smdodd						    + sizeof(*ahb->ha_inq_data),
326112782Smdodd				/* nsegments	*/ 1,
327112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
328112782Smdodd				/* flags	*/ 0,
329117126Sscottl				/* lockfunc	*/ busdma_lock_mutex,
330117126Sscottl				/* lockarg	*/ &Giant,
331112782Smdodd				&ahb->ecb_dmat) != 0)
33239219Sgibbs		goto error_exit;
33339219Sgibbs
33439219Sgibbs	ahb->init_level++;
33539219Sgibbs
33639219Sgibbs	/* Allocation for our ccbs */
33739219Sgibbs	if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array,
33839219Sgibbs			     BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0)
33939219Sgibbs		goto error_exit;
34039219Sgibbs
34139219Sgibbs	ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB];
34239219Sgibbs
34339219Sgibbs	ahb->init_level++;
34439219Sgibbs
34539219Sgibbs	/* And permanently map them */
34639219Sgibbs	bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap,
34739219Sgibbs			ahb->ecb_array, AHB_NSEG * sizeof(struct ecb),
34839219Sgibbs			ahbmapecbs, ahb, /*flags*/0);
34939219Sgibbs
35039219Sgibbs	ahb->init_level++;
35139219Sgibbs
35239219Sgibbs	/* Allocate the buffer dmamaps for each of our ECBs */
35339219Sgibbs	bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb))
35439219Sgibbs	      + sizeof(*ahb->ha_inq_data));
35539219Sgibbs	next_ecb = ahb->ecb_array;
35639219Sgibbs	while (ahb->num_ecbs < AHB_NECB) {
35739219Sgibbs		u_int32_t ecb_paddr;
35839219Sgibbs
35939219Sgibbs		if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0,
36039219Sgibbs				      &next_ecb->dmamap))
36139219Sgibbs			break;
36239219Sgibbs		ecb_paddr = ahbecbvtop(ahb, next_ecb);
36339219Sgibbs		next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr);
36439219Sgibbs		next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr);
36539219Sgibbs		ahb->num_ecbs++;
36639219Sgibbs		ahbecbfree(ahb, next_ecb);
36739219Sgibbs		next_ecb++;
36839219Sgibbs	}
36939219Sgibbs
37039219Sgibbs	if (ahb->num_ecbs == 0)
37139219Sgibbs		goto error_exit;
37239219Sgibbs
37339219Sgibbs	ahb->init_level++;
37439219Sgibbs
37539219Sgibbs	/*
37639219Sgibbs	 * Now that we know we own the resources we need, register
37739219Sgibbs	 * our bus with the XPT.
37839219Sgibbs	 */
37939219Sgibbs	if (ahbxptattach(ahb))
38039219Sgibbs		goto error_exit;
38139219Sgibbs
38239219Sgibbs	/* Enable our interrupt */
38373280Smarkm	bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, ahbintr, ahb, &ih);
38439219Sgibbs	return (0);
38545791Speter
38639219Sgibbserror_exit:
38739219Sgibbs	/*
38839219Sgibbs	 * The board's IRQ line will not be left enabled
38939219Sgibbs	 * if we can't intialize correctly, so its safe
39039219Sgibbs	 * to release the irq.
39139219Sgibbs	 */
39239219Sgibbs	ahbfree(ahb);
39345791Spetererror_exit2:
39445791Speter	if (io)
39545791Speter		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
39645791Speter	if (irq)
39745791Speter		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
39839219Sgibbs	return (-1);
39939219Sgibbs}
40039219Sgibbs
40139219Sgibbsstatic struct ahb_softc *
40256177Snyanahballoc(u_long unit, struct resource *res)
40339219Sgibbs{
40439219Sgibbs	struct	ahb_softc *ahb;
40539219Sgibbs
40639219Sgibbs	/*
40739219Sgibbs	 * Allocate a storage area for us
40839219Sgibbs	 */
40967888Sdwmalone	ahb = malloc(sizeof(struct ahb_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
41039219Sgibbs	if (!ahb) {
41139324Sgibbs		printf("ahb%ld: cannot malloc!\n", unit);
41239219Sgibbs		return (NULL);
41339219Sgibbs	}
41439219Sgibbs	SLIST_INIT(&ahb->free_ecbs);
41539219Sgibbs	LIST_INIT(&ahb->pending_ccbs);
41639219Sgibbs	ahb->unit = unit;
41756177Snyan	ahb->tag = rman_get_bustag(res);
41856177Snyan	ahb->bsh = rman_get_bushandle(res);
41939219Sgibbs	ahb->disc_permitted = ~0;
42039219Sgibbs	ahb->tags_permitted = ~0;
42139219Sgibbs
42239219Sgibbs	return (ahb);
42339219Sgibbs}
42439219Sgibbs
42539219Sgibbsstatic void
42639219Sgibbsahbfree(struct ahb_softc *ahb)
42739219Sgibbs{
42839219Sgibbs	switch (ahb->init_level) {
42939219Sgibbs	default:
43039219Sgibbs	case 4:
43139219Sgibbs		bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap);
43239219Sgibbs	case 3:
43339219Sgibbs		bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array,
43439219Sgibbs				ahb->ecb_dmamap);
43539219Sgibbs		bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap);
43639219Sgibbs	case 2:
43739219Sgibbs		bus_dma_tag_destroy(ahb->ecb_dmat);
43839219Sgibbs	case 1:
43939219Sgibbs		bus_dma_tag_destroy(ahb->buffer_dmat);
44039219Sgibbs	case 0:
44197208Speter		break;
44239219Sgibbs	}
44339219Sgibbs	free(ahb, M_DEVBUF);
44439219Sgibbs}
44539219Sgibbs
44639219Sgibbs/*
44739219Sgibbs * reset board, If it doesn't respond, return failure
44839219Sgibbs */
44939219Sgibbsstatic int
45039219Sgibbsahbreset(struct ahb_softc *ahb)
45139219Sgibbs{
45239219Sgibbs	int	wait = 1000;	/* 1 sec enough? */
45339219Sgibbs	int	test;
45439219Sgibbs
45539219Sgibbs	if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {
45639219Sgibbs		printf("ahb_reset: Controller not in enhanced mode\n");
45739219Sgibbs		return (-1);
45839219Sgibbs	}
45939219Sgibbs
46039219Sgibbs	ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);
46139219Sgibbs	DELAY(1000);
46239219Sgibbs	ahb_outb(ahb, CONTROL, 0);
46339219Sgibbs	while (--wait) {
46439219Sgibbs		DELAY(1000);
46539219Sgibbs		if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)
46639219Sgibbs			break;
46739219Sgibbs	}
46839219Sgibbs
46939219Sgibbs	if (wait == 0) {
47039219Sgibbs		printf("ahbreset: No answer from aha1742 board\n");
47139219Sgibbs		return (-1);
47239219Sgibbs	}
47339219Sgibbs	if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {
47439219Sgibbs		printf("ahb_reset: self test failed, val = 0x%x\n", test);
47539219Sgibbs		return (-1);
47639219Sgibbs	}
47739219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
47839219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
47939219Sgibbs		DELAY(10000);
48039219Sgibbs	}
48139219Sgibbs	return (0);
48239219Sgibbs}
48339219Sgibbs
48439219Sgibbsstatic void
48539219Sgibbsahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
48639219Sgibbs{
48739219Sgibbs	struct ahb_softc* ahb;
48839219Sgibbs
48939219Sgibbs	ahb = (struct ahb_softc*)arg;
49039219Sgibbs	ahb->ecb_physbase = segs->ds_addr;
49139219Sgibbs	/*
49239219Sgibbs	 * Space for adapter inquiry information is on the
49339219Sgibbs	 * tail of the ecb array.
49439219Sgibbs	 */
49539219Sgibbs	ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);
49639219Sgibbs}
49739219Sgibbs
49839219Sgibbsstatic int
49939219Sgibbsahbxptattach(struct ahb_softc *ahb)
50039219Sgibbs{
50139219Sgibbs	struct cam_devq *devq;
50239219Sgibbs	struct ecb *ecb;
50339219Sgibbs	u_int  i;
50439219Sgibbs
50539219Sgibbs	/* Remeber who are we on the scsi bus */
50639219Sgibbs	ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;
50739219Sgibbs
50839219Sgibbs	/* Use extended translation?? */
50939219Sgibbs    	ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;
51039219Sgibbs
51139219Sgibbs	/* Fetch adapter inquiry data */
51239219Sgibbs	ecb = ahbecbget(ahb);	/* Always succeeds - no outstanding commands */
51339219Sgibbs	ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;
51439219Sgibbs	ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;
51539219Sgibbs	ecb->hecb.data_ptr = ahb->ha_inq_physbase;
51639219Sgibbs	ecb->hecb.data_len = sizeof(struct ha_inquiry_data);
51739219Sgibbs	ecb->hecb.sense_ptr = 0;
51839219Sgibbs	ecb->state = ECB_ACTIVE;
51939219Sgibbs
52039219Sgibbs	/* Tell the adapter about this command */
52139219Sgibbs	ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),
52239219Sgibbs		     ATTN_STARTECB|ahb->scsi_id);
52339219Sgibbs
52439219Sgibbs	/* Poll for interrupt completion */
52539219Sgibbs	for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {
52639219Sgibbs		ahbintr(ahb);
52739219Sgibbs		DELAY(1000);
52839219Sgibbs	}
52939219Sgibbs
53039219Sgibbs	ahb->num_ecbs = MIN(ahb->num_ecbs,
53139219Sgibbs			    ahb->ha_inq_data->scsi_data.reserved[1]);
53239324Sgibbs	printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",
53339219Sgibbs	       ahb->unit, ahb->ha_inq_data->scsi_data.product,
53439219Sgibbs	       (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"
53539219Sgibbs							 : "Single Ended",
53639219Sgibbs	       ahb->ha_inq_data->scsi_data.revision,
53739219Sgibbs	       ahb->scsi_id, ahb->num_ecbs);
53839219Sgibbs
53939219Sgibbs	/* Restore sense paddr for future CCB clients */
54039219Sgibbs	ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));
54139219Sgibbs
54239219Sgibbs	ahbecbfree(ahb, ecb);
54339219Sgibbs
54439219Sgibbs	/*
54539219Sgibbs	 * Create the device queue for our SIM.
54639219Sgibbs	 */
54739219Sgibbs	devq = cam_simq_alloc(ahb->num_ecbs);
54839219Sgibbs	if (devq == NULL)
54939219Sgibbs		return (ENOMEM);
55039219Sgibbs
55139219Sgibbs	/*
55239219Sgibbs	 * Construct our SIM entry
55339219Sgibbs	 */
55439219Sgibbs	ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit,
55539219Sgibbs				 2, ahb->num_ecbs, devq);
55639219Sgibbs	if (ahb->sim == NULL) {
55739219Sgibbs		cam_simq_free(devq);
55839219Sgibbs		return (ENOMEM);
55939219Sgibbs	}
56039219Sgibbs
56139219Sgibbs	if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) {
56239219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
56339219Sgibbs		return (ENXIO);
56439219Sgibbs	}
56539219Sgibbs
56639219Sgibbs	if (xpt_create_path(&ahb->path, /*periph*/NULL,
56739219Sgibbs			    cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,
56839219Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
56939219Sgibbs		xpt_bus_deregister(cam_sim_path(ahb->sim));
57039219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
57139219Sgibbs		return (ENXIO);
57239219Sgibbs	}
57339219Sgibbs
57439219Sgibbs	/*
57539219Sgibbs	 * Allow the board to generate interrupts.
57639219Sgibbs	 */
57739219Sgibbs	ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);
57839219Sgibbs
57939219Sgibbs	return (0);
58039219Sgibbs}
58139219Sgibbs
58239219Sgibbsstatic void
58339219Sgibbsahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
58439219Sgibbs{
58539219Sgibbs	struct ccb_hdr *ccb_h;
58639219Sgibbs	u_int target_id;
58739219Sgibbs
58839219Sgibbs	if (ahb->immed_cmd == 0) {
58939324Sgibbs		printf("ahb%ld: Immediate Command complete with no "
59039324Sgibbs		       " pending command\n", ahb->unit);
59139219Sgibbs		return;
59239219Sgibbs	}
59339219Sgibbs
59439219Sgibbs	target_id = intstat & INTSTAT_TARGET_MASK;
59539219Sgibbs
59639219Sgibbs	ccb_h = LIST_FIRST(&ahb->pending_ccbs);
59739219Sgibbs	while (ccb_h != NULL) {
59839219Sgibbs		struct ecb *pending_ecb;
59939219Sgibbs		union ccb *ccb;
60039219Sgibbs
60139219Sgibbs		pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
60239219Sgibbs		ccb = pending_ecb->ccb;
60339219Sgibbs		ccb_h = LIST_NEXT(ccb_h, sim_links.le);
60439219Sgibbs		if (ccb->ccb_h.target_id == target_id
60539219Sgibbs		 || target_id == ahb->scsi_id) {
60639219Sgibbs			untimeout(ahbtimeout, pending_ecb,
60739219Sgibbs				  ccb->ccb_h.timeout_ch);
60839219Sgibbs			LIST_REMOVE(&ccb->ccb_h, sim_links.le);
60939219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
61039219Sgibbs				bus_dmamap_unload(ahb->buffer_dmat,
61139219Sgibbs						  pending_ecb->dmamap);
61239219Sgibbs			if (pending_ecb == ahb->immed_ecb)
61339219Sgibbs				ccb->ccb_h.status =
61439219Sgibbs				    CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;
61539219Sgibbs			else if (target_id == ahb->scsi_id)
61639219Sgibbs				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
61739219Sgibbs			else
61839219Sgibbs				ccb->ccb_h.status = CAM_BDR_SENT;
61939219Sgibbs			ahbecbfree(ahb, pending_ecb);
62039219Sgibbs			xpt_done(ccb);
62139219Sgibbs		} else if (ahb->immed_ecb != NULL) {
62239219Sgibbs			/* Re-instate timeout */
62339219Sgibbs			ccb->ccb_h.timeout_ch =
62439219Sgibbs			    timeout(ahbtimeout, (caddr_t)pending_ecb,
62539219Sgibbs				    (ccb->ccb_h.timeout * hz) / 1000);
62639219Sgibbs		}
62739219Sgibbs	}
62839219Sgibbs
62939219Sgibbs	if (ahb->immed_ecb != NULL) {
63039219Sgibbs		ahb->immed_ecb = NULL;
63139324Sgibbs		printf("ahb%ld: No longer in timeout\n", ahb->unit);
63239219Sgibbs	} else if (target_id == ahb->scsi_id)
63339324Sgibbs		printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit);
63439219Sgibbs	else
63539324Sgibbs		printf("ahb%ld:  Bus Device Reset Delibered to target %d\n",
63639219Sgibbs		       ahb->unit, target_id);
63739219Sgibbs
63839219Sgibbs	ahb->immed_cmd = 0;
63939219Sgibbs}
64039219Sgibbs
64139219Sgibbsstatic void
64239219Sgibbsahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
64339219Sgibbs{
64439219Sgibbs	if (ecb->status.data_overrun != 0) {
64539219Sgibbs		/*
64639219Sgibbs		 * Overrun Condition.  The hardware doesn't
64739219Sgibbs		 * provide a meaningful byte count in this case
64839219Sgibbs		 * (the residual is always 0).  Tell the XPT
64939219Sgibbs		 * layer about the error.
65039219Sgibbs		 */
65139219Sgibbs		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
65239219Sgibbs	} else {
65339219Sgibbs		ccb->csio.resid = ecb->status.resid_count;
65439219Sgibbs
65539219Sgibbs		if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {
65639219Sgibbs			/*
65739219Sgibbs			 * For S/G transfers, the adapter provides a pointer
65839219Sgibbs			 * to the address in the last S/G element used and a
65939219Sgibbs			 * residual for that element.  So, we need to sum up
66039219Sgibbs			 * the elements that follow it in order to get a real
66139219Sgibbs			 * residual number.  If we have an overrun, the residual
66239219Sgibbs			 * reported will be 0 and we already know that all S/G
66339219Sgibbs			 * segments have been exhausted, so we can skip this
66439219Sgibbs			 * step.
66539219Sgibbs			 */
66639219Sgibbs			ahb_sg_t *sg;
66739219Sgibbs			int	  num_sg;
66839219Sgibbs
66939219Sgibbs			num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);
67039219Sgibbs
67139219Sgibbs			/* Find the S/G the adapter was working on */
67239219Sgibbs			for (sg = ecb->sg_list;
67339219Sgibbs			     num_sg != 0 && sg->addr != ecb->status.resid_addr;
67439219Sgibbs			     num_sg--, sg++)
67539219Sgibbs				;
67639219Sgibbs
67739219Sgibbs			/* Skip it */
67839219Sgibbs			num_sg--;
67939219Sgibbs			sg++;
68039219Sgibbs
68139219Sgibbs			/* Sum the rest */
68239219Sgibbs			for (; num_sg != 0; num_sg--, sg++)
68339219Sgibbs				ccb->csio.resid += sg->len;
68439219Sgibbs		}
68539219Sgibbs		/* Underruns are not errors */
68639219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
68739219Sgibbs	}
68839219Sgibbs}
68939219Sgibbs
69039219Sgibbsstatic void
69139219Sgibbsahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
69239219Sgibbs{
69339219Sgibbs	struct hardware_ecb *hecb;
69439219Sgibbs	struct ecb_status *status;
69539219Sgibbs
69639219Sgibbs	hecb = &ecb->hecb;
69739219Sgibbs	status = &ecb->status;
69839219Sgibbs	switch (status->ha_status) {
69939219Sgibbs	case HS_OK:
70039219Sgibbs		ccb->csio.scsi_status = status->scsi_status;
70139219Sgibbs		if (status->scsi_status != 0) {
70239219Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
70339219Sgibbs			if (status->sense_stored) {
70439219Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
70539219Sgibbs				ccb->csio.sense_resid =
70639219Sgibbs				    ccb->csio.sense_len - status->sense_len;
70739219Sgibbs				bcopy(&ecb->sense, &ccb->csio.sense_data,
70839219Sgibbs				      status->sense_len);
70939219Sgibbs			}
71039219Sgibbs		}
71139219Sgibbs		break;
71239219Sgibbs	case HS_TARGET_NOT_ASSIGNED:
71339219Sgibbs		ccb->ccb_h.status = CAM_PATH_INVALID;
71439219Sgibbs		break;
71539219Sgibbs	case HS_SEL_TIMEOUT:
71639219Sgibbs		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
71739219Sgibbs		break;
71839219Sgibbs	case HS_DATA_RUN_ERR:
71939219Sgibbs		ahbcalcresid(ahb, ecb, ccb);
72039219Sgibbs		break;
72139219Sgibbs	case HS_UNEXPECTED_BUSFREE:
72239219Sgibbs		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
72339219Sgibbs		break;
72439219Sgibbs	case HS_INVALID_PHASE:
72539219Sgibbs		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
72639219Sgibbs		break;
72739219Sgibbs	case HS_REQUEST_SENSE_FAILED:
72839219Sgibbs		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
72939219Sgibbs		break;
73039219Sgibbs	case HS_TAG_MSG_REJECTED:
73139219Sgibbs	{
73239219Sgibbs		struct ccb_trans_settings neg;
73339219Sgibbs
73439219Sgibbs		xpt_print_path(ccb->ccb_h.path);
73539219Sgibbs		printf("refuses tagged commands.  Performing "
73639219Sgibbs		       "non-tagged I/O\n");
73739219Sgibbs		neg.flags = 0;
73839219Sgibbs		neg.valid = CCB_TRANS_TQ_VALID;
73939219Sgibbs		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
74039219Sgibbs		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
74139219Sgibbs		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
74239219Sgibbs		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
74339219Sgibbs		break;
74439219Sgibbs	}
74539219Sgibbs	case HS_FIRMWARE_LOAD_REQ:
74639219Sgibbs	case HS_HARDWARE_ERR:
74739219Sgibbs		/*
74839219Sgibbs		 * Tell the system that the Adapter
74939219Sgibbs		 * is no longer functional.
75039219Sgibbs		 */
75139219Sgibbs		ccb->ccb_h.status = CAM_NO_HBA;
75239219Sgibbs		break;
75339219Sgibbs	case HS_CMD_ABORTED_HOST:
75439219Sgibbs	case HS_CMD_ABORTED_ADAPTER:
75539219Sgibbs	case HS_ATN_TARGET_FAILED:
75639219Sgibbs	case HS_SCSI_RESET_ADAPTER:
75739219Sgibbs	case HS_SCSI_RESET_INCOMING:
75839219Sgibbs		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
75939219Sgibbs		break;
76049360Smdodd	case HS_INVALID_ECB_PARAM:
76149360Smdodd		printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
76249360Smdodd			ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2);
76349360Smdodd		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
76449360Smdodd		break;
76539219Sgibbs	case HS_DUP_TCB_RECEIVED:
76639219Sgibbs	case HS_INVALID_OPCODE:
76739219Sgibbs	case HS_INVALID_CMD_LINK:
76839219Sgibbs	case HS_PROGRAM_CKSUM_ERROR:
76939324Sgibbs		panic("ahb%ld: Can't happen host status %x occurred",
77039219Sgibbs		      ahb->unit, status->ha_status);
77139219Sgibbs		break;
77239219Sgibbs	}
77339219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
77439219Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
77539219Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
77639219Sgibbs	}
77739219Sgibbs}
77839219Sgibbs
77939219Sgibbsstatic void
78039219Sgibbsahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
78139219Sgibbs{
78239219Sgibbs	struct ecb *ecb;
78339219Sgibbs	union ccb *ccb;
78439219Sgibbs
78539219Sgibbs	ecb = ahbecbptov(ahb, mbox);
78639219Sgibbs
78739219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0)
78839219Sgibbs		panic("ecb not active");
78939219Sgibbs
79039219Sgibbs	ccb = ecb->ccb;
79139219Sgibbs
79239219Sgibbs	if (ccb != NULL) {
79339219Sgibbs		untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch);
79439219Sgibbs		LIST_REMOVE(&ccb->ccb_h, sim_links.le);
79539219Sgibbs
79639219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
797115343Sscottl			bus_dmasync_op_t op;
79839219Sgibbs
79939219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
80039219Sgibbs				op = BUS_DMASYNC_POSTREAD;
80139219Sgibbs			else
80239219Sgibbs				op = BUS_DMASYNC_POSTWRITE;
80339219Sgibbs			bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
80439219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
80539219Sgibbs		}
80639219Sgibbs
80739219Sgibbs		if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {
80839219Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
80939219Sgibbs			ccb->csio.resid = 0;
81039219Sgibbs		} else {
81139219Sgibbs			ahbprocesserror(ahb, ecb, ccb);
81239219Sgibbs		}
81339219Sgibbs		ahbecbfree(ahb, ecb);
81439219Sgibbs		xpt_done(ccb);
81539219Sgibbs	} else {
81639219Sgibbs		/* Non CCB Command */
81739219Sgibbs		if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {
81839324Sgibbs			printf("ahb%ld: Command 0%x Failed %x:%x:%x\n",
81939219Sgibbs			       ahb->unit, ecb->hecb.opcode,
82039219Sgibbs			       *((u_int16_t*)&ecb->status),
82139219Sgibbs			       ecb->status.ha_status, ecb->status.resid_count);
82239219Sgibbs		}
82339219Sgibbs		/* Client owns this ECB and will release it. */
82439219Sgibbs	}
82539219Sgibbs}
82639219Sgibbs
82739219Sgibbs/*
82839219Sgibbs * Catch an interrupt from the adaptor
82939219Sgibbs */
83039219Sgibbsstatic void
83139219Sgibbsahbintr(void *arg)
83239219Sgibbs{
83339219Sgibbs	struct	  ahb_softc *ahb;
83439219Sgibbs	u_int	  intstat;
83539219Sgibbs	u_int32_t mbox;
83639219Sgibbs
83739219Sgibbs	ahb = (struct ahb_softc *)arg;
83839219Sgibbs
83939219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
84039219Sgibbs		/*
84139219Sgibbs		 * Fetch information about this interrupt.
84239219Sgibbs		 */
84339219Sgibbs		intstat = ahb_inb(ahb, INTSTAT);
84439219Sgibbs		mbox = ahb_inl(ahb, MBOXIN0);
84539219Sgibbs
84639219Sgibbs		/*
84739219Sgibbs		 * Reset interrupt latch.
84839219Sgibbs		 */
84939219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
85039219Sgibbs
85139219Sgibbs		/*
85239219Sgibbs		 * Process the completed operation
85339219Sgibbs		 */
85439219Sgibbs		switch (intstat & INTSTAT_MASK) {
85539219Sgibbs		case INTSTAT_ECB_OK:
85639219Sgibbs		case INTSTAT_ECB_CMPWRETRY:
85739219Sgibbs		case INTSTAT_ECB_CMPWERR:
85839219Sgibbs			ahbdone(ahb, mbox, intstat);
85939219Sgibbs			break;
86039219Sgibbs		case INTSTAT_AEN_OCCURED:
86139219Sgibbs			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
86239219Sgibbs				/* Bus Reset */
86339219Sgibbs				xpt_print_path(ahb->path);
86439219Sgibbs				switch (mbox) {
86539219Sgibbs				case HS_SCSI_RESET_ADAPTER:
86639219Sgibbs					printf("Host Adapter Initiated "
86739219Sgibbs					       "Bus Reset occurred\n");
86839219Sgibbs					break;
86939219Sgibbs				case HS_SCSI_RESET_INCOMING:
87039219Sgibbs					printf("Bus Reset Initiated "
87139219Sgibbs					       "by another device occurred\n");
87239219Sgibbs					break;
87339219Sgibbs				}
87439219Sgibbs				/* Notify the XPT */
87539219Sgibbs				xpt_async(AC_BUS_RESET, ahb->path, NULL);
87639219Sgibbs				break;
87739219Sgibbs			}
87839219Sgibbs			printf("Unsupported initiator selection AEN occured\n");
87939219Sgibbs			break;
88039219Sgibbs		case INTSTAT_IMMED_OK:
88139219Sgibbs		case INTSTAT_IMMED_ERR:
88239219Sgibbs			ahbhandleimmed(ahb, mbox, intstat);
88339219Sgibbs			break;
88439219Sgibbs		case INTSTAT_HW_ERR:
88539219Sgibbs			panic("Unrecoverable hardware Error Occurred\n");
88639219Sgibbs		}
88739219Sgibbs	}
88839219Sgibbs}
88939219Sgibbs
89039219Sgibbsstatic void
89139219Sgibbsahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
89239219Sgibbs{
89339219Sgibbs	struct	  ecb *ecb;
89439219Sgibbs	union	  ccb *ccb;
89539219Sgibbs	struct	  ahb_softc *ahb;
89639219Sgibbs	u_int32_t ecb_paddr;
89739219Sgibbs	int	  s;
89839219Sgibbs
89939219Sgibbs	ecb = (struct ecb *)arg;
90039219Sgibbs	ccb = ecb->ccb;
90139219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
90239219Sgibbs
90339219Sgibbs	if (error != 0) {
90439219Sgibbs		if (error != EFBIG)
90539324Sgibbs			printf("ahb%ld: Unexepected error 0x%x returned from "
90639324Sgibbs			       "bus_dmamap_load\n", ahb->unit, error);
90739219Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
90839219Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
90939219Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
91039219Sgibbs		}
91139219Sgibbs		ahbecbfree(ahb, ecb);
91239219Sgibbs		xpt_done(ccb);
91339219Sgibbs		return;
91439219Sgibbs	}
91539219Sgibbs
91639219Sgibbs	ecb_paddr = ahbecbvtop(ahb, ecb);
91739219Sgibbs
91839219Sgibbs	if (nseg != 0) {
91939219Sgibbs		ahb_sg_t *sg;
92039219Sgibbs		bus_dma_segment_t *end_seg;
921115343Sscottl		bus_dmasync_op_t op;
92239219Sgibbs
92339219Sgibbs		end_seg = dm_segs + nseg;
92439219Sgibbs
92539219Sgibbs		/* Copy the segments into our SG list */
92639219Sgibbs		sg = ecb->sg_list;
92739219Sgibbs		while (dm_segs < end_seg) {
92839219Sgibbs			sg->addr = dm_segs->ds_addr;
92939219Sgibbs			sg->len = dm_segs->ds_len;
93039219Sgibbs			sg++;
93139219Sgibbs			dm_segs++;
93239219Sgibbs		}
93339219Sgibbs
93439219Sgibbs		if (nseg > 1) {
93539219Sgibbs			ecb->hecb.flag_word1 |= FW1_SG_ECB;
93639219Sgibbs			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
93739219Sgibbs			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
93839219Sgibbs		} else {
93939219Sgibbs			ecb->hecb.data_ptr = ecb->sg_list->addr;
94039219Sgibbs			ecb->hecb.data_len = ecb->sg_list->len;
94139219Sgibbs		}
94239219Sgibbs
94339219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
94439219Sgibbs/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
94539219Sgibbs			op = BUS_DMASYNC_PREREAD;
94639219Sgibbs		} else {
94739219Sgibbs			op = BUS_DMASYNC_PREWRITE;
94839219Sgibbs		}
94939219Sgibbs		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */
95039219Sgibbs
95139219Sgibbs		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
95239219Sgibbs
95339219Sgibbs	} else {
95439219Sgibbs		ecb->hecb.data_ptr = 0;
95539219Sgibbs		ecb->hecb.data_len = 0;
95639219Sgibbs	}
95739219Sgibbs
95839219Sgibbs	s = splcam();
95939219Sgibbs
96039219Sgibbs	/*
96139219Sgibbs	 * Last time we need to check if this CCB needs to
96239219Sgibbs	 * be aborted.
96339219Sgibbs	 */
96439219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
96539219Sgibbs		if (nseg != 0)
96639219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
96739219Sgibbs		ahbecbfree(ahb, ecb);
96839219Sgibbs		xpt_done(ccb);
96939219Sgibbs		splx(s);
97039219Sgibbs		return;
97139219Sgibbs	}
97239219Sgibbs
97339219Sgibbs	ecb->state = ECB_ACTIVE;
97439219Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
97539219Sgibbs	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);
97639219Sgibbs
97739219Sgibbs	/* Tell the adapter about this command */
97839219Sgibbs	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);
97939219Sgibbs
98039219Sgibbs	ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,
98139219Sgibbs					(ccb->ccb_h.timeout * hz) / 1000);
98239219Sgibbs	splx(s);
98339219Sgibbs}
98439219Sgibbs
98539219Sgibbsstatic void
98639219Sgibbsahbaction(struct cam_sim *sim, union ccb *ccb)
98739219Sgibbs{
98839219Sgibbs	struct	ahb_softc *ahb;
98939219Sgibbs
99039219Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
99139219Sgibbs
99239219Sgibbs	ahb = (struct ahb_softc *)cam_sim_softc(sim);
99339219Sgibbs
99439219Sgibbs	switch (ccb->ccb_h.func_code) {
99539219Sgibbs	/* Common cases first */
99639219Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
99739219Sgibbs	{
99839219Sgibbs		struct ecb *ecb;
99939219Sgibbs		struct hardware_ecb *hecb;
100039219Sgibbs
100139219Sgibbs		/*
100239219Sgibbs		 * get an ecb to use.
100339219Sgibbs		 */
100439219Sgibbs		if ((ecb = ahbecbget(ahb)) == NULL) {
100539219Sgibbs			/* Should never occur */
100639219Sgibbs			panic("Failed to get an ecb");
100739219Sgibbs		}
100839219Sgibbs
100939219Sgibbs		/*
101039219Sgibbs		 * So we can find the ECB when an abort is requested
101139219Sgibbs		 */
101239219Sgibbs		ecb->ccb = ccb;
101339219Sgibbs		ccb->ccb_h.ccb_ecb_ptr = ecb;
101439219Sgibbs		ccb->ccb_h.ccb_ahb_ptr = ahb;
101539219Sgibbs
101639219Sgibbs		/*
101739219Sgibbs		 * Put all the arguments for the xfer in the ecb
101839219Sgibbs		 */
101939219Sgibbs		hecb = &ecb->hecb;
102039219Sgibbs		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
102139219Sgibbs		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
102239219Sgibbs				 | FW1_ERR_STATUS_BLK_ONLY;
102339219Sgibbs		hecb->flag_word2 = ccb->ccb_h.target_lun
102439219Sgibbs				 | FW2_NO_RETRY_ON_BUSY;
102539219Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
102639219Sgibbs			hecb->flag_word2 |= FW2_TAG_ENB
102739219Sgibbs					 | ((ccb->csio.tag_action & 0x3)
102839219Sgibbs					    << FW2_TAG_TYPE_SHIFT);
102939219Sgibbs		}
103039219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
103139219Sgibbs			hecb->flag_word2 |= FW2_DISABLE_DISC;
103239219Sgibbs		hecb->sense_len = ccb->csio.sense_len;
103339219Sgibbs		hecb->cdb_len = ccb->csio.cdb_len;
103439219Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
103539219Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
103639219Sgibbs				bcopy(ccb->csio.cdb_io.cdb_ptr,
103739219Sgibbs				      hecb->cdb, hecb->cdb_len);
103839219Sgibbs			} else {
103939219Sgibbs				/* I guess I could map it in... */
104039219Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
104139219Sgibbs				ahbecbfree(ahb, ecb);
104239219Sgibbs				xpt_done(ccb);
104339219Sgibbs				return;
104439219Sgibbs			}
104539219Sgibbs		} else {
104639219Sgibbs			bcopy(ccb->csio.cdb_io.cdb_bytes,
104739219Sgibbs			      hecb->cdb, hecb->cdb_len);
104839219Sgibbs		}
104939219Sgibbs
105039219Sgibbs		/*
105139219Sgibbs		 * If we have any data to send with this command,
105239219Sgibbs		 * map it into bus space.
105339219Sgibbs		 */
105439219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
105539219Sgibbs			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
105639219Sgibbs				/*
105739219Sgibbs				 * We've been given a pointer
105839219Sgibbs				 * to a single buffer.
105939219Sgibbs				 */
106039219Sgibbs				if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {
106139219Sgibbs					int s;
106239219Sgibbs					int error;
106339219Sgibbs
106439219Sgibbs					s = splsoftvm();
106539219Sgibbs					error = bus_dmamap_load(
106639219Sgibbs					    ahb->buffer_dmat,
106739219Sgibbs					    ecb->dmamap,
106839219Sgibbs					    ccb->csio.data_ptr,
106939219Sgibbs					    ccb->csio.dxfer_len,
107039219Sgibbs					    ahbexecuteecb,
107139219Sgibbs					    ecb, /*flags*/0);
107239219Sgibbs					if (error == EINPROGRESS) {
107339219Sgibbs						/*
107439219Sgibbs						 * So as to maintain ordering,
107539219Sgibbs						 * freeze the controller queue
107639219Sgibbs						 * until our mapping is
107739219Sgibbs						 * returned.
107839219Sgibbs						 */
107939219Sgibbs						xpt_freeze_simq(ahb->sim, 1);
108039219Sgibbs						ccb->ccb_h.status |=
108139219Sgibbs						    CAM_RELEASE_SIMQ;
108239219Sgibbs					}
108339219Sgibbs					splx(s);
108439219Sgibbs				} else {
108539219Sgibbs					struct bus_dma_segment seg;
108639219Sgibbs
108739219Sgibbs					/* Pointer to physical buffer */
108839219Sgibbs					seg.ds_addr =
108939219Sgibbs					    (bus_addr_t)ccb->csio.data_ptr;
109039219Sgibbs					seg.ds_len = ccb->csio.dxfer_len;
109139219Sgibbs					ahbexecuteecb(ecb, &seg, 1, 0);
109239219Sgibbs				}
109339219Sgibbs			} else {
109439219Sgibbs				struct bus_dma_segment *segs;
109539219Sgibbs
109639219Sgibbs				if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
109739219Sgibbs					panic("ahbaction - Physical segment "
109839219Sgibbs					      "pointers unsupported");
109939219Sgibbs
110039219Sgibbs				if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
110139219Sgibbs					panic("btaction - Virtual segment "
110239219Sgibbs					      "addresses unsupported");
110339219Sgibbs
110439219Sgibbs				/* Just use the segments provided */
110539219Sgibbs				segs = (struct bus_dma_segment *)
110639219Sgibbs				    ccb->csio.data_ptr;
110739219Sgibbs				ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,
110839219Sgibbs					     0);
110939219Sgibbs			}
111039219Sgibbs		} else {
111139219Sgibbs			ahbexecuteecb(ecb, NULL, 0, 0);
111239219Sgibbs		}
111339219Sgibbs		break;
111439219Sgibbs	}
111539219Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
111639219Sgibbs	case XPT_TARGET_IO:		/* Execute target I/O request */
111739219Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
111839219Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
111939219Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
112039219Sgibbs		/* XXX Implement */
112139219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
112239219Sgibbs		xpt_done(ccb);
112339219Sgibbs		break;
112439219Sgibbs	case XPT_SET_TRAN_SETTINGS:
112539219Sgibbs	{
112639219Sgibbs		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
112739219Sgibbs		xpt_done(ccb);
112839219Sgibbs		break;
112939219Sgibbs	}
113039219Sgibbs	case XPT_GET_TRAN_SETTINGS:
113139219Sgibbs	/* Get default/user set transfer settings for the target */
113239219Sgibbs	{
113339219Sgibbs		struct	ccb_trans_settings *cts;
113439219Sgibbs		u_int	target_mask;
113539219Sgibbs
113639219Sgibbs		cts = &ccb->cts;
113739219Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
113839219Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
113939219Sgibbs			cts->flags = 0;
114039219Sgibbs			if ((ahb->disc_permitted & target_mask) != 0)
114139219Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
114239219Sgibbs			if ((ahb->tags_permitted & target_mask) != 0)
114339219Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
114439219Sgibbs			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
114539219Sgibbs			cts->sync_period = 25; /* 10MHz */
114639219Sgibbs
114739219Sgibbs			if (cts->sync_period != 0)
114839219Sgibbs				cts->sync_offset = 15;
114939219Sgibbs
115039219Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
115139219Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
115239219Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
115339219Sgibbs				   | CCB_TRANS_DISC_VALID
115439219Sgibbs				   | CCB_TRANS_TQ_VALID;
115539219Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
115639219Sgibbs		} else {
115739219Sgibbs			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
115839219Sgibbs		}
115939219Sgibbs		xpt_done(ccb);
116039219Sgibbs		break;
116139219Sgibbs	}
116239219Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
116339219Sgibbs	{
116439219Sgibbs		int i;
116544508Sgibbs		int s;
116639219Sgibbs
116744508Sgibbs		s = splcam();
116839219Sgibbs		ahb->immed_cmd = IMMED_RESET;
116939219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
117039219Sgibbs		/* Poll for interrupt completion */
117144508Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
117239219Sgibbs			DELAY(1000);
117344508Sgibbs			ahbintr(cam_sim_softc(sim));
117444508Sgibbs		}
117544508Sgibbs		splx(s);
117639219Sgibbs		break;
117739219Sgibbs	}
117839219Sgibbs	case XPT_CALC_GEOMETRY:
117939219Sgibbs	{
1180116351Snjl		cam_calc_geometry(&ccb->ccg, ahb->extended_trans);
118139219Sgibbs		xpt_done(ccb);
118239219Sgibbs		break;
118339219Sgibbs	}
118439219Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
118539219Sgibbs	{
118639219Sgibbs		int i;
118739219Sgibbs
118839219Sgibbs		ahb->immed_cmd = IMMED_RESET;
118939219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
119039219Sgibbs		/* Poll for interrupt completion */
119139219Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
119239219Sgibbs			DELAY(1000);
119339219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
119439219Sgibbs		xpt_done(ccb);
119539219Sgibbs		break;
119639219Sgibbs	}
119739219Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
119839219Sgibbs		/* XXX Implement */
119939219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
120039219Sgibbs		xpt_done(ccb);
120139219Sgibbs		break;
120239219Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
120339219Sgibbs	{
120439219Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
120539219Sgibbs
120639219Sgibbs		cpi->version_num = 1; /* XXX??? */
120739219Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
120839219Sgibbs		cpi->target_sprt = 0;
120939219Sgibbs		cpi->hba_misc = 0;
121039219Sgibbs		cpi->hba_eng_cnt = 0;
121139219Sgibbs		cpi->max_target = 7;
121239219Sgibbs		cpi->max_lun = 7;
121339219Sgibbs		cpi->initiator_id = ahb->scsi_id;
121439219Sgibbs		cpi->bus_id = cam_sim_bus(sim);
121546581Sken		cpi->base_transfer_speed = 3300;
121639219Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
121739219Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
121839219Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
121939219Sgibbs		cpi->unit_number = cam_sim_unit(sim);
122039219Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
122139219Sgibbs		xpt_done(ccb);
122239219Sgibbs		break;
122339219Sgibbs	}
122439219Sgibbs#if 0
122539219Sgibbs	/* Need these??? */
122639219Sgibbs        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */
122739219Sgibbs        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */
122839219Sgibbs#endif
122939219Sgibbs	default:
123039219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
123139219Sgibbs		xpt_done(ccb);
123239219Sgibbs		break;
123339219Sgibbs	}
123439219Sgibbs}
123539219Sgibbs
123639219Sgibbsstatic void
123739219Sgibbsahbpoll(struct cam_sim *sim)
123839219Sgibbs{
123940132Sgibbs	ahbintr(cam_sim_softc(sim));
124039219Sgibbs}
124139219Sgibbs
124245577Seivindstatic void
124339219Sgibbsahbtimeout(void *arg)
124439219Sgibbs{
124539219Sgibbs	struct ecb	 *ecb;
124639219Sgibbs	union  ccb	 *ccb;
124739219Sgibbs	struct ahb_softc *ahb;
124839219Sgibbs	int		  s;
124939219Sgibbs
125039219Sgibbs	ecb = (struct ecb *)arg;
125139219Sgibbs	ccb = ecb->ccb;
125239219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
125339219Sgibbs	xpt_print_path(ccb->ccb_h.path);
125439390Sgibbs	printf("ECB %p - timed out\n", (void *)ecb);
125539219Sgibbs
125639219Sgibbs	s = splcam();
125739219Sgibbs
125839219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0) {
125939219Sgibbs		xpt_print_path(ccb->ccb_h.path);
126039390Sgibbs		printf("ECB %p - timed out ECB already completed\n",
126139390Sgibbs		       (void *)ecb);
126239219Sgibbs		splx(s);
126339219Sgibbs		return;
126439219Sgibbs	}
126539219Sgibbs	/*
126639219Sgibbs	 * In order to simplify the recovery process, we ask the XPT
126739219Sgibbs	 * layer to halt the queue of new transactions and we traverse
126839219Sgibbs	 * the list of pending CCBs and remove their timeouts. This
126939219Sgibbs	 * means that the driver attempts to clear only one error
127039219Sgibbs	 * condition at a time.  In general, timeouts that occur
127139219Sgibbs	 * close together are related anyway, so there is no benefit
127239219Sgibbs	 * in attempting to handle errors in parrallel.  Timeouts will
127339219Sgibbs	 * be reinstated when the recovery process ends.
127439219Sgibbs	 */
127539219Sgibbs	if ((ecb->state & ECB_DEVICE_RESET) == 0) {
127639219Sgibbs		struct ccb_hdr *ccb_h;
127739219Sgibbs
127839219Sgibbs		if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {
127939219Sgibbs			xpt_freeze_simq(ahb->sim, /*count*/1);
128039219Sgibbs			ecb->state |= ECB_RELEASE_SIMQ;
128139219Sgibbs		}
128239219Sgibbs
128339219Sgibbs		ccb_h = LIST_FIRST(&ahb->pending_ccbs);
128439219Sgibbs		while (ccb_h != NULL) {
128539219Sgibbs			struct ecb *pending_ecb;
128639219Sgibbs
128739219Sgibbs			pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
128839219Sgibbs			untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch);
128939219Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
129039219Sgibbs		}
129139219Sgibbs
129239219Sgibbs		/* Store for our interrupt handler */
129339219Sgibbs		ahb->immed_ecb = ecb;
129439219Sgibbs
129539219Sgibbs		/*
129639219Sgibbs		 * Send a Bus Device Reset message:
129739219Sgibbs		 * The target that is holding up the bus may not
129839219Sgibbs		 * be the same as the one that triggered this timeout
129939219Sgibbs		 * (different commands have different timeout lengths),
130039219Sgibbs		 * but we have no way of determining this from our
130139219Sgibbs		 * timeout handler.  Our strategy here is to queue a
130239219Sgibbs		 * BDR message to the target of the timed out command.
130339219Sgibbs		 * If this fails, we'll get another timeout 2 seconds
130439219Sgibbs		 * later which will attempt a bus reset.
130539219Sgibbs		 */
130639219Sgibbs		xpt_print_path(ccb->ccb_h.path);
130739324Sgibbs		printf("Queuing BDR\n");
130839219Sgibbs		ecb->state |= ECB_DEVICE_RESET;
130939219Sgibbs		ccb->ccb_h.timeout_ch =
131039219Sgibbs		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
131139219Sgibbs
131239219Sgibbs		ahb->immed_cmd = IMMED_RESET;
131339219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
131439219Sgibbs	} else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {
131539219Sgibbs		/*
131639219Sgibbs		 * Try a SCSI bus reset.  We do this only if we
131739219Sgibbs		 * have already attempted to clear the condition with a BDR.
131839219Sgibbs		 */
131939219Sgibbs		xpt_print_path(ccb->ccb_h.path);
132039324Sgibbs		printf("Attempting SCSI Bus reset\n");
132139219Sgibbs		ecb->state |= ECB_SCSIBUS_RESET;
132239219Sgibbs		ccb->ccb_h.timeout_ch =
132339219Sgibbs		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
132439219Sgibbs		ahb->immed_cmd = IMMED_RESET;
132539219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
132639219Sgibbs	} else {
132739219Sgibbs		/* Bring out the hammer... */
132839219Sgibbs		ahbreset(ahb);
132939219Sgibbs
133039219Sgibbs		/* Simulate the reset complete interrupt */
133139219Sgibbs		ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);
133239219Sgibbs	}
133339219Sgibbs
133439219Sgibbs	splx(s);
133539219Sgibbs}
133639219Sgibbs
133745791Speterstatic device_method_t ahb_eisa_methods[] = {
133845791Speter	/* Device interface */
133945791Speter	DEVMETHOD(device_probe,		ahbprobe),
134045791Speter	DEVMETHOD(device_attach,	ahbattach),
134145791Speter
134245791Speter	{ 0, 0 }
134345791Speter};
134445791Speter
134545791Speterstatic driver_t ahb_eisa_driver = {
134645791Speter	"ahb",
134745791Speter	ahb_eisa_methods,
134845791Speter	1,			/* unused */
134945791Speter};
135045791Speter
135145791Speterstatic devclass_t ahb_devclass;
135245791Speter
135345791SpeterDRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0);
1354