ahb.c revision 115343
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 115343 2003-05-27 04:59:59Z 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>
3645791Speter#include <sys/bus.h>
3739219Sgibbs
3839219Sgibbs#include <machine/bus_pio.h>
3939219Sgibbs#include <machine/bus.h>
4045791Speter#include <machine/resource.h>
4145791Speter#include <sys/rman.h>
4239219Sgibbs
4339219Sgibbs#include <cam/cam.h>
4439219Sgibbs#include <cam/cam_ccb.h>
4539219Sgibbs#include <cam/cam_sim.h>
4639219Sgibbs#include <cam/cam_xpt_sim.h>
4739219Sgibbs#include <cam/cam_debug.h>
4839219Sgibbs
4939219Sgibbs#include <cam/scsi/scsi_message.h>
5039219Sgibbs
5155953Speter#include <dev/eisa/eisaconf.h>
5239219Sgibbs
5355953Speter#include <dev/ahb/ahbreg.h>
5439219Sgibbs
5539219Sgibbs#define ccb_ecb_ptr spriv_ptr0
5639219Sgibbs#define ccb_ahb_ptr spriv_ptr1
5739219Sgibbs
5839219Sgibbs#define ahb_inb(ahb, port)				\
5939219Sgibbs	bus_space_read_1((ahb)->tag, (ahb)->bsh, port)
6039219Sgibbs
6139219Sgibbs#define ahb_inl(ahb, port)				\
6239219Sgibbs	bus_space_read_4((ahb)->tag, (ahb)->bsh, port)
6339219Sgibbs
6439219Sgibbs#define ahb_outb(ahb, port, value)			\
6539219Sgibbs	bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value)
6639219Sgibbs
6739219Sgibbs#define ahb_outl(ahb, port, value)			\
6839219Sgibbs	bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value)
6939219Sgibbs
7039219Sgibbsstatic const char		*ahbmatch(eisa_id_t type);
7156177Snyanstatic struct ahb_softc		*ahballoc(u_long unit, struct resource *res);
7239219Sgibbsstatic void			 ahbfree(struct ahb_softc *ahb);
7339219Sgibbsstatic int			 ahbreset(struct ahb_softc *ahb);
7439219Sgibbsstatic void			 ahbmapecbs(void *arg, bus_dma_segment_t *segs,
7539219Sgibbs					    int nseg, int error);
7639219Sgibbsstatic int			 ahbxptattach(struct ahb_softc *ahb);
7739219Sgibbsstatic void			 ahbhandleimmed(struct ahb_softc *ahb,
7839219Sgibbs						u_int32_t mbox, u_int intstat);
7939219Sgibbsstatic void			 ahbcalcresid(struct ahb_softc *ahb,
8039219Sgibbs					      struct ecb *ecb, union ccb *ccb);
8139219Sgibbsstatic __inline void		 ahbdone(struct ahb_softc *ahb, u_int32_t mbox,
8239219Sgibbs					 u_int intstat);
8339219Sgibbsstatic void			 ahbintr(void *arg);
8439219Sgibbsstatic bus_dmamap_callback_t	 ahbexecuteecb;
8539219Sgibbsstatic void			 ahbaction(struct cam_sim *sim, union ccb *ccb);
8639219Sgibbsstatic void			 ahbpoll(struct cam_sim *sim);
8739219Sgibbs
8839219Sgibbs/* Our timeout handler */
8945967Sgibbsstatic timeout_t ahbtimeout;
9039219Sgibbs
9139219Sgibbsstatic __inline struct ecb*	ahbecbget(struct ahb_softc *ahb);
9239219Sgibbsstatic __inline void	 	ahbecbfree(struct ahb_softc* ahb,
9339219Sgibbs					   struct ecb* ecb);
9439219Sgibbsstatic __inline u_int32_t	ahbecbvtop(struct ahb_softc *ahb,
9539219Sgibbs					   struct ecb *ecb);
9639219Sgibbsstatic __inline struct ecb*	ahbecbptov(struct ahb_softc *ahb,
9739219Sgibbs					   u_int32_t ecb_addr);
9839219Sgibbsstatic __inline u_int32_t	ahbstatuspaddr(u_int32_t ecb_paddr);
9939219Sgibbsstatic __inline u_int32_t	ahbsensepaddr(u_int32_t ecb_paddr);
10039219Sgibbsstatic __inline u_int32_t	ahbsgpaddr(u_int32_t ecb_paddr);
10139219Sgibbsstatic __inline void		ahbqueuembox(struct ahb_softc *ahb,
10239219Sgibbs					     u_int32_t mboxval,
10339219Sgibbs					     u_int attn_code);
10439219Sgibbs
10539219Sgibbsstatic __inline struct ecb*
10639219Sgibbsahbecbget(struct ahb_softc *ahb)
10739219Sgibbs{
10839219Sgibbs	struct	ecb* ecb;
10939219Sgibbs	int	s;
11039219Sgibbs
11139219Sgibbs	s = splcam();
11239219Sgibbs	if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL)
11339219Sgibbs		SLIST_REMOVE_HEAD(&ahb->free_ecbs, links);
11439219Sgibbs	splx(s);
11539219Sgibbs
11639219Sgibbs	return (ecb);
11739219Sgibbs}
11839219Sgibbs
11939219Sgibbsstatic __inline void
12039219Sgibbsahbecbfree(struct ahb_softc* ahb, struct ecb* ecb)
12139219Sgibbs{
12239219Sgibbs	int s;
12339219Sgibbs
12439219Sgibbs	s = splcam();
12539219Sgibbs	ecb->state = ECB_FREE;
12639219Sgibbs	SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links);
12739219Sgibbs	splx(s);
12839219Sgibbs}
12939219Sgibbs
13039219Sgibbsstatic __inline u_int32_t
13139219Sgibbsahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb)
13239219Sgibbs{
13339219Sgibbs	return (ahb->ecb_physbase
13439219Sgibbs	      + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));
13539219Sgibbs}
13639219Sgibbs
13739219Sgibbsstatic __inline struct ecb*
13839219Sgibbsahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr)
13939219Sgibbs{
14039219Sgibbs	return (ahb->ecb_array
14139219Sgibbs	      + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase));
14239219Sgibbs}
14339219Sgibbs
14439219Sgibbsstatic __inline u_int32_t
14539219Sgibbsahbstatuspaddr(u_int32_t ecb_paddr)
14639219Sgibbs{
14739219Sgibbs	return (ecb_paddr + offsetof(struct ecb, status));
14839219Sgibbs}
14939219Sgibbs
15039219Sgibbsstatic __inline u_int32_t
15139219Sgibbsahbsensepaddr(u_int32_t ecb_paddr)
15239219Sgibbs{
15339219Sgibbs	return (ecb_paddr + offsetof(struct ecb, sense));
15439219Sgibbs}
15539219Sgibbs
15639219Sgibbsstatic __inline u_int32_t
15739219Sgibbsahbsgpaddr(u_int32_t ecb_paddr)
15839219Sgibbs{
15939219Sgibbs	return (ecb_paddr + offsetof(struct ecb, sg_list));
16039219Sgibbs}
16139219Sgibbs
16239219Sgibbsstatic __inline void
16339219Sgibbsahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code)
16439219Sgibbs{
16539219Sgibbs	u_int loopmax = 300;
16639219Sgibbs	while (--loopmax) {
16739219Sgibbs		u_int status;
16839219Sgibbs
16939219Sgibbs		status = ahb_inb(ahb, HOSTSTAT);
17043312Sdillon		if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY))
17143316Sgibbs		   == HOSTSTAT_MBOX_EMPTY)
17239219Sgibbs			break;
17339219Sgibbs		DELAY(20);
17439219Sgibbs	}
17539219Sgibbs	if (loopmax == 0)
17639324Sgibbs		panic("ahb%ld: adapter not taking commands\n", ahb->unit);
17739219Sgibbs
17839219Sgibbs	ahb_outl(ahb, MBOXOUT0, mboxval);
17939219Sgibbs	ahb_outb(ahb, ATTN, attn_code);
18039219Sgibbs}
18139219Sgibbs
18239219Sgibbsstatic const char *
18339219Sgibbsahbmatch(eisa_id_t type)
18439219Sgibbs{
18539219Sgibbs	switch(type & 0xfffffe00) {
18639219Sgibbs		case EISA_DEVICE_ID_ADAPTEC_1740:
18739219Sgibbs			return ("Adaptec 174x SCSI host adapter");
18839219Sgibbs			break;
18939219Sgibbs		default:
19039219Sgibbs			break;
19139219Sgibbs	}
19239219Sgibbs	return (NULL);
19339219Sgibbs}
19439219Sgibbs
19539219Sgibbsstatic int
19645791Speterahbprobe(device_t dev)
19739219Sgibbs{
19845791Speter	const char *desc;
19939219Sgibbs	u_int32_t iobase;
20039219Sgibbs	u_int32_t irq;
20145791Speter	u_int8_t  intdef;
20249360Smdodd	int shared;
20339219Sgibbs
20445791Speter	desc = ahbmatch(eisa_get_id(dev));
20545791Speter	if (!desc)
20645791Speter	    return (ENXIO);
20745791Speter	device_set_desc(dev, desc);
20839219Sgibbs
20945791Speter	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) +
21045791Speter	    AHB_EISA_SLOT_OFFSET;
21139219Sgibbs
21245791Speter	eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE);
21339219Sgibbs
21445791Speter	intdef = inb(INTDEF + iobase);
21545791Speter	switch (intdef & 0x7) {
21645791Speter	case INT9:
21745791Speter	    irq = 9;
21845791Speter	    break;
21945791Speter	case INT10:
22045791Speter	    irq = 10;
22145791Speter	    break;
22245791Speter	case INT11:
22345791Speter	    irq = 11;
22445791Speter	    break;
22545791Speter	case INT12:
22645791Speter	    irq = 12;
22745791Speter	    break;
22845791Speter	case INT14:
22945791Speter	    irq = 14;
23045791Speter	    break;
23145791Speter	case INT15:
23245791Speter	    irq = 15;
23345791Speter	    break;
23445791Speter	default:
23545791Speter	    printf("Adaptec 174X at slot %d: illegal "
23645791Speter		   "irq setting %d\n", eisa_get_slot(dev),
23745791Speter		   (intdef & 0x7));
23845791Speter	    irq = 0;
23945791Speter	    break;
24039219Sgibbs	}
24145791Speter	if (irq == 0)
24245791Speter	    return ENXIO;
24345791Speter
24449360Smdodd	shared = (inb(INTDEF + iobase) & INTLEVEL) ?
24549360Smdodd		 EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE;
24645791Speter
24749360Smdodd	eisa_add_intr(dev, irq, shared);
24849360Smdodd
24945791Speter	return 0;
25039219Sgibbs}
25139219Sgibbs
25239219Sgibbsstatic int
25345791Speterahbattach(device_t dev)
25439219Sgibbs{
25539219Sgibbs	/*
25639219Sgibbs	 * find unit and check we have that many defined
25739219Sgibbs	 */
25839219Sgibbs	struct	    ahb_softc *ahb;
25939219Sgibbs	struct	    ecb* next_ecb;
26045791Speter	struct	    resource *io = 0;
26145791Speter	struct	    resource *irq = 0;
26249360Smdodd	int	    rid;
26345791Speter	void	    *ih;
26439219Sgibbs
26545791Speter	rid = 0;
26645791Speter	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
26745791Speter				0, ~0, 1, RF_ACTIVE);
26845791Speter	if (!io) {
26945791Speter		device_printf(dev, "No I/O space?!\n");
27045791Speter		return ENOMEM;
27139219Sgibbs	}
27239219Sgibbs
27356177Snyan	if ((ahb = ahballoc(device_get_unit(dev), io)) == NULL) {
27445791Speter		goto error_exit2;
27539219Sgibbs	}
27639219Sgibbs
27739219Sgibbs	if (ahbreset(ahb) != 0)
27845791Speter		goto error_exit;
27939219Sgibbs
28045791Speter	rid = 0;
28145791Speter	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
28249360Smdodd				 0, ~0, 1, RF_ACTIVE);
28345791Speter	if (!irq) {
28445791Speter		device_printf(dev, "Can't allocate interrupt\n");
28545791Speter		goto error_exit;
28639219Sgibbs	}
28739219Sgibbs
28839219Sgibbs	/*
28939219Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
29061686Salex	 * accessible memory allocations and memory mappings we will
29139219Sgibbs	 * need to perform during normal operation.
29239219Sgibbs	 */
29339219Sgibbs	/* DMA tag for mapping buffers into device visible space. */
29439219Sgibbs	/* XXX Should be a child of the EISA bus dma tag */
295112782Smdodd	if (bus_dma_tag_create(	/* parent	*/ NULL,
296112782Smdodd				/* alignment	*/ 1,
297112782Smdodd				/* boundary	*/ 0,
298112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
299112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
300112782Smdodd				/* filter	*/ NULL,
301112782Smdodd				/* filterarg	*/ NULL,
302112782Smdodd				/* maxsize	*/ MAXBSIZE,
303112782Smdodd				/* nsegments	*/ AHB_NSEG,
304112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
305112782Smdodd				/* flags	*/ BUS_DMA_ALLOCNOW,
306112782Smdodd				&ahb->buffer_dmat) != 0)
30739219Sgibbs		goto error_exit;
30839219Sgibbs
30939219Sgibbs	ahb->init_level++;
31039219Sgibbs
31139219Sgibbs	/* DMA tag for our ccb structures and ha inquiry data */
312112782Smdodd	if (bus_dma_tag_create(	/* parent	*/ NULL,
313112782Smdodd				/* alignment	*/ 1,
314112782Smdodd				/* boundary	*/ 0,
315112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
316112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
317112782Smdodd				/* filter	*/ NULL,
318112782Smdodd				/* filterarg	*/ NULL,
319112782Smdodd				/* maxsize	*/ (AHB_NECB *
320112782Smdodd						    sizeof(struct ecb))
321112782Smdodd						    + sizeof(*ahb->ha_inq_data),
322112782Smdodd				/* nsegments	*/ 1,
323112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
324112782Smdodd				/* flags	*/ 0,
325112782Smdodd				&ahb->ecb_dmat) != 0)
32639219Sgibbs		goto error_exit;
32739219Sgibbs
32839219Sgibbs	ahb->init_level++;
32939219Sgibbs
33039219Sgibbs	/* Allocation for our ccbs */
33139219Sgibbs	if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array,
33239219Sgibbs			     BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0)
33339219Sgibbs		goto error_exit;
33439219Sgibbs
33539219Sgibbs	ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB];
33639219Sgibbs
33739219Sgibbs	ahb->init_level++;
33839219Sgibbs
33939219Sgibbs	/* And permanently map them */
34039219Sgibbs	bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap,
34139219Sgibbs			ahb->ecb_array, AHB_NSEG * sizeof(struct ecb),
34239219Sgibbs			ahbmapecbs, ahb, /*flags*/0);
34339219Sgibbs
34439219Sgibbs	ahb->init_level++;
34539219Sgibbs
34639219Sgibbs	/* Allocate the buffer dmamaps for each of our ECBs */
34739219Sgibbs	bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb))
34839219Sgibbs	      + sizeof(*ahb->ha_inq_data));
34939219Sgibbs	next_ecb = ahb->ecb_array;
35039219Sgibbs	while (ahb->num_ecbs < AHB_NECB) {
35139219Sgibbs		u_int32_t ecb_paddr;
35239219Sgibbs
35339219Sgibbs		if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0,
35439219Sgibbs				      &next_ecb->dmamap))
35539219Sgibbs			break;
35639219Sgibbs		ecb_paddr = ahbecbvtop(ahb, next_ecb);
35739219Sgibbs		next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr);
35839219Sgibbs		next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr);
35939219Sgibbs		ahb->num_ecbs++;
36039219Sgibbs		ahbecbfree(ahb, next_ecb);
36139219Sgibbs		next_ecb++;
36239219Sgibbs	}
36339219Sgibbs
36439219Sgibbs	if (ahb->num_ecbs == 0)
36539219Sgibbs		goto error_exit;
36639219Sgibbs
36739219Sgibbs	ahb->init_level++;
36839219Sgibbs
36939219Sgibbs	/*
37039219Sgibbs	 * Now that we know we own the resources we need, register
37139219Sgibbs	 * our bus with the XPT.
37239219Sgibbs	 */
37339219Sgibbs	if (ahbxptattach(ahb))
37439219Sgibbs		goto error_exit;
37539219Sgibbs
37639219Sgibbs	/* Enable our interrupt */
37773280Smarkm	bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, ahbintr, ahb, &ih);
37839219Sgibbs	return (0);
37945791Speter
38039219Sgibbserror_exit:
38139219Sgibbs	/*
38239219Sgibbs	 * The board's IRQ line will not be left enabled
38339219Sgibbs	 * if we can't intialize correctly, so its safe
38439219Sgibbs	 * to release the irq.
38539219Sgibbs	 */
38639219Sgibbs	ahbfree(ahb);
38745791Spetererror_exit2:
38845791Speter	if (io)
38945791Speter		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
39045791Speter	if (irq)
39145791Speter		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
39239219Sgibbs	return (-1);
39339219Sgibbs}
39439219Sgibbs
39539219Sgibbsstatic struct ahb_softc *
39656177Snyanahballoc(u_long unit, struct resource *res)
39739219Sgibbs{
39839219Sgibbs	struct	ahb_softc *ahb;
39939219Sgibbs
40039219Sgibbs	/*
40139219Sgibbs	 * Allocate a storage area for us
40239219Sgibbs	 */
40367888Sdwmalone	ahb = malloc(sizeof(struct ahb_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
40439219Sgibbs	if (!ahb) {
40539324Sgibbs		printf("ahb%ld: cannot malloc!\n", unit);
40639219Sgibbs		return (NULL);
40739219Sgibbs	}
40839219Sgibbs	SLIST_INIT(&ahb->free_ecbs);
40939219Sgibbs	LIST_INIT(&ahb->pending_ccbs);
41039219Sgibbs	ahb->unit = unit;
41156177Snyan	ahb->tag = rman_get_bustag(res);
41256177Snyan	ahb->bsh = rman_get_bushandle(res);
41339219Sgibbs	ahb->disc_permitted = ~0;
41439219Sgibbs	ahb->tags_permitted = ~0;
41539219Sgibbs
41639219Sgibbs	return (ahb);
41739219Sgibbs}
41839219Sgibbs
41939219Sgibbsstatic void
42039219Sgibbsahbfree(struct ahb_softc *ahb)
42139219Sgibbs{
42239219Sgibbs	switch (ahb->init_level) {
42339219Sgibbs	default:
42439219Sgibbs	case 4:
42539219Sgibbs		bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap);
42639219Sgibbs	case 3:
42739219Sgibbs		bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array,
42839219Sgibbs				ahb->ecb_dmamap);
42939219Sgibbs		bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap);
43039219Sgibbs	case 2:
43139219Sgibbs		bus_dma_tag_destroy(ahb->ecb_dmat);
43239219Sgibbs	case 1:
43339219Sgibbs		bus_dma_tag_destroy(ahb->buffer_dmat);
43439219Sgibbs	case 0:
43597208Speter		break;
43639219Sgibbs	}
43739219Sgibbs	free(ahb, M_DEVBUF);
43839219Sgibbs}
43939219Sgibbs
44039219Sgibbs/*
44139219Sgibbs * reset board, If it doesn't respond, return failure
44239219Sgibbs */
44339219Sgibbsstatic int
44439219Sgibbsahbreset(struct ahb_softc *ahb)
44539219Sgibbs{
44639219Sgibbs	int	wait = 1000;	/* 1 sec enough? */
44739219Sgibbs	int	test;
44839219Sgibbs
44939219Sgibbs	if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {
45039219Sgibbs		printf("ahb_reset: Controller not in enhanced mode\n");
45139219Sgibbs		return (-1);
45239219Sgibbs	}
45339219Sgibbs
45439219Sgibbs	ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);
45539219Sgibbs	DELAY(1000);
45639219Sgibbs	ahb_outb(ahb, CONTROL, 0);
45739219Sgibbs	while (--wait) {
45839219Sgibbs		DELAY(1000);
45939219Sgibbs		if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)
46039219Sgibbs			break;
46139219Sgibbs	}
46239219Sgibbs
46339219Sgibbs	if (wait == 0) {
46439219Sgibbs		printf("ahbreset: No answer from aha1742 board\n");
46539219Sgibbs		return (-1);
46639219Sgibbs	}
46739219Sgibbs	if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {
46839219Sgibbs		printf("ahb_reset: self test failed, val = 0x%x\n", test);
46939219Sgibbs		return (-1);
47039219Sgibbs	}
47139219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
47239219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
47339219Sgibbs		DELAY(10000);
47439219Sgibbs	}
47539219Sgibbs	return (0);
47639219Sgibbs}
47739219Sgibbs
47839219Sgibbsstatic void
47939219Sgibbsahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
48039219Sgibbs{
48139219Sgibbs	struct ahb_softc* ahb;
48239219Sgibbs
48339219Sgibbs	ahb = (struct ahb_softc*)arg;
48439219Sgibbs	ahb->ecb_physbase = segs->ds_addr;
48539219Sgibbs	/*
48639219Sgibbs	 * Space for adapter inquiry information is on the
48739219Sgibbs	 * tail of the ecb array.
48839219Sgibbs	 */
48939219Sgibbs	ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);
49039219Sgibbs}
49139219Sgibbs
49239219Sgibbsstatic int
49339219Sgibbsahbxptattach(struct ahb_softc *ahb)
49439219Sgibbs{
49539219Sgibbs	struct cam_devq *devq;
49639219Sgibbs	struct ecb *ecb;
49739219Sgibbs	u_int  i;
49839219Sgibbs
49939219Sgibbs	/* Remeber who are we on the scsi bus */
50039219Sgibbs	ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;
50139219Sgibbs
50239219Sgibbs	/* Use extended translation?? */
50339219Sgibbs    	ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;
50439219Sgibbs
50539219Sgibbs	/* Fetch adapter inquiry data */
50639219Sgibbs	ecb = ahbecbget(ahb);	/* Always succeeds - no outstanding commands */
50739219Sgibbs	ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;
50839219Sgibbs	ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;
50939219Sgibbs	ecb->hecb.data_ptr = ahb->ha_inq_physbase;
51039219Sgibbs	ecb->hecb.data_len = sizeof(struct ha_inquiry_data);
51139219Sgibbs	ecb->hecb.sense_ptr = 0;
51239219Sgibbs	ecb->state = ECB_ACTIVE;
51339219Sgibbs
51439219Sgibbs	/* Tell the adapter about this command */
51539219Sgibbs	ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),
51639219Sgibbs		     ATTN_STARTECB|ahb->scsi_id);
51739219Sgibbs
51839219Sgibbs	/* Poll for interrupt completion */
51939219Sgibbs	for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {
52039219Sgibbs		ahbintr(ahb);
52139219Sgibbs		DELAY(1000);
52239219Sgibbs	}
52339219Sgibbs
52439219Sgibbs	ahb->num_ecbs = MIN(ahb->num_ecbs,
52539219Sgibbs			    ahb->ha_inq_data->scsi_data.reserved[1]);
52639324Sgibbs	printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",
52739219Sgibbs	       ahb->unit, ahb->ha_inq_data->scsi_data.product,
52839219Sgibbs	       (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"
52939219Sgibbs							 : "Single Ended",
53039219Sgibbs	       ahb->ha_inq_data->scsi_data.revision,
53139219Sgibbs	       ahb->scsi_id, ahb->num_ecbs);
53239219Sgibbs
53339219Sgibbs	/* Restore sense paddr for future CCB clients */
53439219Sgibbs	ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));
53539219Sgibbs
53639219Sgibbs	ahbecbfree(ahb, ecb);
53739219Sgibbs
53839219Sgibbs	/*
53939219Sgibbs	 * Create the device queue for our SIM.
54039219Sgibbs	 */
54139219Sgibbs	devq = cam_simq_alloc(ahb->num_ecbs);
54239219Sgibbs	if (devq == NULL)
54339219Sgibbs		return (ENOMEM);
54439219Sgibbs
54539219Sgibbs	/*
54639219Sgibbs	 * Construct our SIM entry
54739219Sgibbs	 */
54839219Sgibbs	ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit,
54939219Sgibbs				 2, ahb->num_ecbs, devq);
55039219Sgibbs	if (ahb->sim == NULL) {
55139219Sgibbs		cam_simq_free(devq);
55239219Sgibbs		return (ENOMEM);
55339219Sgibbs	}
55439219Sgibbs
55539219Sgibbs	if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) {
55639219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
55739219Sgibbs		return (ENXIO);
55839219Sgibbs	}
55939219Sgibbs
56039219Sgibbs	if (xpt_create_path(&ahb->path, /*periph*/NULL,
56139219Sgibbs			    cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,
56239219Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
56339219Sgibbs		xpt_bus_deregister(cam_sim_path(ahb->sim));
56439219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
56539219Sgibbs		return (ENXIO);
56639219Sgibbs	}
56739219Sgibbs
56839219Sgibbs	/*
56939219Sgibbs	 * Allow the board to generate interrupts.
57039219Sgibbs	 */
57139219Sgibbs	ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);
57239219Sgibbs
57339219Sgibbs	return (0);
57439219Sgibbs}
57539219Sgibbs
57639219Sgibbsstatic void
57739219Sgibbsahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
57839219Sgibbs{
57939219Sgibbs	struct ccb_hdr *ccb_h;
58039219Sgibbs	u_int target_id;
58139219Sgibbs
58239219Sgibbs	if (ahb->immed_cmd == 0) {
58339324Sgibbs		printf("ahb%ld: Immediate Command complete with no "
58439324Sgibbs		       " pending command\n", ahb->unit);
58539219Sgibbs		return;
58639219Sgibbs	}
58739219Sgibbs
58839219Sgibbs	target_id = intstat & INTSTAT_TARGET_MASK;
58939219Sgibbs
59039219Sgibbs	ccb_h = LIST_FIRST(&ahb->pending_ccbs);
59139219Sgibbs	while (ccb_h != NULL) {
59239219Sgibbs		struct ecb *pending_ecb;
59339219Sgibbs		union ccb *ccb;
59439219Sgibbs
59539219Sgibbs		pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
59639219Sgibbs		ccb = pending_ecb->ccb;
59739219Sgibbs		ccb_h = LIST_NEXT(ccb_h, sim_links.le);
59839219Sgibbs		if (ccb->ccb_h.target_id == target_id
59939219Sgibbs		 || target_id == ahb->scsi_id) {
60039219Sgibbs			untimeout(ahbtimeout, pending_ecb,
60139219Sgibbs				  ccb->ccb_h.timeout_ch);
60239219Sgibbs			LIST_REMOVE(&ccb->ccb_h, sim_links.le);
60339219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
60439219Sgibbs				bus_dmamap_unload(ahb->buffer_dmat,
60539219Sgibbs						  pending_ecb->dmamap);
60639219Sgibbs			if (pending_ecb == ahb->immed_ecb)
60739219Sgibbs				ccb->ccb_h.status =
60839219Sgibbs				    CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;
60939219Sgibbs			else if (target_id == ahb->scsi_id)
61039219Sgibbs				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
61139219Sgibbs			else
61239219Sgibbs				ccb->ccb_h.status = CAM_BDR_SENT;
61339219Sgibbs			ahbecbfree(ahb, pending_ecb);
61439219Sgibbs			xpt_done(ccb);
61539219Sgibbs		} else if (ahb->immed_ecb != NULL) {
61639219Sgibbs			/* Re-instate timeout */
61739219Sgibbs			ccb->ccb_h.timeout_ch =
61839219Sgibbs			    timeout(ahbtimeout, (caddr_t)pending_ecb,
61939219Sgibbs				    (ccb->ccb_h.timeout * hz) / 1000);
62039219Sgibbs		}
62139219Sgibbs	}
62239219Sgibbs
62339219Sgibbs	if (ahb->immed_ecb != NULL) {
62439219Sgibbs		ahb->immed_ecb = NULL;
62539324Sgibbs		printf("ahb%ld: No longer in timeout\n", ahb->unit);
62639219Sgibbs	} else if (target_id == ahb->scsi_id)
62739324Sgibbs		printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit);
62839219Sgibbs	else
62939324Sgibbs		printf("ahb%ld:  Bus Device Reset Delibered to target %d\n",
63039219Sgibbs		       ahb->unit, target_id);
63139219Sgibbs
63239219Sgibbs	ahb->immed_cmd = 0;
63339219Sgibbs}
63439219Sgibbs
63539219Sgibbsstatic void
63639219Sgibbsahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
63739219Sgibbs{
63839219Sgibbs	if (ecb->status.data_overrun != 0) {
63939219Sgibbs		/*
64039219Sgibbs		 * Overrun Condition.  The hardware doesn't
64139219Sgibbs		 * provide a meaningful byte count in this case
64239219Sgibbs		 * (the residual is always 0).  Tell the XPT
64339219Sgibbs		 * layer about the error.
64439219Sgibbs		 */
64539219Sgibbs		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
64639219Sgibbs	} else {
64739219Sgibbs		ccb->csio.resid = ecb->status.resid_count;
64839219Sgibbs
64939219Sgibbs		if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {
65039219Sgibbs			/*
65139219Sgibbs			 * For S/G transfers, the adapter provides a pointer
65239219Sgibbs			 * to the address in the last S/G element used and a
65339219Sgibbs			 * residual for that element.  So, we need to sum up
65439219Sgibbs			 * the elements that follow it in order to get a real
65539219Sgibbs			 * residual number.  If we have an overrun, the residual
65639219Sgibbs			 * reported will be 0 and we already know that all S/G
65739219Sgibbs			 * segments have been exhausted, so we can skip this
65839219Sgibbs			 * step.
65939219Sgibbs			 */
66039219Sgibbs			ahb_sg_t *sg;
66139219Sgibbs			int	  num_sg;
66239219Sgibbs
66339219Sgibbs			num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);
66439219Sgibbs
66539219Sgibbs			/* Find the S/G the adapter was working on */
66639219Sgibbs			for (sg = ecb->sg_list;
66739219Sgibbs			     num_sg != 0 && sg->addr != ecb->status.resid_addr;
66839219Sgibbs			     num_sg--, sg++)
66939219Sgibbs				;
67039219Sgibbs
67139219Sgibbs			/* Skip it */
67239219Sgibbs			num_sg--;
67339219Sgibbs			sg++;
67439219Sgibbs
67539219Sgibbs			/* Sum the rest */
67639219Sgibbs			for (; num_sg != 0; num_sg--, sg++)
67739219Sgibbs				ccb->csio.resid += sg->len;
67839219Sgibbs		}
67939219Sgibbs		/* Underruns are not errors */
68039219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
68139219Sgibbs	}
68239219Sgibbs}
68339219Sgibbs
68439219Sgibbsstatic void
68539219Sgibbsahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
68639219Sgibbs{
68739219Sgibbs	struct hardware_ecb *hecb;
68839219Sgibbs	struct ecb_status *status;
68939219Sgibbs
69039219Sgibbs	hecb = &ecb->hecb;
69139219Sgibbs	status = &ecb->status;
69239219Sgibbs	switch (status->ha_status) {
69339219Sgibbs	case HS_OK:
69439219Sgibbs		ccb->csio.scsi_status = status->scsi_status;
69539219Sgibbs		if (status->scsi_status != 0) {
69639219Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
69739219Sgibbs			if (status->sense_stored) {
69839219Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
69939219Sgibbs				ccb->csio.sense_resid =
70039219Sgibbs				    ccb->csio.sense_len - status->sense_len;
70139219Sgibbs				bcopy(&ecb->sense, &ccb->csio.sense_data,
70239219Sgibbs				      status->sense_len);
70339219Sgibbs			}
70439219Sgibbs		}
70539219Sgibbs		break;
70639219Sgibbs	case HS_TARGET_NOT_ASSIGNED:
70739219Sgibbs		ccb->ccb_h.status = CAM_PATH_INVALID;
70839219Sgibbs		break;
70939219Sgibbs	case HS_SEL_TIMEOUT:
71039219Sgibbs		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
71139219Sgibbs		break;
71239219Sgibbs	case HS_DATA_RUN_ERR:
71339219Sgibbs		ahbcalcresid(ahb, ecb, ccb);
71439219Sgibbs		break;
71539219Sgibbs	case HS_UNEXPECTED_BUSFREE:
71639219Sgibbs		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
71739219Sgibbs		break;
71839219Sgibbs	case HS_INVALID_PHASE:
71939219Sgibbs		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
72039219Sgibbs		break;
72139219Sgibbs	case HS_REQUEST_SENSE_FAILED:
72239219Sgibbs		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
72339219Sgibbs		break;
72439219Sgibbs	case HS_TAG_MSG_REJECTED:
72539219Sgibbs	{
72639219Sgibbs		struct ccb_trans_settings neg;
72739219Sgibbs
72839219Sgibbs		xpt_print_path(ccb->ccb_h.path);
72939219Sgibbs		printf("refuses tagged commands.  Performing "
73039219Sgibbs		       "non-tagged I/O\n");
73139219Sgibbs		neg.flags = 0;
73239219Sgibbs		neg.valid = CCB_TRANS_TQ_VALID;
73339219Sgibbs		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
73439219Sgibbs		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
73539219Sgibbs		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
73639219Sgibbs		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
73739219Sgibbs		break;
73839219Sgibbs	}
73939219Sgibbs	case HS_FIRMWARE_LOAD_REQ:
74039219Sgibbs	case HS_HARDWARE_ERR:
74139219Sgibbs		/*
74239219Sgibbs		 * Tell the system that the Adapter
74339219Sgibbs		 * is no longer functional.
74439219Sgibbs		 */
74539219Sgibbs		ccb->ccb_h.status = CAM_NO_HBA;
74639219Sgibbs		break;
74739219Sgibbs	case HS_CMD_ABORTED_HOST:
74839219Sgibbs	case HS_CMD_ABORTED_ADAPTER:
74939219Sgibbs	case HS_ATN_TARGET_FAILED:
75039219Sgibbs	case HS_SCSI_RESET_ADAPTER:
75139219Sgibbs	case HS_SCSI_RESET_INCOMING:
75239219Sgibbs		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
75339219Sgibbs		break;
75449360Smdodd	case HS_INVALID_ECB_PARAM:
75549360Smdodd		printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
75649360Smdodd			ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2);
75749360Smdodd		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
75849360Smdodd		break;
75939219Sgibbs	case HS_DUP_TCB_RECEIVED:
76039219Sgibbs	case HS_INVALID_OPCODE:
76139219Sgibbs	case HS_INVALID_CMD_LINK:
76239219Sgibbs	case HS_PROGRAM_CKSUM_ERROR:
76339324Sgibbs		panic("ahb%ld: Can't happen host status %x occurred",
76439219Sgibbs		      ahb->unit, status->ha_status);
76539219Sgibbs		break;
76639219Sgibbs	}
76739219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
76839219Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
76939219Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
77039219Sgibbs	}
77139219Sgibbs}
77239219Sgibbs
77339219Sgibbsstatic void
77439219Sgibbsahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
77539219Sgibbs{
77639219Sgibbs	struct ecb *ecb;
77739219Sgibbs	union ccb *ccb;
77839219Sgibbs
77939219Sgibbs	ecb = ahbecbptov(ahb, mbox);
78039219Sgibbs
78139219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0)
78239219Sgibbs		panic("ecb not active");
78339219Sgibbs
78439219Sgibbs	ccb = ecb->ccb;
78539219Sgibbs
78639219Sgibbs	if (ccb != NULL) {
78739219Sgibbs		untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch);
78839219Sgibbs		LIST_REMOVE(&ccb->ccb_h, sim_links.le);
78939219Sgibbs
79039219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
791115343Sscottl			bus_dmasync_op_t op;
79239219Sgibbs
79339219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
79439219Sgibbs				op = BUS_DMASYNC_POSTREAD;
79539219Sgibbs			else
79639219Sgibbs				op = BUS_DMASYNC_POSTWRITE;
79739219Sgibbs			bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
79839219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
79939219Sgibbs		}
80039219Sgibbs
80139219Sgibbs		if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {
80239219Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
80339219Sgibbs			ccb->csio.resid = 0;
80439219Sgibbs		} else {
80539219Sgibbs			ahbprocesserror(ahb, ecb, ccb);
80639219Sgibbs		}
80739219Sgibbs		ahbecbfree(ahb, ecb);
80839219Sgibbs		xpt_done(ccb);
80939219Sgibbs	} else {
81039219Sgibbs		/* Non CCB Command */
81139219Sgibbs		if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {
81239324Sgibbs			printf("ahb%ld: Command 0%x Failed %x:%x:%x\n",
81339219Sgibbs			       ahb->unit, ecb->hecb.opcode,
81439219Sgibbs			       *((u_int16_t*)&ecb->status),
81539219Sgibbs			       ecb->status.ha_status, ecb->status.resid_count);
81639219Sgibbs		}
81739219Sgibbs		/* Client owns this ECB and will release it. */
81839219Sgibbs	}
81939219Sgibbs}
82039219Sgibbs
82139219Sgibbs/*
82239219Sgibbs * Catch an interrupt from the adaptor
82339219Sgibbs */
82439219Sgibbsstatic void
82539219Sgibbsahbintr(void *arg)
82639219Sgibbs{
82739219Sgibbs	struct	  ahb_softc *ahb;
82839219Sgibbs	u_int	  intstat;
82939219Sgibbs	u_int32_t mbox;
83039219Sgibbs
83139219Sgibbs	ahb = (struct ahb_softc *)arg;
83239219Sgibbs
83339219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
83439219Sgibbs		/*
83539219Sgibbs		 * Fetch information about this interrupt.
83639219Sgibbs		 */
83739219Sgibbs		intstat = ahb_inb(ahb, INTSTAT);
83839219Sgibbs		mbox = ahb_inl(ahb, MBOXIN0);
83939219Sgibbs
84039219Sgibbs		/*
84139219Sgibbs		 * Reset interrupt latch.
84239219Sgibbs		 */
84339219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
84439219Sgibbs
84539219Sgibbs		/*
84639219Sgibbs		 * Process the completed operation
84739219Sgibbs		 */
84839219Sgibbs		switch (intstat & INTSTAT_MASK) {
84939219Sgibbs		case INTSTAT_ECB_OK:
85039219Sgibbs		case INTSTAT_ECB_CMPWRETRY:
85139219Sgibbs		case INTSTAT_ECB_CMPWERR:
85239219Sgibbs			ahbdone(ahb, mbox, intstat);
85339219Sgibbs			break;
85439219Sgibbs		case INTSTAT_AEN_OCCURED:
85539219Sgibbs			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
85639219Sgibbs				/* Bus Reset */
85739219Sgibbs				xpt_print_path(ahb->path);
85839219Sgibbs				switch (mbox) {
85939219Sgibbs				case HS_SCSI_RESET_ADAPTER:
86039219Sgibbs					printf("Host Adapter Initiated "
86139219Sgibbs					       "Bus Reset occurred\n");
86239219Sgibbs					break;
86339219Sgibbs				case HS_SCSI_RESET_INCOMING:
86439219Sgibbs					printf("Bus Reset Initiated "
86539219Sgibbs					       "by another device occurred\n");
86639219Sgibbs					break;
86739219Sgibbs				}
86839219Sgibbs				/* Notify the XPT */
86939219Sgibbs				xpt_async(AC_BUS_RESET, ahb->path, NULL);
87039219Sgibbs				break;
87139219Sgibbs			}
87239219Sgibbs			printf("Unsupported initiator selection AEN occured\n");
87339219Sgibbs			break;
87439219Sgibbs		case INTSTAT_IMMED_OK:
87539219Sgibbs		case INTSTAT_IMMED_ERR:
87639219Sgibbs			ahbhandleimmed(ahb, mbox, intstat);
87739219Sgibbs			break;
87839219Sgibbs		case INTSTAT_HW_ERR:
87939219Sgibbs			panic("Unrecoverable hardware Error Occurred\n");
88039219Sgibbs		}
88139219Sgibbs	}
88239219Sgibbs}
88339219Sgibbs
88439219Sgibbsstatic void
88539219Sgibbsahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
88639219Sgibbs{
88739219Sgibbs	struct	  ecb *ecb;
88839219Sgibbs	union	  ccb *ccb;
88939219Sgibbs	struct	  ahb_softc *ahb;
89039219Sgibbs	u_int32_t ecb_paddr;
89139219Sgibbs	int	  s;
89239219Sgibbs
89339219Sgibbs	ecb = (struct ecb *)arg;
89439219Sgibbs	ccb = ecb->ccb;
89539219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
89639219Sgibbs
89739219Sgibbs	if (error != 0) {
89839219Sgibbs		if (error != EFBIG)
89939324Sgibbs			printf("ahb%ld: Unexepected error 0x%x returned from "
90039324Sgibbs			       "bus_dmamap_load\n", ahb->unit, error);
90139219Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
90239219Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
90339219Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
90439219Sgibbs		}
90539219Sgibbs		ahbecbfree(ahb, ecb);
90639219Sgibbs		xpt_done(ccb);
90739219Sgibbs		return;
90839219Sgibbs	}
90939219Sgibbs
91039219Sgibbs	ecb_paddr = ahbecbvtop(ahb, ecb);
91139219Sgibbs
91239219Sgibbs	if (nseg != 0) {
91339219Sgibbs		ahb_sg_t *sg;
91439219Sgibbs		bus_dma_segment_t *end_seg;
915115343Sscottl		bus_dmasync_op_t op;
91639219Sgibbs
91739219Sgibbs		end_seg = dm_segs + nseg;
91839219Sgibbs
91939219Sgibbs		/* Copy the segments into our SG list */
92039219Sgibbs		sg = ecb->sg_list;
92139219Sgibbs		while (dm_segs < end_seg) {
92239219Sgibbs			sg->addr = dm_segs->ds_addr;
92339219Sgibbs			sg->len = dm_segs->ds_len;
92439219Sgibbs			sg++;
92539219Sgibbs			dm_segs++;
92639219Sgibbs		}
92739219Sgibbs
92839219Sgibbs		if (nseg > 1) {
92939219Sgibbs			ecb->hecb.flag_word1 |= FW1_SG_ECB;
93039219Sgibbs			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
93139219Sgibbs			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
93239219Sgibbs		} else {
93339219Sgibbs			ecb->hecb.data_ptr = ecb->sg_list->addr;
93439219Sgibbs			ecb->hecb.data_len = ecb->sg_list->len;
93539219Sgibbs		}
93639219Sgibbs
93739219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
93839219Sgibbs/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
93939219Sgibbs			op = BUS_DMASYNC_PREREAD;
94039219Sgibbs		} else {
94139219Sgibbs			op = BUS_DMASYNC_PREWRITE;
94239219Sgibbs		}
94339219Sgibbs		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */
94439219Sgibbs
94539219Sgibbs		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
94639219Sgibbs
94739219Sgibbs	} else {
94839219Sgibbs		ecb->hecb.data_ptr = 0;
94939219Sgibbs		ecb->hecb.data_len = 0;
95039219Sgibbs	}
95139219Sgibbs
95239219Sgibbs	s = splcam();
95339219Sgibbs
95439219Sgibbs	/*
95539219Sgibbs	 * Last time we need to check if this CCB needs to
95639219Sgibbs	 * be aborted.
95739219Sgibbs	 */
95839219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
95939219Sgibbs		if (nseg != 0)
96039219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
96139219Sgibbs		ahbecbfree(ahb, ecb);
96239219Sgibbs		xpt_done(ccb);
96339219Sgibbs		splx(s);
96439219Sgibbs		return;
96539219Sgibbs	}
96639219Sgibbs
96739219Sgibbs	ecb->state = ECB_ACTIVE;
96839219Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
96939219Sgibbs	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);
97039219Sgibbs
97139219Sgibbs	/* Tell the adapter about this command */
97239219Sgibbs	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);
97339219Sgibbs
97439219Sgibbs	ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,
97539219Sgibbs					(ccb->ccb_h.timeout * hz) / 1000);
97639219Sgibbs	splx(s);
97739219Sgibbs}
97839219Sgibbs
97939219Sgibbsstatic void
98039219Sgibbsahbaction(struct cam_sim *sim, union ccb *ccb)
98139219Sgibbs{
98239219Sgibbs	struct	ahb_softc *ahb;
98339219Sgibbs
98439219Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
98539219Sgibbs
98639219Sgibbs	ahb = (struct ahb_softc *)cam_sim_softc(sim);
98739219Sgibbs
98839219Sgibbs	switch (ccb->ccb_h.func_code) {
98939219Sgibbs	/* Common cases first */
99039219Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
99139219Sgibbs	{
99239219Sgibbs		struct ecb *ecb;
99339219Sgibbs		struct hardware_ecb *hecb;
99439219Sgibbs
99539219Sgibbs		/*
99639219Sgibbs		 * get an ecb to use.
99739219Sgibbs		 */
99839219Sgibbs		if ((ecb = ahbecbget(ahb)) == NULL) {
99939219Sgibbs			/* Should never occur */
100039219Sgibbs			panic("Failed to get an ecb");
100139219Sgibbs		}
100239219Sgibbs
100339219Sgibbs		/*
100439219Sgibbs		 * So we can find the ECB when an abort is requested
100539219Sgibbs		 */
100639219Sgibbs		ecb->ccb = ccb;
100739219Sgibbs		ccb->ccb_h.ccb_ecb_ptr = ecb;
100839219Sgibbs		ccb->ccb_h.ccb_ahb_ptr = ahb;
100939219Sgibbs
101039219Sgibbs		/*
101139219Sgibbs		 * Put all the arguments for the xfer in the ecb
101239219Sgibbs		 */
101339219Sgibbs		hecb = &ecb->hecb;
101439219Sgibbs		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
101539219Sgibbs		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
101639219Sgibbs				 | FW1_ERR_STATUS_BLK_ONLY;
101739219Sgibbs		hecb->flag_word2 = ccb->ccb_h.target_lun
101839219Sgibbs				 | FW2_NO_RETRY_ON_BUSY;
101939219Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
102039219Sgibbs			hecb->flag_word2 |= FW2_TAG_ENB
102139219Sgibbs					 | ((ccb->csio.tag_action & 0x3)
102239219Sgibbs					    << FW2_TAG_TYPE_SHIFT);
102339219Sgibbs		}
102439219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
102539219Sgibbs			hecb->flag_word2 |= FW2_DISABLE_DISC;
102639219Sgibbs		hecb->sense_len = ccb->csio.sense_len;
102739219Sgibbs		hecb->cdb_len = ccb->csio.cdb_len;
102839219Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
102939219Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
103039219Sgibbs				bcopy(ccb->csio.cdb_io.cdb_ptr,
103139219Sgibbs				      hecb->cdb, hecb->cdb_len);
103239219Sgibbs			} else {
103339219Sgibbs				/* I guess I could map it in... */
103439219Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
103539219Sgibbs				ahbecbfree(ahb, ecb);
103639219Sgibbs				xpt_done(ccb);
103739219Sgibbs				return;
103839219Sgibbs			}
103939219Sgibbs		} else {
104039219Sgibbs			bcopy(ccb->csio.cdb_io.cdb_bytes,
104139219Sgibbs			      hecb->cdb, hecb->cdb_len);
104239219Sgibbs		}
104339219Sgibbs
104439219Sgibbs		/*
104539219Sgibbs		 * If we have any data to send with this command,
104639219Sgibbs		 * map it into bus space.
104739219Sgibbs		 */
104839219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
104939219Sgibbs			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
105039219Sgibbs				/*
105139219Sgibbs				 * We've been given a pointer
105239219Sgibbs				 * to a single buffer.
105339219Sgibbs				 */
105439219Sgibbs				if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {
105539219Sgibbs					int s;
105639219Sgibbs					int error;
105739219Sgibbs
105839219Sgibbs					s = splsoftvm();
105939219Sgibbs					error = bus_dmamap_load(
106039219Sgibbs					    ahb->buffer_dmat,
106139219Sgibbs					    ecb->dmamap,
106239219Sgibbs					    ccb->csio.data_ptr,
106339219Sgibbs					    ccb->csio.dxfer_len,
106439219Sgibbs					    ahbexecuteecb,
106539219Sgibbs					    ecb, /*flags*/0);
106639219Sgibbs					if (error == EINPROGRESS) {
106739219Sgibbs						/*
106839219Sgibbs						 * So as to maintain ordering,
106939219Sgibbs						 * freeze the controller queue
107039219Sgibbs						 * until our mapping is
107139219Sgibbs						 * returned.
107239219Sgibbs						 */
107339219Sgibbs						xpt_freeze_simq(ahb->sim, 1);
107439219Sgibbs						ccb->ccb_h.status |=
107539219Sgibbs						    CAM_RELEASE_SIMQ;
107639219Sgibbs					}
107739219Sgibbs					splx(s);
107839219Sgibbs				} else {
107939219Sgibbs					struct bus_dma_segment seg;
108039219Sgibbs
108139219Sgibbs					/* Pointer to physical buffer */
108239219Sgibbs					seg.ds_addr =
108339219Sgibbs					    (bus_addr_t)ccb->csio.data_ptr;
108439219Sgibbs					seg.ds_len = ccb->csio.dxfer_len;
108539219Sgibbs					ahbexecuteecb(ecb, &seg, 1, 0);
108639219Sgibbs				}
108739219Sgibbs			} else {
108839219Sgibbs				struct bus_dma_segment *segs;
108939219Sgibbs
109039219Sgibbs				if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
109139219Sgibbs					panic("ahbaction - Physical segment "
109239219Sgibbs					      "pointers unsupported");
109339219Sgibbs
109439219Sgibbs				if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
109539219Sgibbs					panic("btaction - Virtual segment "
109639219Sgibbs					      "addresses unsupported");
109739219Sgibbs
109839219Sgibbs				/* Just use the segments provided */
109939219Sgibbs				segs = (struct bus_dma_segment *)
110039219Sgibbs				    ccb->csio.data_ptr;
110139219Sgibbs				ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,
110239219Sgibbs					     0);
110339219Sgibbs			}
110439219Sgibbs		} else {
110539219Sgibbs			ahbexecuteecb(ecb, NULL, 0, 0);
110639219Sgibbs		}
110739219Sgibbs		break;
110839219Sgibbs	}
110939219Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
111039219Sgibbs	case XPT_TARGET_IO:		/* Execute target I/O request */
111139219Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
111239219Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
111339219Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
111439219Sgibbs		/* XXX Implement */
111539219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
111639219Sgibbs		xpt_done(ccb);
111739219Sgibbs		break;
111839219Sgibbs	case XPT_SET_TRAN_SETTINGS:
111939219Sgibbs	{
112039219Sgibbs		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
112139219Sgibbs		xpt_done(ccb);
112239219Sgibbs		break;
112339219Sgibbs	}
112439219Sgibbs	case XPT_GET_TRAN_SETTINGS:
112539219Sgibbs	/* Get default/user set transfer settings for the target */
112639219Sgibbs	{
112739219Sgibbs		struct	ccb_trans_settings *cts;
112839219Sgibbs		u_int	target_mask;
112939219Sgibbs
113039219Sgibbs		cts = &ccb->cts;
113139219Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
113239219Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
113339219Sgibbs			cts->flags = 0;
113439219Sgibbs			if ((ahb->disc_permitted & target_mask) != 0)
113539219Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
113639219Sgibbs			if ((ahb->tags_permitted & target_mask) != 0)
113739219Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
113839219Sgibbs			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
113939219Sgibbs			cts->sync_period = 25; /* 10MHz */
114039219Sgibbs
114139219Sgibbs			if (cts->sync_period != 0)
114239219Sgibbs				cts->sync_offset = 15;
114339219Sgibbs
114439219Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
114539219Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
114639219Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
114739219Sgibbs				   | CCB_TRANS_DISC_VALID
114839219Sgibbs				   | CCB_TRANS_TQ_VALID;
114939219Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
115039219Sgibbs		} else {
115139219Sgibbs			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
115239219Sgibbs		}
115339219Sgibbs		xpt_done(ccb);
115439219Sgibbs		break;
115539219Sgibbs	}
115639219Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
115739219Sgibbs	{
115839219Sgibbs		int i;
115944508Sgibbs		int s;
116039219Sgibbs
116144508Sgibbs		s = splcam();
116239219Sgibbs		ahb->immed_cmd = IMMED_RESET;
116339219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
116439219Sgibbs		/* Poll for interrupt completion */
116544508Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
116639219Sgibbs			DELAY(1000);
116744508Sgibbs			ahbintr(cam_sim_softc(sim));
116844508Sgibbs		}
116944508Sgibbs		splx(s);
117039219Sgibbs		break;
117139219Sgibbs	}
117239219Sgibbs	case XPT_CALC_GEOMETRY:
117339219Sgibbs	{
117439219Sgibbs		struct	  ccb_calc_geometry *ccg;
117539219Sgibbs		u_int32_t size_mb;
117639219Sgibbs		u_int32_t secs_per_cylinder;
117739219Sgibbs
117839219Sgibbs		ccg = &ccb->ccg;
117939219Sgibbs		size_mb = ccg->volume_size
118039219Sgibbs			/ ((1024L * 1024L) / ccg->block_size);
118139219Sgibbs
118239219Sgibbs		if (size_mb > 1024 && (ahb->extended_trans != 0)) {
118339219Sgibbs			ccg->heads = 255;
118439219Sgibbs			ccg->secs_per_track = 63;
118539219Sgibbs		} else {
118639219Sgibbs			ccg->heads = 64;
118739219Sgibbs			ccg->secs_per_track = 32;
118839219Sgibbs		}
118939219Sgibbs		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
119039219Sgibbs		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
119139219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
119239219Sgibbs		xpt_done(ccb);
119339219Sgibbs		break;
119439219Sgibbs	}
119539219Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
119639219Sgibbs	{
119739219Sgibbs		int i;
119839219Sgibbs
119939219Sgibbs		ahb->immed_cmd = IMMED_RESET;
120039219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
120139219Sgibbs		/* Poll for interrupt completion */
120239219Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
120339219Sgibbs			DELAY(1000);
120439219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
120539219Sgibbs		xpt_done(ccb);
120639219Sgibbs		break;
120739219Sgibbs	}
120839219Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
120939219Sgibbs		/* XXX Implement */
121039219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
121139219Sgibbs		xpt_done(ccb);
121239219Sgibbs		break;
121339219Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
121439219Sgibbs	{
121539219Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
121639219Sgibbs
121739219Sgibbs		cpi->version_num = 1; /* XXX??? */
121839219Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
121939219Sgibbs		cpi->target_sprt = 0;
122039219Sgibbs		cpi->hba_misc = 0;
122139219Sgibbs		cpi->hba_eng_cnt = 0;
122239219Sgibbs		cpi->max_target = 7;
122339219Sgibbs		cpi->max_lun = 7;
122439219Sgibbs		cpi->initiator_id = ahb->scsi_id;
122539219Sgibbs		cpi->bus_id = cam_sim_bus(sim);
122646581Sken		cpi->base_transfer_speed = 3300;
122739219Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
122839219Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
122939219Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
123039219Sgibbs		cpi->unit_number = cam_sim_unit(sim);
123139219Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
123239219Sgibbs		xpt_done(ccb);
123339219Sgibbs		break;
123439219Sgibbs	}
123539219Sgibbs#if 0
123639219Sgibbs	/* Need these??? */
123739219Sgibbs        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */
123839219Sgibbs        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */
123939219Sgibbs#endif
124039219Sgibbs	default:
124139219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
124239219Sgibbs		xpt_done(ccb);
124339219Sgibbs		break;
124439219Sgibbs	}
124539219Sgibbs}
124639219Sgibbs
124739219Sgibbsstatic void
124839219Sgibbsahbpoll(struct cam_sim *sim)
124939219Sgibbs{
125040132Sgibbs	ahbintr(cam_sim_softc(sim));
125139219Sgibbs}
125239219Sgibbs
125345577Seivindstatic void
125439219Sgibbsahbtimeout(void *arg)
125539219Sgibbs{
125639219Sgibbs	struct ecb	 *ecb;
125739219Sgibbs	union  ccb	 *ccb;
125839219Sgibbs	struct ahb_softc *ahb;
125939219Sgibbs	int		  s;
126039219Sgibbs
126139219Sgibbs	ecb = (struct ecb *)arg;
126239219Sgibbs	ccb = ecb->ccb;
126339219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
126439219Sgibbs	xpt_print_path(ccb->ccb_h.path);
126539390Sgibbs	printf("ECB %p - timed out\n", (void *)ecb);
126639219Sgibbs
126739219Sgibbs	s = splcam();
126839219Sgibbs
126939219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0) {
127039219Sgibbs		xpt_print_path(ccb->ccb_h.path);
127139390Sgibbs		printf("ECB %p - timed out ECB already completed\n",
127239390Sgibbs		       (void *)ecb);
127339219Sgibbs		splx(s);
127439219Sgibbs		return;
127539219Sgibbs	}
127639219Sgibbs	/*
127739219Sgibbs	 * In order to simplify the recovery process, we ask the XPT
127839219Sgibbs	 * layer to halt the queue of new transactions and we traverse
127939219Sgibbs	 * the list of pending CCBs and remove their timeouts. This
128039219Sgibbs	 * means that the driver attempts to clear only one error
128139219Sgibbs	 * condition at a time.  In general, timeouts that occur
128239219Sgibbs	 * close together are related anyway, so there is no benefit
128339219Sgibbs	 * in attempting to handle errors in parrallel.  Timeouts will
128439219Sgibbs	 * be reinstated when the recovery process ends.
128539219Sgibbs	 */
128639219Sgibbs	if ((ecb->state & ECB_DEVICE_RESET) == 0) {
128739219Sgibbs		struct ccb_hdr *ccb_h;
128839219Sgibbs
128939219Sgibbs		if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {
129039219Sgibbs			xpt_freeze_simq(ahb->sim, /*count*/1);
129139219Sgibbs			ecb->state |= ECB_RELEASE_SIMQ;
129239219Sgibbs		}
129339219Sgibbs
129439219Sgibbs		ccb_h = LIST_FIRST(&ahb->pending_ccbs);
129539219Sgibbs		while (ccb_h != NULL) {
129639219Sgibbs			struct ecb *pending_ecb;
129739219Sgibbs
129839219Sgibbs			pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
129939219Sgibbs			untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch);
130039219Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
130139219Sgibbs		}
130239219Sgibbs
130339219Sgibbs		/* Store for our interrupt handler */
130439219Sgibbs		ahb->immed_ecb = ecb;
130539219Sgibbs
130639219Sgibbs		/*
130739219Sgibbs		 * Send a Bus Device Reset message:
130839219Sgibbs		 * The target that is holding up the bus may not
130939219Sgibbs		 * be the same as the one that triggered this timeout
131039219Sgibbs		 * (different commands have different timeout lengths),
131139219Sgibbs		 * but we have no way of determining this from our
131239219Sgibbs		 * timeout handler.  Our strategy here is to queue a
131339219Sgibbs		 * BDR message to the target of the timed out command.
131439219Sgibbs		 * If this fails, we'll get another timeout 2 seconds
131539219Sgibbs		 * later which will attempt a bus reset.
131639219Sgibbs		 */
131739219Sgibbs		xpt_print_path(ccb->ccb_h.path);
131839324Sgibbs		printf("Queuing BDR\n");
131939219Sgibbs		ecb->state |= ECB_DEVICE_RESET;
132039219Sgibbs		ccb->ccb_h.timeout_ch =
132139219Sgibbs		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
132239219Sgibbs
132339219Sgibbs		ahb->immed_cmd = IMMED_RESET;
132439219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
132539219Sgibbs	} else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {
132639219Sgibbs		/*
132739219Sgibbs		 * Try a SCSI bus reset.  We do this only if we
132839219Sgibbs		 * have already attempted to clear the condition with a BDR.
132939219Sgibbs		 */
133039219Sgibbs		xpt_print_path(ccb->ccb_h.path);
133139324Sgibbs		printf("Attempting SCSI Bus reset\n");
133239219Sgibbs		ecb->state |= ECB_SCSIBUS_RESET;
133339219Sgibbs		ccb->ccb_h.timeout_ch =
133439219Sgibbs		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
133539219Sgibbs		ahb->immed_cmd = IMMED_RESET;
133639219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
133739219Sgibbs	} else {
133839219Sgibbs		/* Bring out the hammer... */
133939219Sgibbs		ahbreset(ahb);
134039219Sgibbs
134139219Sgibbs		/* Simulate the reset complete interrupt */
134239219Sgibbs		ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);
134339219Sgibbs	}
134439219Sgibbs
134539219Sgibbs	splx(s);
134639219Sgibbs}
134739219Sgibbs
134845791Speterstatic device_method_t ahb_eisa_methods[] = {
134945791Speter	/* Device interface */
135045791Speter	DEVMETHOD(device_probe,		ahbprobe),
135145791Speter	DEVMETHOD(device_attach,	ahbattach),
135245791Speter
135345791Speter	{ 0, 0 }
135445791Speter};
135545791Speter
135645791Speterstatic driver_t ahb_eisa_driver = {
135745791Speter	"ahb",
135845791Speter	ahb_eisa_methods,
135945791Speter	1,			/* unused */
136045791Speter};
136145791Speter
136245791Speterstatic devclass_t ahb_devclass;
136345791Speter
136445791SpeterDRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0);
1365