1139749Simp/*-
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$
2939219Sgibbs */
3039219Sgibbs
3139219Sgibbs#include <sys/param.h>
32241590Sjhb#include <sys/conf.h>
3339219Sgibbs#include <sys/systm.h>
3439219Sgibbs#include <sys/kernel.h>
3539219Sgibbs#include <sys/malloc.h>
3645791Speter#include <sys/module.h>
37117126Sscottl#include <sys/lock.h>
38117126Sscottl#include <sys/mutex.h>
3945791Speter#include <sys/bus.h>
4039219Sgibbs
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)				\
61241590Sjhb	bus_read_1((ahb)->res, port)
6239219Sgibbs
6339219Sgibbs#define ahb_inl(ahb, port)				\
64241590Sjhb	bus_read_4((ahb)->res, port)
6539219Sgibbs
6639219Sgibbs#define ahb_outb(ahb, port, value)			\
67241590Sjhb	bus_write_1((ahb)->res, port, value)
6839219Sgibbs
6939219Sgibbs#define ahb_outl(ahb, port, value)			\
70241590Sjhb	bus_write_4((ahb)->res, port, value)
7139219Sgibbs
7239219Sgibbsstatic const char		*ahbmatch(eisa_id_t type);
73170872Sscottlstatic struct ahb_softc		*ahballoc(device_t dev, 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);
86241590Sjhbstatic void			 ahbintr_locked(struct ahb_softc *ahb);
8739219Sgibbsstatic bus_dmamap_callback_t	 ahbexecuteecb;
8839219Sgibbsstatic void			 ahbaction(struct cam_sim *sim, union ccb *ccb);
8939219Sgibbsstatic void			 ahbpoll(struct cam_sim *sim);
9039219Sgibbs
9139219Sgibbs/* Our timeout handler */
92241590Sjhbstatic void			 ahbtimeout(void *arg);
9339219Sgibbs
9439219Sgibbsstatic __inline struct ecb*	ahbecbget(struct ahb_softc *ahb);
9539219Sgibbsstatic __inline void	 	ahbecbfree(struct ahb_softc* ahb,
9639219Sgibbs					   struct ecb* ecb);
9739219Sgibbsstatic __inline u_int32_t	ahbecbvtop(struct ahb_softc *ahb,
9839219Sgibbs					   struct ecb *ecb);
9939219Sgibbsstatic __inline struct ecb*	ahbecbptov(struct ahb_softc *ahb,
10039219Sgibbs					   u_int32_t ecb_addr);
10139219Sgibbsstatic __inline u_int32_t	ahbstatuspaddr(u_int32_t ecb_paddr);
10239219Sgibbsstatic __inline u_int32_t	ahbsensepaddr(u_int32_t ecb_paddr);
10339219Sgibbsstatic __inline u_int32_t	ahbsgpaddr(u_int32_t ecb_paddr);
10439219Sgibbsstatic __inline void		ahbqueuembox(struct ahb_softc *ahb,
10539219Sgibbs					     u_int32_t mboxval,
10639219Sgibbs					     u_int attn_code);
10739219Sgibbs
10839219Sgibbsstatic __inline struct ecb*
10939219Sgibbsahbecbget(struct ahb_softc *ahb)
11039219Sgibbs{
11139219Sgibbs	struct	ecb* ecb;
11239219Sgibbs
113241590Sjhb	if (!dumping)
114241590Sjhb		mtx_assert(&ahb->lock, MA_OWNED);
11539219Sgibbs	if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL)
11639219Sgibbs		SLIST_REMOVE_HEAD(&ahb->free_ecbs, links);
11739219Sgibbs
11839219Sgibbs	return (ecb);
11939219Sgibbs}
12039219Sgibbs
12139219Sgibbsstatic __inline void
12239219Sgibbsahbecbfree(struct ahb_softc* ahb, struct ecb* ecb)
12339219Sgibbs{
12439219Sgibbs
125241590Sjhb	if (!dumping)
126241590Sjhb		mtx_assert(&ahb->lock, MA_OWNED);
12739219Sgibbs	ecb->state = ECB_FREE;
12839219Sgibbs	SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links);
12939219Sgibbs}
13039219Sgibbs
13139219Sgibbsstatic __inline u_int32_t
13239219Sgibbsahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb)
13339219Sgibbs{
13439219Sgibbs	return (ahb->ecb_physbase
13539219Sgibbs	      + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));
13639219Sgibbs}
13739219Sgibbs
13839219Sgibbsstatic __inline struct ecb*
13939219Sgibbsahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr)
14039219Sgibbs{
14139219Sgibbs	return (ahb->ecb_array
142118225Sgallatin	      + ((struct ecb*)(uintptr_t)ecb_addr
143118225Sgallatin		- (struct ecb*)(uintptr_t)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)
178241590Sjhb		panic("%s: adapter not taking commands\n",
179241590Sjhb		    device_get_nameunit(ahb->dev));
18039219Sgibbs
18139219Sgibbs	ahb_outl(ahb, MBOXOUT0, mboxval);
18239219Sgibbs	ahb_outb(ahb, ATTN, attn_code);
18339219Sgibbs}
18439219Sgibbs
18539219Sgibbsstatic const char *
18639219Sgibbsahbmatch(eisa_id_t type)
18739219Sgibbs{
18839219Sgibbs	switch(type & 0xfffffe00) {
18939219Sgibbs		case EISA_DEVICE_ID_ADAPTEC_1740:
19039219Sgibbs			return ("Adaptec 174x SCSI host adapter");
19139219Sgibbs			break;
19239219Sgibbs		default:
19339219Sgibbs			break;
19439219Sgibbs	}
19539219Sgibbs	return (NULL);
19639219Sgibbs}
19739219Sgibbs
19839219Sgibbsstatic int
19945791Speterahbprobe(device_t dev)
20039219Sgibbs{
20145791Speter	const char *desc;
20239219Sgibbs	u_int32_t iobase;
20339219Sgibbs	u_int32_t irq;
20445791Speter	u_int8_t  intdef;
20549360Smdodd	int shared;
20639219Sgibbs
20745791Speter	desc = ahbmatch(eisa_get_id(dev));
20845791Speter	if (!desc)
20945791Speter	    return (ENXIO);
21045791Speter	device_set_desc(dev, desc);
21139219Sgibbs
21245791Speter	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) +
21345791Speter	    AHB_EISA_SLOT_OFFSET;
21439219Sgibbs
21545791Speter	eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE);
21639219Sgibbs
21745791Speter	intdef = inb(INTDEF + iobase);
21845791Speter	switch (intdef & 0x7) {
21945791Speter	case INT9:
22045791Speter	    irq = 9;
22145791Speter	    break;
22245791Speter	case INT10:
22345791Speter	    irq = 10;
22445791Speter	    break;
22545791Speter	case INT11:
22645791Speter	    irq = 11;
22745791Speter	    break;
22845791Speter	case INT12:
22945791Speter	    irq = 12;
23045791Speter	    break;
23145791Speter	case INT14:
23245791Speter	    irq = 14;
23345791Speter	    break;
23445791Speter	case INT15:
23545791Speter	    irq = 15;
23645791Speter	    break;
23745791Speter	default:
23845791Speter	    printf("Adaptec 174X at slot %d: illegal "
23945791Speter		   "irq setting %d\n", eisa_get_slot(dev),
24045791Speter		   (intdef & 0x7));
24145791Speter	    irq = 0;
24245791Speter	    break;
24339219Sgibbs	}
24445791Speter	if (irq == 0)
24545791Speter	    return ENXIO;
24645791Speter
24749360Smdodd	shared = (inb(INTDEF + iobase) & INTLEVEL) ?
24849360Smdodd		 EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE;
24945791Speter
25049360Smdodd	eisa_add_intr(dev, irq, shared);
25149360Smdodd
25245791Speter	return 0;
25339219Sgibbs}
25439219Sgibbs
25539219Sgibbsstatic int
25645791Speterahbattach(device_t dev)
25739219Sgibbs{
25839219Sgibbs	/*
25939219Sgibbs	 * find unit and check we have that many defined
26039219Sgibbs	 */
26139219Sgibbs	struct	    ahb_softc *ahb;
26239219Sgibbs	struct	    ecb* next_ecb;
263241590Sjhb	struct	    resource *io;
264241590Sjhb	struct	    resource *irq;
26549360Smdodd	int	    rid;
26645791Speter	void	    *ih;
26739219Sgibbs
268241590Sjhb	irq = NULL;
26945791Speter	rid = 0;
270127135Snjl	io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
271241590Sjhb	if (io == NULL) {
27245791Speter		device_printf(dev, "No I/O space?!\n");
27345791Speter		return ENOMEM;
27439219Sgibbs	}
27539219Sgibbs
276241590Sjhb	ahb = ahballoc(dev, io);
27739219Sgibbs
27839219Sgibbs	if (ahbreset(ahb) != 0)
27945791Speter		goto error_exit;
28039219Sgibbs
28145791Speter	rid = 0;
282127135Snjl	irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
283241590Sjhb	if (irq == NULL) {
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. */
294232883Sscottl	if (bus_dma_tag_create(	/* parent	*/ bus_get_dma_tag(dev),
295112782Smdodd				/* alignment	*/ 1,
296112782Smdodd				/* boundary	*/ 0,
297112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
298112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
299112782Smdodd				/* filter	*/ NULL,
300112782Smdodd				/* filterarg	*/ NULL,
301112782Smdodd				/* maxsize	*/ MAXBSIZE,
302112782Smdodd				/* nsegments	*/ AHB_NSEG,
303112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
304112782Smdodd				/* flags	*/ BUS_DMA_ALLOCNOW,
305117126Sscottl				/* lockfunc	*/ busdma_lock_mutex,
306241590Sjhb				/* lockarg	*/ &ahb->lock,
307112782Smdodd				&ahb->buffer_dmat) != 0)
30839219Sgibbs		goto error_exit;
30939219Sgibbs
31039219Sgibbs	ahb->init_level++;
31139219Sgibbs
31239219Sgibbs	/* DMA tag for our ccb structures and ha inquiry data */
313232883Sscottl	if (bus_dma_tag_create(	/* parent	*/ bus_get_dma_tag(dev),
314112782Smdodd				/* alignment	*/ 1,
315112782Smdodd				/* boundary	*/ 0,
316112782Smdodd				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
317112782Smdodd				/* highaddr	*/ BUS_SPACE_MAXADDR,
318112782Smdodd				/* filter	*/ NULL,
319112782Smdodd				/* filterarg	*/ NULL,
320112782Smdodd				/* maxsize	*/ (AHB_NECB *
321112782Smdodd						    sizeof(struct ecb))
322112782Smdodd						    + sizeof(*ahb->ha_inq_data),
323112782Smdodd				/* nsegments	*/ 1,
324112782Smdodd				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
325112782Smdodd				/* flags	*/ 0,
326241590Sjhb				/* lockfunc	*/ NULL,
327241590Sjhb				/* lockarg	*/ NULL,
328112782Smdodd				&ahb->ecb_dmat) != 0)
32939219Sgibbs		goto error_exit;
33039219Sgibbs
33139219Sgibbs	ahb->init_level++;
33239219Sgibbs
33339219Sgibbs	/* Allocation for our ccbs */
33439219Sgibbs	if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array,
33539219Sgibbs			     BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0)
33639219Sgibbs		goto error_exit;
33739219Sgibbs
33839219Sgibbs	ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB];
33939219Sgibbs
34039219Sgibbs	ahb->init_level++;
34139219Sgibbs
34239219Sgibbs	/* And permanently map them */
34339219Sgibbs	bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap,
34439219Sgibbs			ahb->ecb_array, AHB_NSEG * sizeof(struct ecb),
34539219Sgibbs			ahbmapecbs, ahb, /*flags*/0);
34639219Sgibbs
34739219Sgibbs	ahb->init_level++;
34839219Sgibbs
34939219Sgibbs	/* Allocate the buffer dmamaps for each of our ECBs */
35039219Sgibbs	bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb))
35139219Sgibbs	      + sizeof(*ahb->ha_inq_data));
35239219Sgibbs	next_ecb = ahb->ecb_array;
35339219Sgibbs	while (ahb->num_ecbs < AHB_NECB) {
35439219Sgibbs		u_int32_t ecb_paddr;
35539219Sgibbs
35639219Sgibbs		if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0,
35739219Sgibbs				      &next_ecb->dmamap))
35839219Sgibbs			break;
359241590Sjhb		callout_init_mtx(&next_ecb->timer, &ahb->lock, 0);
36039219Sgibbs		ecb_paddr = ahbecbvtop(ahb, next_ecb);
36139219Sgibbs		next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr);
36239219Sgibbs		next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr);
36339219Sgibbs		ahb->num_ecbs++;
36439219Sgibbs		ahbecbfree(ahb, next_ecb);
36539219Sgibbs		next_ecb++;
36639219Sgibbs	}
36739219Sgibbs
36839219Sgibbs	ahb->init_level++;
36939219Sgibbs
37039219Sgibbs	/*
37139219Sgibbs	 * Now that we know we own the resources we need, register
37239219Sgibbs	 * our bus with the XPT.
37339219Sgibbs	 */
37439219Sgibbs	if (ahbxptattach(ahb))
37539219Sgibbs		goto error_exit;
37639219Sgibbs
37739219Sgibbs	/* Enable our interrupt */
378241590Sjhb	if (bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY|INTR_MPSAFE,
379241590Sjhb	    NULL, ahbintr,  ahb, &ih) != 0)
380168219Snetchild		goto error_exit;
381168219Snetchild
38239219Sgibbs	return (0);
38345791Speter
38439219Sgibbserror_exit:
38539219Sgibbs	/*
38639219Sgibbs	 * The board's IRQ line will not be left enabled
387241590Sjhb	 * if we can't initialize correctly, so its safe
38839219Sgibbs	 * to release the irq.
38939219Sgibbs	 */
39039219Sgibbs	ahbfree(ahb);
391241590Sjhb	if (irq != NULL)
39245791Speter		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
393241590Sjhb	bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
39439219Sgibbs	return (-1);
39539219Sgibbs}
39639219Sgibbs
39739219Sgibbsstatic struct ahb_softc *
398170872Sscottlahballoc(device_t dev, struct resource *res)
39939219Sgibbs{
40039219Sgibbs	struct	ahb_softc *ahb;
40139219Sgibbs
402241590Sjhb	ahb = device_get_softc(dev);
40339219Sgibbs	SLIST_INIT(&ahb->free_ecbs);
40439219Sgibbs	LIST_INIT(&ahb->pending_ccbs);
405241590Sjhb	ahb->res = res;
40639219Sgibbs	ahb->disc_permitted = ~0;
40739219Sgibbs	ahb->tags_permitted = ~0;
408170872Sscottl	ahb->dev = dev;
409241590Sjhb	mtx_init(&ahb->lock, "ahb", NULL, MTX_DEF);
41039219Sgibbs
41139219Sgibbs	return (ahb);
41239219Sgibbs}
41339219Sgibbs
41439219Sgibbsstatic void
41539219Sgibbsahbfree(struct ahb_softc *ahb)
41639219Sgibbs{
41739219Sgibbs	switch (ahb->init_level) {
41839219Sgibbs	default:
41939219Sgibbs	case 4:
42039219Sgibbs		bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap);
42139219Sgibbs	case 3:
42239219Sgibbs		bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array,
42339219Sgibbs				ahb->ecb_dmamap);
42439219Sgibbs		bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap);
42539219Sgibbs	case 2:
42639219Sgibbs		bus_dma_tag_destroy(ahb->ecb_dmat);
42739219Sgibbs	case 1:
42839219Sgibbs		bus_dma_tag_destroy(ahb->buffer_dmat);
42939219Sgibbs	case 0:
43097208Speter		break;
43139219Sgibbs	}
432241590Sjhb	mtx_destroy(&ahb->lock);
43339219Sgibbs}
43439219Sgibbs
43539219Sgibbs/*
43639219Sgibbs * reset board, If it doesn't respond, return failure
43739219Sgibbs */
43839219Sgibbsstatic int
43939219Sgibbsahbreset(struct ahb_softc *ahb)
44039219Sgibbs{
44139219Sgibbs	int	wait = 1000;	/* 1 sec enough? */
44239219Sgibbs	int	test;
44339219Sgibbs
44439219Sgibbs	if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {
44539219Sgibbs		printf("ahb_reset: Controller not in enhanced mode\n");
44639219Sgibbs		return (-1);
44739219Sgibbs	}
44839219Sgibbs
44939219Sgibbs	ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);
45039219Sgibbs	DELAY(1000);
45139219Sgibbs	ahb_outb(ahb, CONTROL, 0);
45239219Sgibbs	while (--wait) {
45339219Sgibbs		DELAY(1000);
45439219Sgibbs		if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)
45539219Sgibbs			break;
45639219Sgibbs	}
45739219Sgibbs
45839219Sgibbs	if (wait == 0) {
45939219Sgibbs		printf("ahbreset: No answer from aha1742 board\n");
46039219Sgibbs		return (-1);
46139219Sgibbs	}
46239219Sgibbs	if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {
46339219Sgibbs		printf("ahb_reset: self test failed, val = 0x%x\n", test);
46439219Sgibbs		return (-1);
46539219Sgibbs	}
46639219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
46739219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
46839219Sgibbs		DELAY(10000);
46939219Sgibbs	}
47039219Sgibbs	return (0);
47139219Sgibbs}
47239219Sgibbs
47339219Sgibbsstatic void
47439219Sgibbsahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
47539219Sgibbs{
47639219Sgibbs	struct ahb_softc* ahb;
47739219Sgibbs
47839219Sgibbs	ahb = (struct ahb_softc*)arg;
47939219Sgibbs	ahb->ecb_physbase = segs->ds_addr;
48039219Sgibbs	/*
48139219Sgibbs	 * Space for adapter inquiry information is on the
48239219Sgibbs	 * tail of the ecb array.
48339219Sgibbs	 */
48439219Sgibbs	ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);
48539219Sgibbs}
48639219Sgibbs
48739219Sgibbsstatic int
48839219Sgibbsahbxptattach(struct ahb_softc *ahb)
48939219Sgibbs{
49039219Sgibbs	struct cam_devq *devq;
49139219Sgibbs	struct ecb *ecb;
49239219Sgibbs	u_int  i;
49339219Sgibbs
494241590Sjhb	mtx_lock(&ahb->lock);
495241590Sjhb
496241590Sjhb	/* Remember who are we on the scsi bus */
49739219Sgibbs	ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;
49839219Sgibbs
49939219Sgibbs	/* Use extended translation?? */
50039219Sgibbs    	ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;
50139219Sgibbs
50239219Sgibbs	/* Fetch adapter inquiry data */
50339219Sgibbs	ecb = ahbecbget(ahb);	/* Always succeeds - no outstanding commands */
50439219Sgibbs	ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;
50539219Sgibbs	ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;
50639219Sgibbs	ecb->hecb.data_ptr = ahb->ha_inq_physbase;
50739219Sgibbs	ecb->hecb.data_len = sizeof(struct ha_inquiry_data);
50839219Sgibbs	ecb->hecb.sense_ptr = 0;
50939219Sgibbs	ecb->state = ECB_ACTIVE;
51039219Sgibbs
51139219Sgibbs	/* Tell the adapter about this command */
51239219Sgibbs	ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),
51339219Sgibbs		     ATTN_STARTECB|ahb->scsi_id);
51439219Sgibbs
51539219Sgibbs	/* Poll for interrupt completion */
51639219Sgibbs	for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {
517241590Sjhb		ahbintr_locked(ahb);
51839219Sgibbs		DELAY(1000);
51939219Sgibbs	}
52039219Sgibbs
52139219Sgibbs	ahb->num_ecbs = MIN(ahb->num_ecbs,
522159105Smjacob			    ahb->ha_inq_data->scsi_data.spc2_flags);
523241590Sjhb	device_printf(ahb->dev,
524241590Sjhb	       "%.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",
525241590Sjhb	       ahb->ha_inq_data->scsi_data.product,
52639219Sgibbs	       (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"
52739219Sgibbs							 : "Single Ended",
52839219Sgibbs	       ahb->ha_inq_data->scsi_data.revision,
52939219Sgibbs	       ahb->scsi_id, ahb->num_ecbs);
53039219Sgibbs
53139219Sgibbs	/* Restore sense paddr for future CCB clients */
53239219Sgibbs	ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));
53339219Sgibbs
53439219Sgibbs	ahbecbfree(ahb, ecb);
53539219Sgibbs
53639219Sgibbs	/*
53739219Sgibbs	 * Create the device queue for our SIM.
53839219Sgibbs	 */
53939219Sgibbs	devq = cam_simq_alloc(ahb->num_ecbs);
540241590Sjhb	if (devq == NULL) {
541241590Sjhb		mtx_unlock(&ahb->lock);
54239219Sgibbs		return (ENOMEM);
543241590Sjhb	}
54439219Sgibbs
54539219Sgibbs	/*
54639219Sgibbs	 * Construct our SIM entry
54739219Sgibbs	 */
548241590Sjhb	ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb,
549241590Sjhb	    device_get_unit(ahb->dev), &ahb->lock, 2, ahb->num_ecbs, devq);
55039219Sgibbs	if (ahb->sim == NULL) {
55139219Sgibbs		cam_simq_free(devq);
552241590Sjhb		mtx_unlock(&ahb->lock);
55339219Sgibbs		return (ENOMEM);
55439219Sgibbs	}
55539219Sgibbs
556170872Sscottl	if (xpt_bus_register(ahb->sim, ahb->dev, 0) != CAM_SUCCESS) {
55739219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
558241590Sjhb		mtx_unlock(&ahb->lock);
55939219Sgibbs		return (ENXIO);
56039219Sgibbs	}
56139219Sgibbs
56239219Sgibbs	if (xpt_create_path(&ahb->path, /*periph*/NULL,
56339219Sgibbs			    cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,
56439219Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
56539219Sgibbs		xpt_bus_deregister(cam_sim_path(ahb->sim));
56639219Sgibbs		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
567241590Sjhb		mtx_unlock(&ahb->lock);
56839219Sgibbs		return (ENXIO);
56939219Sgibbs	}
57039219Sgibbs
57139219Sgibbs	/*
57239219Sgibbs	 * Allow the board to generate interrupts.
57339219Sgibbs	 */
57439219Sgibbs	ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);
575241590Sjhb	mtx_unlock(&ahb->lock);
57639219Sgibbs
57739219Sgibbs	return (0);
57839219Sgibbs}
57939219Sgibbs
58039219Sgibbsstatic void
58139219Sgibbsahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
58239219Sgibbs{
58339219Sgibbs	struct ccb_hdr *ccb_h;
58439219Sgibbs	u_int target_id;
58539219Sgibbs
58639219Sgibbs	if (ahb->immed_cmd == 0) {
587241590Sjhb		device_printf(ahb->dev, "Immediate Command complete with no "
588241590Sjhb		       " pending command\n");
58939219Sgibbs		return;
59039219Sgibbs	}
59139219Sgibbs
59239219Sgibbs	target_id = intstat & INTSTAT_TARGET_MASK;
59339219Sgibbs
59439219Sgibbs	ccb_h = LIST_FIRST(&ahb->pending_ccbs);
59539219Sgibbs	while (ccb_h != NULL) {
59639219Sgibbs		struct ecb *pending_ecb;
59739219Sgibbs		union ccb *ccb;
59839219Sgibbs
59939219Sgibbs		pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
60039219Sgibbs		ccb = pending_ecb->ccb;
60139219Sgibbs		ccb_h = LIST_NEXT(ccb_h, sim_links.le);
60239219Sgibbs		if (ccb->ccb_h.target_id == target_id
60339219Sgibbs		 || target_id == ahb->scsi_id) {
604241590Sjhb			callout_stop(&pending_ecb->timer);
60539219Sgibbs			LIST_REMOVE(&ccb->ccb_h, sim_links.le);
60639219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
60739219Sgibbs				bus_dmamap_unload(ahb->buffer_dmat,
60839219Sgibbs						  pending_ecb->dmamap);
60939219Sgibbs			if (pending_ecb == ahb->immed_ecb)
61039219Sgibbs				ccb->ccb_h.status =
61139219Sgibbs				    CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;
61239219Sgibbs			else if (target_id == ahb->scsi_id)
61339219Sgibbs				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
61439219Sgibbs			else
61539219Sgibbs				ccb->ccb_h.status = CAM_BDR_SENT;
61639219Sgibbs			ahbecbfree(ahb, pending_ecb);
61739219Sgibbs			xpt_done(ccb);
61839219Sgibbs		} else if (ahb->immed_ecb != NULL) {
61939219Sgibbs			/* Re-instate timeout */
620241590Sjhb			callout_reset(&pending_ecb->timer,
621241590Sjhb			    (ccb->ccb_h.timeout * hz) / 1000,
622241590Sjhb			    ahbtimeout, pending_ecb);
62339219Sgibbs		}
62439219Sgibbs	}
62539219Sgibbs
62639219Sgibbs	if (ahb->immed_ecb != NULL) {
62739219Sgibbs		ahb->immed_ecb = NULL;
628241590Sjhb		device_printf(ahb->dev, "No longer in timeout\n");
62939219Sgibbs	} else if (target_id == ahb->scsi_id)
630241590Sjhb		device_printf(ahb->dev, "SCSI Bus Reset Delivered\n");
63139219Sgibbs	else
632241590Sjhb		device_printf(ahb->dev,
633241590Sjhb		    "Bus Device Reset Delivered to target %d\n", target_id);
63439219Sgibbs
63539219Sgibbs	ahb->immed_cmd = 0;
63639219Sgibbs}
63739219Sgibbs
63839219Sgibbsstatic void
63939219Sgibbsahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
64039219Sgibbs{
64139219Sgibbs	if (ecb->status.data_overrun != 0) {
64239219Sgibbs		/*
64339219Sgibbs		 * Overrun Condition.  The hardware doesn't
64439219Sgibbs		 * provide a meaningful byte count in this case
64539219Sgibbs		 * (the residual is always 0).  Tell the XPT
64639219Sgibbs		 * layer about the error.
64739219Sgibbs		 */
64839219Sgibbs		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
64939219Sgibbs	} else {
65039219Sgibbs		ccb->csio.resid = ecb->status.resid_count;
65139219Sgibbs
65239219Sgibbs		if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {
65339219Sgibbs			/*
65439219Sgibbs			 * For S/G transfers, the adapter provides a pointer
65539219Sgibbs			 * to the address in the last S/G element used and a
65639219Sgibbs			 * residual for that element.  So, we need to sum up
65739219Sgibbs			 * the elements that follow it in order to get a real
65839219Sgibbs			 * residual number.  If we have an overrun, the residual
65939219Sgibbs			 * reported will be 0 and we already know that all S/G
66039219Sgibbs			 * segments have been exhausted, so we can skip this
66139219Sgibbs			 * step.
66239219Sgibbs			 */
66339219Sgibbs			ahb_sg_t *sg;
66439219Sgibbs			int	  num_sg;
66539219Sgibbs
66639219Sgibbs			num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);
66739219Sgibbs
66839219Sgibbs			/* Find the S/G the adapter was working on */
66939219Sgibbs			for (sg = ecb->sg_list;
67039219Sgibbs			     num_sg != 0 && sg->addr != ecb->status.resid_addr;
67139219Sgibbs			     num_sg--, sg++)
67239219Sgibbs				;
67339219Sgibbs
67439219Sgibbs			/* Skip it */
67539219Sgibbs			num_sg--;
67639219Sgibbs			sg++;
67739219Sgibbs
67839219Sgibbs			/* Sum the rest */
67939219Sgibbs			for (; num_sg != 0; num_sg--, sg++)
68039219Sgibbs				ccb->csio.resid += sg->len;
68139219Sgibbs		}
68239219Sgibbs		/* Underruns are not errors */
68339219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
68439219Sgibbs	}
68539219Sgibbs}
68639219Sgibbs
68739219Sgibbsstatic void
68839219Sgibbsahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
68939219Sgibbs{
69039219Sgibbs	struct hardware_ecb *hecb;
69139219Sgibbs	struct ecb_status *status;
69239219Sgibbs
69339219Sgibbs	hecb = &ecb->hecb;
69439219Sgibbs	status = &ecb->status;
69539219Sgibbs	switch (status->ha_status) {
69639219Sgibbs	case HS_OK:
69739219Sgibbs		ccb->csio.scsi_status = status->scsi_status;
69839219Sgibbs		if (status->scsi_status != 0) {
69939219Sgibbs			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
70039219Sgibbs			if (status->sense_stored) {
70139219Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
70239219Sgibbs				ccb->csio.sense_resid =
70339219Sgibbs				    ccb->csio.sense_len - status->sense_len;
70439219Sgibbs				bcopy(&ecb->sense, &ccb->csio.sense_data,
70539219Sgibbs				      status->sense_len);
70639219Sgibbs			}
70739219Sgibbs		}
70839219Sgibbs		break;
70939219Sgibbs	case HS_TARGET_NOT_ASSIGNED:
71039219Sgibbs		ccb->ccb_h.status = CAM_PATH_INVALID;
71139219Sgibbs		break;
71239219Sgibbs	case HS_SEL_TIMEOUT:
71339219Sgibbs		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
71439219Sgibbs		break;
71539219Sgibbs	case HS_DATA_RUN_ERR:
71639219Sgibbs		ahbcalcresid(ahb, ecb, ccb);
71739219Sgibbs		break;
71839219Sgibbs	case HS_UNEXPECTED_BUSFREE:
71939219Sgibbs		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
72039219Sgibbs		break;
72139219Sgibbs	case HS_INVALID_PHASE:
72239219Sgibbs		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
72339219Sgibbs		break;
72439219Sgibbs	case HS_REQUEST_SENSE_FAILED:
72539219Sgibbs		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
72639219Sgibbs		break;
72739219Sgibbs	case HS_TAG_MSG_REJECTED:
72839219Sgibbs	{
72939219Sgibbs		struct ccb_trans_settings neg;
730163816Smjacob		struct ccb_trans_settings_scsi *scsi = &neg.proto_specific.scsi;
73139219Sgibbs
73239219Sgibbs		xpt_print_path(ccb->ccb_h.path);
73339219Sgibbs		printf("refuses tagged commands.  Performing "
73439219Sgibbs		       "non-tagged I/O\n");
735163816Smjacob		memset(&neg, 0, sizeof (neg));
736163816Smjacob		neg.protocol = PROTO_SCSI;
737163816Smjacob		neg.protocol_version = SCSI_REV_2;
738163816Smjacob		neg.transport = XPORT_SPI;
739163816Smjacob		neg.transport_version = 2;
740163816Smjacob		scsi->flags = CTS_SCSI_VALID_TQ;
74139219Sgibbs		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
74239219Sgibbs		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
74339219Sgibbs		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
74439219Sgibbs		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
74539219Sgibbs		break;
74639219Sgibbs	}
74739219Sgibbs	case HS_FIRMWARE_LOAD_REQ:
74839219Sgibbs	case HS_HARDWARE_ERR:
74939219Sgibbs		/*
75039219Sgibbs		 * Tell the system that the Adapter
75139219Sgibbs		 * is no longer functional.
75239219Sgibbs		 */
75339219Sgibbs		ccb->ccb_h.status = CAM_NO_HBA;
75439219Sgibbs		break;
75539219Sgibbs	case HS_CMD_ABORTED_HOST:
75639219Sgibbs	case HS_CMD_ABORTED_ADAPTER:
75739219Sgibbs	case HS_ATN_TARGET_FAILED:
75839219Sgibbs	case HS_SCSI_RESET_ADAPTER:
75939219Sgibbs	case HS_SCSI_RESET_INCOMING:
76039219Sgibbs		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
76139219Sgibbs		break;
76249360Smdodd	case HS_INVALID_ECB_PARAM:
763241590Sjhb		device_printf(ahb->dev,
764241590Sjhb		    "opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
765241590Sjhb		    hecb->opcode, hecb->flag_word1, hecb->flag_word2);
76649360Smdodd		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
76749360Smdodd		break;
76839219Sgibbs	case HS_DUP_TCB_RECEIVED:
76939219Sgibbs	case HS_INVALID_OPCODE:
77039219Sgibbs	case HS_INVALID_CMD_LINK:
77139219Sgibbs	case HS_PROGRAM_CKSUM_ERROR:
772241590Sjhb		panic("%s: Can't happen host status %x occurred",
773241590Sjhb		    device_get_nameunit(ahb->dev), status->ha_status);
77439219Sgibbs		break;
77539219Sgibbs	}
77639219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_CMP) {
77739219Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
77839219Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
77939219Sgibbs	}
78039219Sgibbs}
78139219Sgibbs
78239219Sgibbsstatic void
78339219Sgibbsahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
78439219Sgibbs{
78539219Sgibbs	struct ecb *ecb;
78639219Sgibbs	union ccb *ccb;
78739219Sgibbs
78839219Sgibbs	ecb = ahbecbptov(ahb, mbox);
78939219Sgibbs
79039219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0)
79139219Sgibbs		panic("ecb not active");
79239219Sgibbs
79339219Sgibbs	ccb = ecb->ccb;
79439219Sgibbs
79539219Sgibbs	if (ccb != NULL) {
796241590Sjhb		callout_stop(&ecb->timer);
79739219Sgibbs		LIST_REMOVE(&ccb->ccb_h, sim_links.le);
79839219Sgibbs
79939219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
800115343Sscottl			bus_dmasync_op_t op;
80139219Sgibbs
80239219Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
80339219Sgibbs				op = BUS_DMASYNC_POSTREAD;
80439219Sgibbs			else
80539219Sgibbs				op = BUS_DMASYNC_POSTWRITE;
80639219Sgibbs			bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
80739219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
80839219Sgibbs		}
80939219Sgibbs
81039219Sgibbs		if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {
81139219Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
81239219Sgibbs			ccb->csio.resid = 0;
81339219Sgibbs		} else {
81439219Sgibbs			ahbprocesserror(ahb, ecb, ccb);
81539219Sgibbs		}
81639219Sgibbs		ahbecbfree(ahb, ecb);
81739219Sgibbs		xpt_done(ccb);
81839219Sgibbs	} else {
81939219Sgibbs		/* Non CCB Command */
82039219Sgibbs		if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {
821241590Sjhb			device_printf(ahb->dev, "Command 0%x Failed %x:%x:%x\n",
822241590Sjhb			       ecb->hecb.opcode,
82339219Sgibbs			       *((u_int16_t*)&ecb->status),
82439219Sgibbs			       ecb->status.ha_status, ecb->status.resid_count);
82539219Sgibbs		}
82639219Sgibbs		/* Client owns this ECB and will release it. */
82739219Sgibbs	}
82839219Sgibbs}
82939219Sgibbs
83039219Sgibbs/*
83139219Sgibbs * Catch an interrupt from the adaptor
83239219Sgibbs */
83339219Sgibbsstatic void
83439219Sgibbsahbintr(void *arg)
83539219Sgibbs{
83639219Sgibbs	struct	  ahb_softc *ahb;
837241590Sjhb
838241590Sjhb	ahb = arg;
839241590Sjhb	mtx_lock(&ahb->lock);
840241590Sjhb	ahbintr_locked(ahb);
841241590Sjhb	mtx_unlock(&ahb->lock);
842241590Sjhb}
843241590Sjhb
844241590Sjhbstatic void
845241590Sjhbahbintr_locked(struct ahb_softc *ahb)
846241590Sjhb{
84739219Sgibbs	u_int	  intstat;
84839219Sgibbs	u_int32_t mbox;
84939219Sgibbs
85039219Sgibbs	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
85139219Sgibbs		/*
85239219Sgibbs		 * Fetch information about this interrupt.
85339219Sgibbs		 */
85439219Sgibbs		intstat = ahb_inb(ahb, INTSTAT);
85539219Sgibbs		mbox = ahb_inl(ahb, MBOXIN0);
85639219Sgibbs
85739219Sgibbs		/*
85839219Sgibbs		 * Reset interrupt latch.
85939219Sgibbs		 */
86039219Sgibbs		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
86139219Sgibbs
86239219Sgibbs		/*
86339219Sgibbs		 * Process the completed operation
86439219Sgibbs		 */
86539219Sgibbs		switch (intstat & INTSTAT_MASK) {
86639219Sgibbs		case INTSTAT_ECB_OK:
86739219Sgibbs		case INTSTAT_ECB_CMPWRETRY:
86839219Sgibbs		case INTSTAT_ECB_CMPWERR:
86939219Sgibbs			ahbdone(ahb, mbox, intstat);
87039219Sgibbs			break;
87139219Sgibbs		case INTSTAT_AEN_OCCURED:
87239219Sgibbs			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
87339219Sgibbs				/* Bus Reset */
87439219Sgibbs				xpt_print_path(ahb->path);
87539219Sgibbs				switch (mbox) {
87639219Sgibbs				case HS_SCSI_RESET_ADAPTER:
87739219Sgibbs					printf("Host Adapter Initiated "
87839219Sgibbs					       "Bus Reset occurred\n");
87939219Sgibbs					break;
88039219Sgibbs				case HS_SCSI_RESET_INCOMING:
88139219Sgibbs					printf("Bus Reset Initiated "
88239219Sgibbs					       "by another device occurred\n");
88339219Sgibbs					break;
88439219Sgibbs				}
88539219Sgibbs				/* Notify the XPT */
88639219Sgibbs				xpt_async(AC_BUS_RESET, ahb->path, NULL);
88739219Sgibbs				break;
88839219Sgibbs			}
88939219Sgibbs			printf("Unsupported initiator selection AEN occured\n");
89039219Sgibbs			break;
89139219Sgibbs		case INTSTAT_IMMED_OK:
89239219Sgibbs		case INTSTAT_IMMED_ERR:
89339219Sgibbs			ahbhandleimmed(ahb, mbox, intstat);
89439219Sgibbs			break;
89539219Sgibbs		case INTSTAT_HW_ERR:
89639219Sgibbs			panic("Unrecoverable hardware Error Occurred\n");
89739219Sgibbs		}
89839219Sgibbs	}
89939219Sgibbs}
90039219Sgibbs
90139219Sgibbsstatic void
90239219Sgibbsahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
90339219Sgibbs{
90439219Sgibbs	struct	  ecb *ecb;
90539219Sgibbs	union	  ccb *ccb;
90639219Sgibbs	struct	  ahb_softc *ahb;
90739219Sgibbs	u_int32_t ecb_paddr;
90839219Sgibbs
90939219Sgibbs	ecb = (struct ecb *)arg;
91039219Sgibbs	ccb = ecb->ccb;
91139219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
912241590Sjhb	mtx_assert(&ahb->lock, MA_OWNED);
91339219Sgibbs
91439219Sgibbs	if (error != 0) {
91539219Sgibbs		if (error != EFBIG)
916241590Sjhb			device_printf(ahb->dev,
917241590Sjhb			    "Unexepected error 0x%x returned from "
918241590Sjhb			    "bus_dmamap_load\n", error);
91939219Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
92039219Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
92139219Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
92239219Sgibbs		}
92339219Sgibbs		ahbecbfree(ahb, ecb);
92439219Sgibbs		xpt_done(ccb);
92539219Sgibbs		return;
92639219Sgibbs	}
92739219Sgibbs
92839219Sgibbs	ecb_paddr = ahbecbvtop(ahb, ecb);
92939219Sgibbs
93039219Sgibbs	if (nseg != 0) {
93139219Sgibbs		ahb_sg_t *sg;
93239219Sgibbs		bus_dma_segment_t *end_seg;
933115343Sscottl		bus_dmasync_op_t op;
93439219Sgibbs
93539219Sgibbs		end_seg = dm_segs + nseg;
93639219Sgibbs
93739219Sgibbs		/* Copy the segments into our SG list */
93839219Sgibbs		sg = ecb->sg_list;
93939219Sgibbs		while (dm_segs < end_seg) {
94039219Sgibbs			sg->addr = dm_segs->ds_addr;
94139219Sgibbs			sg->len = dm_segs->ds_len;
94239219Sgibbs			sg++;
94339219Sgibbs			dm_segs++;
94439219Sgibbs		}
94539219Sgibbs
94639219Sgibbs		if (nseg > 1) {
94739219Sgibbs			ecb->hecb.flag_word1 |= FW1_SG_ECB;
94839219Sgibbs			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
94939219Sgibbs			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
95039219Sgibbs		} else {
95139219Sgibbs			ecb->hecb.data_ptr = ecb->sg_list->addr;
95239219Sgibbs			ecb->hecb.data_len = ecb->sg_list->len;
95339219Sgibbs		}
95439219Sgibbs
95539219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
95639219Sgibbs/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
95739219Sgibbs			op = BUS_DMASYNC_PREREAD;
95839219Sgibbs		} else {
95939219Sgibbs			op = BUS_DMASYNC_PREWRITE;
96039219Sgibbs		}
96139219Sgibbs		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */
96239219Sgibbs
96339219Sgibbs		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
96439219Sgibbs
96539219Sgibbs	} else {
96639219Sgibbs		ecb->hecb.data_ptr = 0;
96739219Sgibbs		ecb->hecb.data_len = 0;
96839219Sgibbs	}
96939219Sgibbs
97039219Sgibbs	/*
97139219Sgibbs	 * Last time we need to check if this CCB needs to
97239219Sgibbs	 * be aborted.
97339219Sgibbs	 */
97439219Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
97539219Sgibbs		if (nseg != 0)
97639219Sgibbs			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
97739219Sgibbs		ahbecbfree(ahb, ecb);
97839219Sgibbs		xpt_done(ccb);
97939219Sgibbs		return;
98039219Sgibbs	}
98139219Sgibbs
98239219Sgibbs	ecb->state = ECB_ACTIVE;
98339219Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
98439219Sgibbs	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);
98539219Sgibbs
98639219Sgibbs	/* Tell the adapter about this command */
98739219Sgibbs	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);
98839219Sgibbs
989241590Sjhb	callout_reset(&ecb->timer, (ccb->ccb_h.timeout * hz) / 1000, ahbtimeout,
990241590Sjhb	    ecb);
99139219Sgibbs}
99239219Sgibbs
99339219Sgibbsstatic void
99439219Sgibbsahbaction(struct cam_sim *sim, union ccb *ccb)
99539219Sgibbs{
99639219Sgibbs	struct	ahb_softc *ahb;
99739219Sgibbs
99839219Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
99939219Sgibbs
100039219Sgibbs	ahb = (struct ahb_softc *)cam_sim_softc(sim);
1001241590Sjhb	mtx_assert(&ahb->lock, MA_OWNED);
100239219Sgibbs
100339219Sgibbs	switch (ccb->ccb_h.func_code) {
100439219Sgibbs	/* Common cases first */
100539219Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
100639219Sgibbs	{
100739219Sgibbs		struct ecb *ecb;
100839219Sgibbs		struct hardware_ecb *hecb;
1009246713Skib		int error;
101039219Sgibbs
101139219Sgibbs		/*
101239219Sgibbs		 * get an ecb to use.
101339219Sgibbs		 */
101439219Sgibbs		if ((ecb = ahbecbget(ahb)) == NULL) {
101539219Sgibbs			/* Should never occur */
101639219Sgibbs			panic("Failed to get an ecb");
101739219Sgibbs		}
101839219Sgibbs
101939219Sgibbs		/*
102039219Sgibbs		 * So we can find the ECB when an abort is requested
102139219Sgibbs		 */
102239219Sgibbs		ecb->ccb = ccb;
102339219Sgibbs		ccb->ccb_h.ccb_ecb_ptr = ecb;
102439219Sgibbs		ccb->ccb_h.ccb_ahb_ptr = ahb;
102539219Sgibbs
102639219Sgibbs		/*
102739219Sgibbs		 * Put all the arguments for the xfer in the ecb
102839219Sgibbs		 */
102939219Sgibbs		hecb = &ecb->hecb;
103039219Sgibbs		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
103139219Sgibbs		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
103239219Sgibbs				 | FW1_ERR_STATUS_BLK_ONLY;
103339219Sgibbs		hecb->flag_word2 = ccb->ccb_h.target_lun
103439219Sgibbs				 | FW2_NO_RETRY_ON_BUSY;
103539219Sgibbs		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
103639219Sgibbs			hecb->flag_word2 |= FW2_TAG_ENB
103739219Sgibbs					 | ((ccb->csio.tag_action & 0x3)
103839219Sgibbs					    << FW2_TAG_TYPE_SHIFT);
103939219Sgibbs		}
104039219Sgibbs		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
104139219Sgibbs			hecb->flag_word2 |= FW2_DISABLE_DISC;
104239219Sgibbs		hecb->sense_len = ccb->csio.sense_len;
104339219Sgibbs		hecb->cdb_len = ccb->csio.cdb_len;
104439219Sgibbs		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
104539219Sgibbs			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
104639219Sgibbs				bcopy(ccb->csio.cdb_io.cdb_ptr,
104739219Sgibbs				      hecb->cdb, hecb->cdb_len);
104839219Sgibbs			} else {
104939219Sgibbs				/* I guess I could map it in... */
105039219Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
105139219Sgibbs				ahbecbfree(ahb, ecb);
105239219Sgibbs				xpt_done(ccb);
105339219Sgibbs				return;
105439219Sgibbs			}
105539219Sgibbs		} else {
105639219Sgibbs			bcopy(ccb->csio.cdb_io.cdb_bytes,
105739219Sgibbs			      hecb->cdb, hecb->cdb_len);
105839219Sgibbs		}
105939219Sgibbs
1060246713Skib		error = bus_dmamap_load_ccb(
1061246713Skib		    ahb->buffer_dmat,
1062246713Skib		    ecb->dmamap,
1063246713Skib		    ccb,
1064246713Skib		    ahbexecuteecb,
1065246713Skib		    ecb, /*flags*/0);
1066246713Skib		if (error == EINPROGRESS) {
1067246713Skib			/*
1068246713Skib			 * So as to maintain ordering, freeze the controller
1069246713Skib			 * queue until our mapping is returned.
1070246713Skib			 */
1071246713Skib			xpt_freeze_simq(ahb->sim, 1);
1072246713Skib			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
107339219Sgibbs		}
107439219Sgibbs		break;
107539219Sgibbs	}
107639219Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
107739219Sgibbs	case XPT_TARGET_IO:		/* Execute target I/O request */
107839219Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
107939219Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
108039219Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
108139219Sgibbs		/* XXX Implement */
108239219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
108339219Sgibbs		xpt_done(ccb);
108439219Sgibbs		break;
108539219Sgibbs	case XPT_SET_TRAN_SETTINGS:
108639219Sgibbs	{
108739219Sgibbs		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
108839219Sgibbs		xpt_done(ccb);
108939219Sgibbs		break;
109039219Sgibbs	}
109139219Sgibbs	case XPT_GET_TRAN_SETTINGS:
109239219Sgibbs	/* Get default/user set transfer settings for the target */
109339219Sgibbs	{
1094163816Smjacob		struct	ccb_trans_settings *cts = &ccb->cts;
1095163816Smjacob		u_int	target_mask = 0x01 << ccb->ccb_h.target_id;
1096163816Smjacob		struct ccb_trans_settings_scsi *scsi =
1097163816Smjacob		    &cts->proto_specific.scsi;
1098163816Smjacob		struct ccb_trans_settings_spi *spi =
1099163816Smjacob		    &cts->xport_specific.spi;
110039219Sgibbs
1101163816Smjacob		if (cts->type == CTS_TYPE_USER_SETTINGS) {
1102163816Smjacob			cts->protocol = PROTO_SCSI;
1103163816Smjacob			cts->protocol_version = SCSI_REV_2;
1104163816Smjacob			cts->transport = XPORT_SPI;
1105163816Smjacob			cts->transport_version = 2;
1106163816Smjacob
1107163816Smjacob			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
1108163816Smjacob			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
1109163816Smjacob			if ((ahb->disc_permitted & target_mask) != 0)
1110163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
1111163816Smjacob			if ((ahb->tags_permitted & target_mask) != 0)
1112163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
1113163816Smjacob			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1114163816Smjacob			spi->sync_period = 25; /* 10MHz */
1115163816Smjacob
1116163816Smjacob			if (spi->sync_period != 0)
1117163816Smjacob				spi->sync_offset = 15;
1118163816Smjacob
1119163816Smjacob			spi->valid = CTS_SPI_VALID_SYNC_RATE
1120163816Smjacob				   | CTS_SPI_VALID_SYNC_OFFSET
1121163816Smjacob				   | CTS_SPI_VALID_BUS_WIDTH
1122163816Smjacob				   | CTS_SPI_VALID_DISC;
1123163816Smjacob			scsi->valid = CTS_SCSI_VALID_TQ;
1124163816Smjacob			ccb->ccb_h.status = CAM_REQ_CMP;
1125163816Smjacob		} else {
1126163816Smjacob			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1127163816Smjacob		}
112839219Sgibbs		xpt_done(ccb);
112939219Sgibbs		break;
113039219Sgibbs	}
113139219Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
113239219Sgibbs	{
113339219Sgibbs		int i;
113439219Sgibbs
113539219Sgibbs		ahb->immed_cmd = IMMED_RESET;
113639219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
113739219Sgibbs		/* Poll for interrupt completion */
113844508Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
113939219Sgibbs			DELAY(1000);
1140241590Sjhb			ahbintr_locked(cam_sim_softc(sim));
114144508Sgibbs		}
114239219Sgibbs		break;
114339219Sgibbs	}
114439219Sgibbs	case XPT_CALC_GEOMETRY:
114539219Sgibbs	{
1146116351Snjl		cam_calc_geometry(&ccb->ccg, ahb->extended_trans);
114739219Sgibbs		xpt_done(ccb);
114839219Sgibbs		break;
114939219Sgibbs	}
115039219Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
115139219Sgibbs	{
115239219Sgibbs		int i;
115339219Sgibbs
115439219Sgibbs		ahb->immed_cmd = IMMED_RESET;
115539219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
115639219Sgibbs		/* Poll for interrupt completion */
115739219Sgibbs		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
115839219Sgibbs			DELAY(1000);
115939219Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
116039219Sgibbs		xpt_done(ccb);
116139219Sgibbs		break;
116239219Sgibbs	}
116339219Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
116439219Sgibbs		/* XXX Implement */
116539219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
116639219Sgibbs		xpt_done(ccb);
116739219Sgibbs		break;
116839219Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
116939219Sgibbs	{
117039219Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
117139219Sgibbs
117239219Sgibbs		cpi->version_num = 1; /* XXX??? */
117339219Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
117439219Sgibbs		cpi->target_sprt = 0;
117539219Sgibbs		cpi->hba_misc = 0;
117639219Sgibbs		cpi->hba_eng_cnt = 0;
117739219Sgibbs		cpi->max_target = 7;
117839219Sgibbs		cpi->max_lun = 7;
117939219Sgibbs		cpi->initiator_id = ahb->scsi_id;
118039219Sgibbs		cpi->bus_id = cam_sim_bus(sim);
118146581Sken		cpi->base_transfer_speed = 3300;
118239219Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
118339219Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
118439219Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
118539219Sgibbs		cpi->unit_number = cam_sim_unit(sim);
1186163816Smjacob                cpi->transport = XPORT_SPI;
1187163816Smjacob                cpi->transport_version = 2;
1188163816Smjacob                cpi->protocol = PROTO_SCSI;
1189163816Smjacob                cpi->protocol_version = SCSI_REV_2;
119039219Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
119139219Sgibbs		xpt_done(ccb);
119239219Sgibbs		break;
119339219Sgibbs	}
119439219Sgibbs#if 0
119539219Sgibbs	/* Need these??? */
119639219Sgibbs        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */
119739219Sgibbs        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */
119839219Sgibbs#endif
119939219Sgibbs	default:
120039219Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
120139219Sgibbs		xpt_done(ccb);
120239219Sgibbs		break;
120339219Sgibbs	}
120439219Sgibbs}
120539219Sgibbs
120639219Sgibbsstatic void
120739219Sgibbsahbpoll(struct cam_sim *sim)
120839219Sgibbs{
120940132Sgibbs	ahbintr(cam_sim_softc(sim));
121039219Sgibbs}
121139219Sgibbs
121245577Seivindstatic void
121339219Sgibbsahbtimeout(void *arg)
121439219Sgibbs{
121539219Sgibbs	struct ecb	 *ecb;
121639219Sgibbs	union  ccb	 *ccb;
121739219Sgibbs	struct ahb_softc *ahb;
121839219Sgibbs
121939219Sgibbs	ecb = (struct ecb *)arg;
122039219Sgibbs	ccb = ecb->ccb;
122139219Sgibbs	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
1222241590Sjhb	mtx_assert(&ahb->lock, MA_OWNED);
122339219Sgibbs	xpt_print_path(ccb->ccb_h.path);
122439390Sgibbs	printf("ECB %p - timed out\n", (void *)ecb);
122539219Sgibbs
122639219Sgibbs	if ((ecb->state & ECB_ACTIVE) == 0) {
122739219Sgibbs		xpt_print_path(ccb->ccb_h.path);
122839390Sgibbs		printf("ECB %p - timed out ECB already completed\n",
122939390Sgibbs		       (void *)ecb);
123039219Sgibbs		return;
123139219Sgibbs	}
123239219Sgibbs	/*
123339219Sgibbs	 * In order to simplify the recovery process, we ask the XPT
123439219Sgibbs	 * layer to halt the queue of new transactions and we traverse
123539219Sgibbs	 * the list of pending CCBs and remove their timeouts. This
123639219Sgibbs	 * means that the driver attempts to clear only one error
123739219Sgibbs	 * condition at a time.  In general, timeouts that occur
123839219Sgibbs	 * close together are related anyway, so there is no benefit
123939219Sgibbs	 * in attempting to handle errors in parrallel.  Timeouts will
124039219Sgibbs	 * be reinstated when the recovery process ends.
124139219Sgibbs	 */
124239219Sgibbs	if ((ecb->state & ECB_DEVICE_RESET) == 0) {
124339219Sgibbs		struct ccb_hdr *ccb_h;
124439219Sgibbs
124539219Sgibbs		if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {
124639219Sgibbs			xpt_freeze_simq(ahb->sim, /*count*/1);
124739219Sgibbs			ecb->state |= ECB_RELEASE_SIMQ;
124839219Sgibbs		}
124939219Sgibbs
1250241590Sjhb		LIST_FOREACH(ccb_h, &ahb->pending_ccbs, sim_links.le) {
125139219Sgibbs			struct ecb *pending_ecb;
125239219Sgibbs
125339219Sgibbs			pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
1254241590Sjhb			callout_stop(&pending_ecb->timer);
125539219Sgibbs		}
125639219Sgibbs
125739219Sgibbs		/* Store for our interrupt handler */
125839219Sgibbs		ahb->immed_ecb = ecb;
125939219Sgibbs
126039219Sgibbs		/*
126139219Sgibbs		 * Send a Bus Device Reset message:
126239219Sgibbs		 * The target that is holding up the bus may not
126339219Sgibbs		 * be the same as the one that triggered this timeout
126439219Sgibbs		 * (different commands have different timeout lengths),
126539219Sgibbs		 * but we have no way of determining this from our
126639219Sgibbs		 * timeout handler.  Our strategy here is to queue a
126739219Sgibbs		 * BDR message to the target of the timed out command.
126839219Sgibbs		 * If this fails, we'll get another timeout 2 seconds
126939219Sgibbs		 * later which will attempt a bus reset.
127039219Sgibbs		 */
127139219Sgibbs		xpt_print_path(ccb->ccb_h.path);
127239324Sgibbs		printf("Queuing BDR\n");
127339219Sgibbs		ecb->state |= ECB_DEVICE_RESET;
1274241590Sjhb		callout_reset(&ecb->timer, 2 * hz, ahbtimeout, ecb);
127539219Sgibbs
127639219Sgibbs		ahb->immed_cmd = IMMED_RESET;
127739219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
127839219Sgibbs	} else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {
127939219Sgibbs		/*
128039219Sgibbs		 * Try a SCSI bus reset.  We do this only if we
128139219Sgibbs		 * have already attempted to clear the condition with a BDR.
128239219Sgibbs		 */
128339219Sgibbs		xpt_print_path(ccb->ccb_h.path);
128439324Sgibbs		printf("Attempting SCSI Bus reset\n");
128539219Sgibbs		ecb->state |= ECB_SCSIBUS_RESET;
1286241590Sjhb		callout_reset(&ecb->timer, 2 * hz, ahbtimeout, ecb);
128739219Sgibbs		ahb->immed_cmd = IMMED_RESET;
128839219Sgibbs		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
128939219Sgibbs	} else {
129039219Sgibbs		/* Bring out the hammer... */
129139219Sgibbs		ahbreset(ahb);
129239219Sgibbs
129339219Sgibbs		/* Simulate the reset complete interrupt */
129439219Sgibbs		ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);
129539219Sgibbs	}
129639219Sgibbs}
129739219Sgibbs
129845791Speterstatic device_method_t ahb_eisa_methods[] = {
129945791Speter	/* Device interface */
130045791Speter	DEVMETHOD(device_probe,		ahbprobe),
130145791Speter	DEVMETHOD(device_attach,	ahbattach),
130245791Speter
130345791Speter	{ 0, 0 }
130445791Speter};
130545791Speter
130645791Speterstatic driver_t ahb_eisa_driver = {
130745791Speter	"ahb",
130845791Speter	ahb_eisa_methods,
1309241590Sjhb	sizeof(struct ahb_softc),
131045791Speter};
131145791Speter
131245791Speterstatic devclass_t ahb_devclass;
131345791Speter
131445791SpeterDRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0);
1315165102SmjacobMODULE_DEPEND(ahb, eisa, 1, 1, 1);
1316165102SmjacobMODULE_DEPEND(ahb, cam, 1, 1, 1);
1317