ahb.c revision 116351
1/*
2 * CAM SCSI device driver for the Adaptec 174X SCSI Host adapter
3 *
4 * Copyright (c) 1998 Justin T. Gibbs
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice immediately at the beginning of the file, without modification,
12 *    this list of conditions, and the following disclaimer.
13 * 2. The name of the author may not be used to endorse or promote products
14 *    derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/dev/ahb/ahb.c 116351 2003-06-14 22:17:41Z njl $
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35#include <sys/module.h>
36#include <sys/bus.h>
37
38#include <machine/bus_pio.h>
39#include <machine/bus.h>
40#include <machine/resource.h>
41#include <sys/rman.h>
42
43#include <cam/cam.h>
44#include <cam/cam_ccb.h>
45#include <cam/cam_sim.h>
46#include <cam/cam_xpt_sim.h>
47#include <cam/cam_debug.h>
48
49#include <cam/scsi/scsi_message.h>
50
51#include <dev/eisa/eisaconf.h>
52
53#include <dev/ahb/ahbreg.h>
54
55#define ccb_ecb_ptr spriv_ptr0
56#define ccb_ahb_ptr spriv_ptr1
57
58#define ahb_inb(ahb, port)				\
59	bus_space_read_1((ahb)->tag, (ahb)->bsh, port)
60
61#define ahb_inl(ahb, port)				\
62	bus_space_read_4((ahb)->tag, (ahb)->bsh, port)
63
64#define ahb_outb(ahb, port, value)			\
65	bus_space_write_1((ahb)->tag, (ahb)->bsh, port, value)
66
67#define ahb_outl(ahb, port, value)			\
68	bus_space_write_4((ahb)->tag, (ahb)->bsh, port, value)
69
70static const char		*ahbmatch(eisa_id_t type);
71static struct ahb_softc		*ahballoc(u_long unit, struct resource *res);
72static void			 ahbfree(struct ahb_softc *ahb);
73static int			 ahbreset(struct ahb_softc *ahb);
74static void			 ahbmapecbs(void *arg, bus_dma_segment_t *segs,
75					    int nseg, int error);
76static int			 ahbxptattach(struct ahb_softc *ahb);
77static void			 ahbhandleimmed(struct ahb_softc *ahb,
78						u_int32_t mbox, u_int intstat);
79static void			 ahbcalcresid(struct ahb_softc *ahb,
80					      struct ecb *ecb, union ccb *ccb);
81static __inline void		 ahbdone(struct ahb_softc *ahb, u_int32_t mbox,
82					 u_int intstat);
83static void			 ahbintr(void *arg);
84static bus_dmamap_callback_t	 ahbexecuteecb;
85static void			 ahbaction(struct cam_sim *sim, union ccb *ccb);
86static void			 ahbpoll(struct cam_sim *sim);
87
88/* Our timeout handler */
89static timeout_t ahbtimeout;
90
91static __inline struct ecb*	ahbecbget(struct ahb_softc *ahb);
92static __inline void	 	ahbecbfree(struct ahb_softc* ahb,
93					   struct ecb* ecb);
94static __inline u_int32_t	ahbecbvtop(struct ahb_softc *ahb,
95					   struct ecb *ecb);
96static __inline struct ecb*	ahbecbptov(struct ahb_softc *ahb,
97					   u_int32_t ecb_addr);
98static __inline u_int32_t	ahbstatuspaddr(u_int32_t ecb_paddr);
99static __inline u_int32_t	ahbsensepaddr(u_int32_t ecb_paddr);
100static __inline u_int32_t	ahbsgpaddr(u_int32_t ecb_paddr);
101static __inline void		ahbqueuembox(struct ahb_softc *ahb,
102					     u_int32_t mboxval,
103					     u_int attn_code);
104
105static __inline struct ecb*
106ahbecbget(struct ahb_softc *ahb)
107{
108	struct	ecb* ecb;
109	int	s;
110
111	s = splcam();
112	if ((ecb = SLIST_FIRST(&ahb->free_ecbs)) != NULL)
113		SLIST_REMOVE_HEAD(&ahb->free_ecbs, links);
114	splx(s);
115
116	return (ecb);
117}
118
119static __inline void
120ahbecbfree(struct ahb_softc* ahb, struct ecb* ecb)
121{
122	int s;
123
124	s = splcam();
125	ecb->state = ECB_FREE;
126	SLIST_INSERT_HEAD(&ahb->free_ecbs, ecb, links);
127	splx(s);
128}
129
130static __inline u_int32_t
131ahbecbvtop(struct ahb_softc *ahb, struct ecb *ecb)
132{
133	return (ahb->ecb_physbase
134	      + (u_int32_t)((caddr_t)ecb - (caddr_t)ahb->ecb_array));
135}
136
137static __inline struct ecb*
138ahbecbptov(struct ahb_softc *ahb, u_int32_t ecb_addr)
139{
140	return (ahb->ecb_array
141	      + ((struct ecb*)ecb_addr - (struct ecb*)ahb->ecb_physbase));
142}
143
144static __inline u_int32_t
145ahbstatuspaddr(u_int32_t ecb_paddr)
146{
147	return (ecb_paddr + offsetof(struct ecb, status));
148}
149
150static __inline u_int32_t
151ahbsensepaddr(u_int32_t ecb_paddr)
152{
153	return (ecb_paddr + offsetof(struct ecb, sense));
154}
155
156static __inline u_int32_t
157ahbsgpaddr(u_int32_t ecb_paddr)
158{
159	return (ecb_paddr + offsetof(struct ecb, sg_list));
160}
161
162static __inline void
163ahbqueuembox(struct ahb_softc *ahb, u_int32_t mboxval, u_int attn_code)
164{
165	u_int loopmax = 300;
166	while (--loopmax) {
167		u_int status;
168
169		status = ahb_inb(ahb, HOSTSTAT);
170		if ((status & (HOSTSTAT_MBOX_EMPTY|HOSTSTAT_BUSY))
171		   == HOSTSTAT_MBOX_EMPTY)
172			break;
173		DELAY(20);
174	}
175	if (loopmax == 0)
176		panic("ahb%ld: adapter not taking commands\n", ahb->unit);
177
178	ahb_outl(ahb, MBOXOUT0, mboxval);
179	ahb_outb(ahb, ATTN, attn_code);
180}
181
182static const char *
183ahbmatch(eisa_id_t type)
184{
185	switch(type & 0xfffffe00) {
186		case EISA_DEVICE_ID_ADAPTEC_1740:
187			return ("Adaptec 174x SCSI host adapter");
188			break;
189		default:
190			break;
191	}
192	return (NULL);
193}
194
195static int
196ahbprobe(device_t dev)
197{
198	const char *desc;
199	u_int32_t iobase;
200	u_int32_t irq;
201	u_int8_t  intdef;
202	int shared;
203
204	desc = ahbmatch(eisa_get_id(dev));
205	if (!desc)
206	    return (ENXIO);
207	device_set_desc(dev, desc);
208
209	iobase = (eisa_get_slot(dev) * EISA_SLOT_SIZE) +
210	    AHB_EISA_SLOT_OFFSET;
211
212	eisa_add_iospace(dev, iobase, AHB_EISA_IOSIZE, RESVADDR_NONE);
213
214	intdef = inb(INTDEF + iobase);
215	switch (intdef & 0x7) {
216	case INT9:
217	    irq = 9;
218	    break;
219	case INT10:
220	    irq = 10;
221	    break;
222	case INT11:
223	    irq = 11;
224	    break;
225	case INT12:
226	    irq = 12;
227	    break;
228	case INT14:
229	    irq = 14;
230	    break;
231	case INT15:
232	    irq = 15;
233	    break;
234	default:
235	    printf("Adaptec 174X at slot %d: illegal "
236		   "irq setting %d\n", eisa_get_slot(dev),
237		   (intdef & 0x7));
238	    irq = 0;
239	    break;
240	}
241	if (irq == 0)
242	    return ENXIO;
243
244	shared = (inb(INTDEF + iobase) & INTLEVEL) ?
245		 EISA_TRIGGER_LEVEL : EISA_TRIGGER_EDGE;
246
247	eisa_add_intr(dev, irq, shared);
248
249	return 0;
250}
251
252static int
253ahbattach(device_t dev)
254{
255	/*
256	 * find unit and check we have that many defined
257	 */
258	struct	    ahb_softc *ahb;
259	struct	    ecb* next_ecb;
260	struct	    resource *io = 0;
261	struct	    resource *irq = 0;
262	int	    rid;
263	void	    *ih;
264
265	rid = 0;
266	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
267				0, ~0, 1, RF_ACTIVE);
268	if (!io) {
269		device_printf(dev, "No I/O space?!\n");
270		return ENOMEM;
271	}
272
273	if ((ahb = ahballoc(device_get_unit(dev), io)) == NULL) {
274		goto error_exit2;
275	}
276
277	if (ahbreset(ahb) != 0)
278		goto error_exit;
279
280	rid = 0;
281	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
282				 0, ~0, 1, RF_ACTIVE);
283	if (!irq) {
284		device_printf(dev, "Can't allocate interrupt\n");
285		goto error_exit;
286	}
287
288	/*
289	 * Create our DMA tags.  These tags define the kinds of device
290	 * accessible memory allocations and memory mappings we will
291	 * need to perform during normal operation.
292	 */
293	/* DMA tag for mapping buffers into device visible space. */
294	/* XXX Should be a child of the EISA bus dma tag */
295	if (bus_dma_tag_create(	/* parent	*/ NULL,
296				/* alignment	*/ 1,
297				/* boundary	*/ 0,
298				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
299				/* highaddr	*/ BUS_SPACE_MAXADDR,
300				/* filter	*/ NULL,
301				/* filterarg	*/ NULL,
302				/* maxsize	*/ MAXBSIZE,
303				/* nsegments	*/ AHB_NSEG,
304				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
305				/* flags	*/ BUS_DMA_ALLOCNOW,
306				&ahb->buffer_dmat) != 0)
307		goto error_exit;
308
309	ahb->init_level++;
310
311	/* DMA tag for our ccb structures and ha inquiry data */
312	if (bus_dma_tag_create(	/* parent	*/ NULL,
313				/* alignment	*/ 1,
314				/* boundary	*/ 0,
315				/* lowaddr	*/ BUS_SPACE_MAXADDR_32BIT,
316				/* highaddr	*/ BUS_SPACE_MAXADDR,
317				/* filter	*/ NULL,
318				/* filterarg	*/ NULL,
319				/* maxsize	*/ (AHB_NECB *
320						    sizeof(struct ecb))
321						    + sizeof(*ahb->ha_inq_data),
322				/* nsegments	*/ 1,
323				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
324				/* flags	*/ 0,
325				&ahb->ecb_dmat) != 0)
326		goto error_exit;
327
328	ahb->init_level++;
329
330	/* Allocation for our ccbs */
331	if (bus_dmamem_alloc(ahb->ecb_dmat, (void **)&ahb->ecb_array,
332			     BUS_DMA_NOWAIT, &ahb->ecb_dmamap) != 0)
333		goto error_exit;
334
335	ahb->ha_inq_data = (struct ha_inquiry_data *)&ahb->ecb_array[AHB_NECB];
336
337	ahb->init_level++;
338
339	/* And permanently map them */
340	bus_dmamap_load(ahb->ecb_dmat, ahb->ecb_dmamap,
341			ahb->ecb_array, AHB_NSEG * sizeof(struct ecb),
342			ahbmapecbs, ahb, /*flags*/0);
343
344	ahb->init_level++;
345
346	/* Allocate the buffer dmamaps for each of our ECBs */
347	bzero(ahb->ecb_array, (AHB_NECB * sizeof(struct ecb))
348	      + sizeof(*ahb->ha_inq_data));
349	next_ecb = ahb->ecb_array;
350	while (ahb->num_ecbs < AHB_NECB) {
351		u_int32_t ecb_paddr;
352
353		if (bus_dmamap_create(ahb->buffer_dmat, /*flags*/0,
354				      &next_ecb->dmamap))
355			break;
356		ecb_paddr = ahbecbvtop(ahb, next_ecb);
357		next_ecb->hecb.status_ptr = ahbstatuspaddr(ecb_paddr);
358		next_ecb->hecb.sense_ptr = ahbsensepaddr(ecb_paddr);
359		ahb->num_ecbs++;
360		ahbecbfree(ahb, next_ecb);
361		next_ecb++;
362	}
363
364	if (ahb->num_ecbs == 0)
365		goto error_exit;
366
367	ahb->init_level++;
368
369	/*
370	 * Now that we know we own the resources we need, register
371	 * our bus with the XPT.
372	 */
373	if (ahbxptattach(ahb))
374		goto error_exit;
375
376	/* Enable our interrupt */
377	bus_setup_intr(dev, irq, INTR_TYPE_CAM|INTR_ENTROPY, ahbintr, ahb, &ih);
378	return (0);
379
380error_exit:
381	/*
382	 * The board's IRQ line will not be left enabled
383	 * if we can't intialize correctly, so its safe
384	 * to release the irq.
385	 */
386	ahbfree(ahb);
387error_exit2:
388	if (io)
389		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
390	if (irq)
391		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
392	return (-1);
393}
394
395static struct ahb_softc *
396ahballoc(u_long unit, struct resource *res)
397{
398	struct	ahb_softc *ahb;
399
400	/*
401	 * Allocate a storage area for us
402	 */
403	ahb = malloc(sizeof(struct ahb_softc), M_DEVBUF, M_NOWAIT | M_ZERO);
404	if (!ahb) {
405		printf("ahb%ld: cannot malloc!\n", unit);
406		return (NULL);
407	}
408	SLIST_INIT(&ahb->free_ecbs);
409	LIST_INIT(&ahb->pending_ccbs);
410	ahb->unit = unit;
411	ahb->tag = rman_get_bustag(res);
412	ahb->bsh = rman_get_bushandle(res);
413	ahb->disc_permitted = ~0;
414	ahb->tags_permitted = ~0;
415
416	return (ahb);
417}
418
419static void
420ahbfree(struct ahb_softc *ahb)
421{
422	switch (ahb->init_level) {
423	default:
424	case 4:
425		bus_dmamap_unload(ahb->ecb_dmat, ahb->ecb_dmamap);
426	case 3:
427		bus_dmamem_free(ahb->ecb_dmat, ahb->ecb_array,
428				ahb->ecb_dmamap);
429		bus_dmamap_destroy(ahb->ecb_dmat, ahb->ecb_dmamap);
430	case 2:
431		bus_dma_tag_destroy(ahb->ecb_dmat);
432	case 1:
433		bus_dma_tag_destroy(ahb->buffer_dmat);
434	case 0:
435		break;
436	}
437	free(ahb, M_DEVBUF);
438}
439
440/*
441 * reset board, If it doesn't respond, return failure
442 */
443static int
444ahbreset(struct ahb_softc *ahb)
445{
446	int	wait = 1000;	/* 1 sec enough? */
447	int	test;
448
449	if ((ahb_inb(ahb, PORTADDR) & PORTADDR_ENHANCED) == 0) {
450		printf("ahb_reset: Controller not in enhanced mode\n");
451		return (-1);
452	}
453
454	ahb_outb(ahb, CONTROL, CNTRL_HARD_RST);
455	DELAY(1000);
456	ahb_outb(ahb, CONTROL, 0);
457	while (--wait) {
458		DELAY(1000);
459		if ((ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_BUSY) == 0)
460			break;
461	}
462
463	if (wait == 0) {
464		printf("ahbreset: No answer from aha1742 board\n");
465		return (-1);
466	}
467	if ((test = ahb_inb(ahb, MBOXIN0)) != 0) {
468		printf("ahb_reset: self test failed, val = 0x%x\n", test);
469		return (-1);
470	}
471	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
472		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
473		DELAY(10000);
474	}
475	return (0);
476}
477
478static void
479ahbmapecbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
480{
481	struct ahb_softc* ahb;
482
483	ahb = (struct ahb_softc*)arg;
484	ahb->ecb_physbase = segs->ds_addr;
485	/*
486	 * Space for adapter inquiry information is on the
487	 * tail of the ecb array.
488	 */
489	ahb->ha_inq_physbase = ahbecbvtop(ahb, &ahb->ecb_array[AHB_NECB]);
490}
491
492static int
493ahbxptattach(struct ahb_softc *ahb)
494{
495	struct cam_devq *devq;
496	struct ecb *ecb;
497	u_int  i;
498
499	/* Remeber who are we on the scsi bus */
500	ahb->scsi_id = ahb_inb(ahb, SCSIDEF) & HSCSIID;
501
502	/* Use extended translation?? */
503    	ahb->extended_trans = ahb_inb(ahb, RESV1) & EXTENDED_TRANS;
504
505	/* Fetch adapter inquiry data */
506	ecb = ahbecbget(ahb);	/* Always succeeds - no outstanding commands */
507	ecb->hecb.opcode = ECBOP_READ_HA_INQDATA;
508	ecb->hecb.flag_word1 = FW1_SUPPRESS_URUN_ERR|FW1_ERR_STATUS_BLK_ONLY;
509	ecb->hecb.data_ptr = ahb->ha_inq_physbase;
510	ecb->hecb.data_len = sizeof(struct ha_inquiry_data);
511	ecb->hecb.sense_ptr = 0;
512	ecb->state = ECB_ACTIVE;
513
514	/* Tell the adapter about this command */
515	ahbqueuembox(ahb, ahbecbvtop(ahb, ecb),
516		     ATTN_STARTECB|ahb->scsi_id);
517
518	/* Poll for interrupt completion */
519	for (i = 1000; ecb->state != ECB_FREE && i != 0; i--) {
520		ahbintr(ahb);
521		DELAY(1000);
522	}
523
524	ahb->num_ecbs = MIN(ahb->num_ecbs,
525			    ahb->ha_inq_data->scsi_data.reserved[1]);
526	printf("ahb%ld: %.8s %s SCSI Adapter, FW Rev. %.4s, ID=%d, %d ECBs\n",
527	       ahb->unit, ahb->ha_inq_data->scsi_data.product,
528	       (ahb->ha_inq_data->scsi_data.flags & 0x4) ? "Differential"
529							 : "Single Ended",
530	       ahb->ha_inq_data->scsi_data.revision,
531	       ahb->scsi_id, ahb->num_ecbs);
532
533	/* Restore sense paddr for future CCB clients */
534	ecb->hecb.sense_ptr = ahbsensepaddr(ahbecbvtop(ahb, ecb));
535
536	ahbecbfree(ahb, ecb);
537
538	/*
539	 * Create the device queue for our SIM.
540	 */
541	devq = cam_simq_alloc(ahb->num_ecbs);
542	if (devq == NULL)
543		return (ENOMEM);
544
545	/*
546	 * Construct our SIM entry
547	 */
548	ahb->sim = cam_sim_alloc(ahbaction, ahbpoll, "ahb", ahb, ahb->unit,
549				 2, ahb->num_ecbs, devq);
550	if (ahb->sim == NULL) {
551		cam_simq_free(devq);
552		return (ENOMEM);
553	}
554
555	if (xpt_bus_register(ahb->sim, 0) != CAM_SUCCESS) {
556		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
557		return (ENXIO);
558	}
559
560	if (xpt_create_path(&ahb->path, /*periph*/NULL,
561			    cam_sim_path(ahb->sim), CAM_TARGET_WILDCARD,
562			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
563		xpt_bus_deregister(cam_sim_path(ahb->sim));
564		cam_sim_free(ahb->sim, /*free_devq*/TRUE);
565		return (ENXIO);
566	}
567
568	/*
569	 * Allow the board to generate interrupts.
570	 */
571	ahb_outb(ahb, INTDEF, ahb_inb(ahb, INTDEF) | INTEN);
572
573	return (0);
574}
575
576static void
577ahbhandleimmed(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
578{
579	struct ccb_hdr *ccb_h;
580	u_int target_id;
581
582	if (ahb->immed_cmd == 0) {
583		printf("ahb%ld: Immediate Command complete with no "
584		       " pending command\n", ahb->unit);
585		return;
586	}
587
588	target_id = intstat & INTSTAT_TARGET_MASK;
589
590	ccb_h = LIST_FIRST(&ahb->pending_ccbs);
591	while (ccb_h != NULL) {
592		struct ecb *pending_ecb;
593		union ccb *ccb;
594
595		pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
596		ccb = pending_ecb->ccb;
597		ccb_h = LIST_NEXT(ccb_h, sim_links.le);
598		if (ccb->ccb_h.target_id == target_id
599		 || target_id == ahb->scsi_id) {
600			untimeout(ahbtimeout, pending_ecb,
601				  ccb->ccb_h.timeout_ch);
602			LIST_REMOVE(&ccb->ccb_h, sim_links.le);
603			if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
604				bus_dmamap_unload(ahb->buffer_dmat,
605						  pending_ecb->dmamap);
606			if (pending_ecb == ahb->immed_ecb)
607				ccb->ccb_h.status =
608				    CAM_CMD_TIMEOUT|CAM_RELEASE_SIMQ;
609			else if (target_id == ahb->scsi_id)
610				ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
611			else
612				ccb->ccb_h.status = CAM_BDR_SENT;
613			ahbecbfree(ahb, pending_ecb);
614			xpt_done(ccb);
615		} else if (ahb->immed_ecb != NULL) {
616			/* Re-instate timeout */
617			ccb->ccb_h.timeout_ch =
618			    timeout(ahbtimeout, (caddr_t)pending_ecb,
619				    (ccb->ccb_h.timeout * hz) / 1000);
620		}
621	}
622
623	if (ahb->immed_ecb != NULL) {
624		ahb->immed_ecb = NULL;
625		printf("ahb%ld: No longer in timeout\n", ahb->unit);
626	} else if (target_id == ahb->scsi_id)
627		printf("ahb%ld: SCSI Bus Reset Delivered\n", ahb->unit);
628	else
629		printf("ahb%ld:  Bus Device Reset Delibered to target %d\n",
630		       ahb->unit, target_id);
631
632	ahb->immed_cmd = 0;
633}
634
635static void
636ahbcalcresid(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
637{
638	if (ecb->status.data_overrun != 0) {
639		/*
640		 * Overrun Condition.  The hardware doesn't
641		 * provide a meaningful byte count in this case
642		 * (the residual is always 0).  Tell the XPT
643		 * layer about the error.
644		 */
645		ccb->ccb_h.status = CAM_DATA_RUN_ERR;
646	} else {
647		ccb->csio.resid = ecb->status.resid_count;
648
649		if ((ecb->hecb.flag_word1 & FW1_SG_ECB) != 0) {
650			/*
651			 * For S/G transfers, the adapter provides a pointer
652			 * to the address in the last S/G element used and a
653			 * residual for that element.  So, we need to sum up
654			 * the elements that follow it in order to get a real
655			 * residual number.  If we have an overrun, the residual
656			 * reported will be 0 and we already know that all S/G
657			 * segments have been exhausted, so we can skip this
658			 * step.
659			 */
660			ahb_sg_t *sg;
661			int	  num_sg;
662
663			num_sg = ecb->hecb.data_len / sizeof(ahb_sg_t);
664
665			/* Find the S/G the adapter was working on */
666			for (sg = ecb->sg_list;
667			     num_sg != 0 && sg->addr != ecb->status.resid_addr;
668			     num_sg--, sg++)
669				;
670
671			/* Skip it */
672			num_sg--;
673			sg++;
674
675			/* Sum the rest */
676			for (; num_sg != 0; num_sg--, sg++)
677				ccb->csio.resid += sg->len;
678		}
679		/* Underruns are not errors */
680		ccb->ccb_h.status = CAM_REQ_CMP;
681	}
682}
683
684static void
685ahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
686{
687	struct hardware_ecb *hecb;
688	struct ecb_status *status;
689
690	hecb = &ecb->hecb;
691	status = &ecb->status;
692	switch (status->ha_status) {
693	case HS_OK:
694		ccb->csio.scsi_status = status->scsi_status;
695		if (status->scsi_status != 0) {
696			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
697			if (status->sense_stored) {
698				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
699				ccb->csio.sense_resid =
700				    ccb->csio.sense_len - status->sense_len;
701				bcopy(&ecb->sense, &ccb->csio.sense_data,
702				      status->sense_len);
703			}
704		}
705		break;
706	case HS_TARGET_NOT_ASSIGNED:
707		ccb->ccb_h.status = CAM_PATH_INVALID;
708		break;
709	case HS_SEL_TIMEOUT:
710		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
711		break;
712	case HS_DATA_RUN_ERR:
713		ahbcalcresid(ahb, ecb, ccb);
714		break;
715	case HS_UNEXPECTED_BUSFREE:
716		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
717		break;
718	case HS_INVALID_PHASE:
719		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
720		break;
721	case HS_REQUEST_SENSE_FAILED:
722		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
723		break;
724	case HS_TAG_MSG_REJECTED:
725	{
726		struct ccb_trans_settings neg;
727
728		xpt_print_path(ccb->ccb_h.path);
729		printf("refuses tagged commands.  Performing "
730		       "non-tagged I/O\n");
731		neg.flags = 0;
732		neg.valid = CCB_TRANS_TQ_VALID;
733		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
734		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
735		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
736		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
737		break;
738	}
739	case HS_FIRMWARE_LOAD_REQ:
740	case HS_HARDWARE_ERR:
741		/*
742		 * Tell the system that the Adapter
743		 * is no longer functional.
744		 */
745		ccb->ccb_h.status = CAM_NO_HBA;
746		break;
747	case HS_CMD_ABORTED_HOST:
748	case HS_CMD_ABORTED_ADAPTER:
749	case HS_ATN_TARGET_FAILED:
750	case HS_SCSI_RESET_ADAPTER:
751	case HS_SCSI_RESET_INCOMING:
752		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
753		break;
754	case HS_INVALID_ECB_PARAM:
755		printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
756			ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2);
757		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
758		break;
759	case HS_DUP_TCB_RECEIVED:
760	case HS_INVALID_OPCODE:
761	case HS_INVALID_CMD_LINK:
762	case HS_PROGRAM_CKSUM_ERROR:
763		panic("ahb%ld: Can't happen host status %x occurred",
764		      ahb->unit, status->ha_status);
765		break;
766	}
767	if (ccb->ccb_h.status != CAM_REQ_CMP) {
768		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
769		ccb->ccb_h.status |= CAM_DEV_QFRZN;
770	}
771}
772
773static void
774ahbdone(struct ahb_softc *ahb, u_int32_t mbox, u_int intstat)
775{
776	struct ecb *ecb;
777	union ccb *ccb;
778
779	ecb = ahbecbptov(ahb, mbox);
780
781	if ((ecb->state & ECB_ACTIVE) == 0)
782		panic("ecb not active");
783
784	ccb = ecb->ccb;
785
786	if (ccb != NULL) {
787		untimeout(ahbtimeout, ecb, ccb->ccb_h.timeout_ch);
788		LIST_REMOVE(&ccb->ccb_h, sim_links.le);
789
790		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
791			bus_dmasync_op_t op;
792
793			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
794				op = BUS_DMASYNC_POSTREAD;
795			else
796				op = BUS_DMASYNC_POSTWRITE;
797			bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
798			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
799		}
800
801		if ((intstat & INTSTAT_MASK) == INTSTAT_ECB_OK) {
802			ccb->ccb_h.status = CAM_REQ_CMP;
803			ccb->csio.resid = 0;
804		} else {
805			ahbprocesserror(ahb, ecb, ccb);
806		}
807		ahbecbfree(ahb, ecb);
808		xpt_done(ccb);
809	} else {
810		/* Non CCB Command */
811		if ((intstat & INTSTAT_MASK) != INTSTAT_ECB_OK) {
812			printf("ahb%ld: Command 0%x Failed %x:%x:%x\n",
813			       ahb->unit, ecb->hecb.opcode,
814			       *((u_int16_t*)&ecb->status),
815			       ecb->status.ha_status, ecb->status.resid_count);
816		}
817		/* Client owns this ECB and will release it. */
818	}
819}
820
821/*
822 * Catch an interrupt from the adaptor
823 */
824static void
825ahbintr(void *arg)
826{
827	struct	  ahb_softc *ahb;
828	u_int	  intstat;
829	u_int32_t mbox;
830
831	ahb = (struct ahb_softc *)arg;
832
833	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
834		/*
835		 * Fetch information about this interrupt.
836		 */
837		intstat = ahb_inb(ahb, INTSTAT);
838		mbox = ahb_inl(ahb, MBOXIN0);
839
840		/*
841		 * Reset interrupt latch.
842		 */
843		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);
844
845		/*
846		 * Process the completed operation
847		 */
848		switch (intstat & INTSTAT_MASK) {
849		case INTSTAT_ECB_OK:
850		case INTSTAT_ECB_CMPWRETRY:
851		case INTSTAT_ECB_CMPWERR:
852			ahbdone(ahb, mbox, intstat);
853			break;
854		case INTSTAT_AEN_OCCURED:
855			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
856				/* Bus Reset */
857				xpt_print_path(ahb->path);
858				switch (mbox) {
859				case HS_SCSI_RESET_ADAPTER:
860					printf("Host Adapter Initiated "
861					       "Bus Reset occurred\n");
862					break;
863				case HS_SCSI_RESET_INCOMING:
864					printf("Bus Reset Initiated "
865					       "by another device occurred\n");
866					break;
867				}
868				/* Notify the XPT */
869				xpt_async(AC_BUS_RESET, ahb->path, NULL);
870				break;
871			}
872			printf("Unsupported initiator selection AEN occured\n");
873			break;
874		case INTSTAT_IMMED_OK:
875		case INTSTAT_IMMED_ERR:
876			ahbhandleimmed(ahb, mbox, intstat);
877			break;
878		case INTSTAT_HW_ERR:
879			panic("Unrecoverable hardware Error Occurred\n");
880		}
881	}
882}
883
884static void
885ahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
886{
887	struct	  ecb *ecb;
888	union	  ccb *ccb;
889	struct	  ahb_softc *ahb;
890	u_int32_t ecb_paddr;
891	int	  s;
892
893	ecb = (struct ecb *)arg;
894	ccb = ecb->ccb;
895	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
896
897	if (error != 0) {
898		if (error != EFBIG)
899			printf("ahb%ld: Unexepected error 0x%x returned from "
900			       "bus_dmamap_load\n", ahb->unit, error);
901		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
902			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
903			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
904		}
905		ahbecbfree(ahb, ecb);
906		xpt_done(ccb);
907		return;
908	}
909
910	ecb_paddr = ahbecbvtop(ahb, ecb);
911
912	if (nseg != 0) {
913		ahb_sg_t *sg;
914		bus_dma_segment_t *end_seg;
915		bus_dmasync_op_t op;
916
917		end_seg = dm_segs + nseg;
918
919		/* Copy the segments into our SG list */
920		sg = ecb->sg_list;
921		while (dm_segs < end_seg) {
922			sg->addr = dm_segs->ds_addr;
923			sg->len = dm_segs->ds_len;
924			sg++;
925			dm_segs++;
926		}
927
928		if (nseg > 1) {
929			ecb->hecb.flag_word1 |= FW1_SG_ECB;
930			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
931			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
932		} else {
933			ecb->hecb.data_ptr = ecb->sg_list->addr;
934			ecb->hecb.data_len = ecb->sg_list->len;
935		}
936
937		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
938/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
939			op = BUS_DMASYNC_PREREAD;
940		} else {
941			op = BUS_DMASYNC_PREWRITE;
942		}
943		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */
944
945		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);
946
947	} else {
948		ecb->hecb.data_ptr = 0;
949		ecb->hecb.data_len = 0;
950	}
951
952	s = splcam();
953
954	/*
955	 * Last time we need to check if this CCB needs to
956	 * be aborted.
957	 */
958	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
959		if (nseg != 0)
960			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
961		ahbecbfree(ahb, ecb);
962		xpt_done(ccb);
963		splx(s);
964		return;
965	}
966
967	ecb->state = ECB_ACTIVE;
968	ccb->ccb_h.status |= CAM_SIM_QUEUED;
969	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);
970
971	/* Tell the adapter about this command */
972	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);
973
974	ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,
975					(ccb->ccb_h.timeout * hz) / 1000);
976	splx(s);
977}
978
979static void
980ahbaction(struct cam_sim *sim, union ccb *ccb)
981{
982	struct	ahb_softc *ahb;
983
984	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
985
986	ahb = (struct ahb_softc *)cam_sim_softc(sim);
987
988	switch (ccb->ccb_h.func_code) {
989	/* Common cases first */
990	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
991	{
992		struct ecb *ecb;
993		struct hardware_ecb *hecb;
994
995		/*
996		 * get an ecb to use.
997		 */
998		if ((ecb = ahbecbget(ahb)) == NULL) {
999			/* Should never occur */
1000			panic("Failed to get an ecb");
1001		}
1002
1003		/*
1004		 * So we can find the ECB when an abort is requested
1005		 */
1006		ecb->ccb = ccb;
1007		ccb->ccb_h.ccb_ecb_ptr = ecb;
1008		ccb->ccb_h.ccb_ahb_ptr = ahb;
1009
1010		/*
1011		 * Put all the arguments for the xfer in the ecb
1012		 */
1013		hecb = &ecb->hecb;
1014		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
1015		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
1016				 | FW1_ERR_STATUS_BLK_ONLY;
1017		hecb->flag_word2 = ccb->ccb_h.target_lun
1018				 | FW2_NO_RETRY_ON_BUSY;
1019		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
1020			hecb->flag_word2 |= FW2_TAG_ENB
1021					 | ((ccb->csio.tag_action & 0x3)
1022					    << FW2_TAG_TYPE_SHIFT);
1023		}
1024		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
1025			hecb->flag_word2 |= FW2_DISABLE_DISC;
1026		hecb->sense_len = ccb->csio.sense_len;
1027		hecb->cdb_len = ccb->csio.cdb_len;
1028		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
1029			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
1030				bcopy(ccb->csio.cdb_io.cdb_ptr,
1031				      hecb->cdb, hecb->cdb_len);
1032			} else {
1033				/* I guess I could map it in... */
1034				ccb->ccb_h.status = CAM_REQ_INVALID;
1035				ahbecbfree(ahb, ecb);
1036				xpt_done(ccb);
1037				return;
1038			}
1039		} else {
1040			bcopy(ccb->csio.cdb_io.cdb_bytes,
1041			      hecb->cdb, hecb->cdb_len);
1042		}
1043
1044		/*
1045		 * If we have any data to send with this command,
1046		 * map it into bus space.
1047		 */
1048		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1049			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
1050				/*
1051				 * We've been given a pointer
1052				 * to a single buffer.
1053				 */
1054				if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {
1055					int s;
1056					int error;
1057
1058					s = splsoftvm();
1059					error = bus_dmamap_load(
1060					    ahb->buffer_dmat,
1061					    ecb->dmamap,
1062					    ccb->csio.data_ptr,
1063					    ccb->csio.dxfer_len,
1064					    ahbexecuteecb,
1065					    ecb, /*flags*/0);
1066					if (error == EINPROGRESS) {
1067						/*
1068						 * So as to maintain ordering,
1069						 * freeze the controller queue
1070						 * until our mapping is
1071						 * returned.
1072						 */
1073						xpt_freeze_simq(ahb->sim, 1);
1074						ccb->ccb_h.status |=
1075						    CAM_RELEASE_SIMQ;
1076					}
1077					splx(s);
1078				} else {
1079					struct bus_dma_segment seg;
1080
1081					/* Pointer to physical buffer */
1082					seg.ds_addr =
1083					    (bus_addr_t)ccb->csio.data_ptr;
1084					seg.ds_len = ccb->csio.dxfer_len;
1085					ahbexecuteecb(ecb, &seg, 1, 0);
1086				}
1087			} else {
1088				struct bus_dma_segment *segs;
1089
1090				if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
1091					panic("ahbaction - Physical segment "
1092					      "pointers unsupported");
1093
1094				if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
1095					panic("btaction - Virtual segment "
1096					      "addresses unsupported");
1097
1098				/* Just use the segments provided */
1099				segs = (struct bus_dma_segment *)
1100				    ccb->csio.data_ptr;
1101				ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,
1102					     0);
1103			}
1104		} else {
1105			ahbexecuteecb(ecb, NULL, 0, 0);
1106		}
1107		break;
1108	}
1109	case XPT_EN_LUN:		/* Enable LUN as a target */
1110	case XPT_TARGET_IO:		/* Execute target I/O request */
1111	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
1112	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
1113	case XPT_ABORT:			/* Abort the specified CCB */
1114		/* XXX Implement */
1115		ccb->ccb_h.status = CAM_REQ_INVALID;
1116		xpt_done(ccb);
1117		break;
1118	case XPT_SET_TRAN_SETTINGS:
1119	{
1120		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1121		xpt_done(ccb);
1122		break;
1123	}
1124	case XPT_GET_TRAN_SETTINGS:
1125	/* Get default/user set transfer settings for the target */
1126	{
1127		struct	ccb_trans_settings *cts;
1128		u_int	target_mask;
1129
1130		cts = &ccb->cts;
1131		target_mask = 0x01 << ccb->ccb_h.target_id;
1132		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
1133			cts->flags = 0;
1134			if ((ahb->disc_permitted & target_mask) != 0)
1135				cts->flags |= CCB_TRANS_DISC_ENB;
1136			if ((ahb->tags_permitted & target_mask) != 0)
1137				cts->flags |= CCB_TRANS_TAG_ENB;
1138			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1139			cts->sync_period = 25; /* 10MHz */
1140
1141			if (cts->sync_period != 0)
1142				cts->sync_offset = 15;
1143
1144			cts->valid = CCB_TRANS_SYNC_RATE_VALID
1145				   | CCB_TRANS_SYNC_OFFSET_VALID
1146				   | CCB_TRANS_BUS_WIDTH_VALID
1147				   | CCB_TRANS_DISC_VALID
1148				   | CCB_TRANS_TQ_VALID;
1149			ccb->ccb_h.status = CAM_REQ_CMP;
1150		} else {
1151			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
1152		}
1153		xpt_done(ccb);
1154		break;
1155	}
1156	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
1157	{
1158		int i;
1159		int s;
1160
1161		s = splcam();
1162		ahb->immed_cmd = IMMED_RESET;
1163		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
1164		/* Poll for interrupt completion */
1165		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
1166			DELAY(1000);
1167			ahbintr(cam_sim_softc(sim));
1168		}
1169		splx(s);
1170		break;
1171	}
1172	case XPT_CALC_GEOMETRY:
1173	{
1174		cam_calc_geometry(&ccb->ccg, ahb->extended_trans);
1175		xpt_done(ccb);
1176		break;
1177	}
1178	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
1179	{
1180		int i;
1181
1182		ahb->immed_cmd = IMMED_RESET;
1183		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
1184		/* Poll for interrupt completion */
1185		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
1186			DELAY(1000);
1187		ccb->ccb_h.status = CAM_REQ_CMP;
1188		xpt_done(ccb);
1189		break;
1190	}
1191	case XPT_TERM_IO:		/* Terminate the I/O process */
1192		/* XXX Implement */
1193		ccb->ccb_h.status = CAM_REQ_INVALID;
1194		xpt_done(ccb);
1195		break;
1196	case XPT_PATH_INQ:		/* Path routing inquiry */
1197	{
1198		struct ccb_pathinq *cpi = &ccb->cpi;
1199
1200		cpi->version_num = 1; /* XXX??? */
1201		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
1202		cpi->target_sprt = 0;
1203		cpi->hba_misc = 0;
1204		cpi->hba_eng_cnt = 0;
1205		cpi->max_target = 7;
1206		cpi->max_lun = 7;
1207		cpi->initiator_id = ahb->scsi_id;
1208		cpi->bus_id = cam_sim_bus(sim);
1209		cpi->base_transfer_speed = 3300;
1210		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1211		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
1212		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1213		cpi->unit_number = cam_sim_unit(sim);
1214		cpi->ccb_h.status = CAM_REQ_CMP;
1215		xpt_done(ccb);
1216		break;
1217	}
1218#if 0
1219	/* Need these??? */
1220        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */
1221        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */
1222#endif
1223	default:
1224		ccb->ccb_h.status = CAM_REQ_INVALID;
1225		xpt_done(ccb);
1226		break;
1227	}
1228}
1229
1230static void
1231ahbpoll(struct cam_sim *sim)
1232{
1233	ahbintr(cam_sim_softc(sim));
1234}
1235
1236static void
1237ahbtimeout(void *arg)
1238{
1239	struct ecb	 *ecb;
1240	union  ccb	 *ccb;
1241	struct ahb_softc *ahb;
1242	int		  s;
1243
1244	ecb = (struct ecb *)arg;
1245	ccb = ecb->ccb;
1246	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;
1247	xpt_print_path(ccb->ccb_h.path);
1248	printf("ECB %p - timed out\n", (void *)ecb);
1249
1250	s = splcam();
1251
1252	if ((ecb->state & ECB_ACTIVE) == 0) {
1253		xpt_print_path(ccb->ccb_h.path);
1254		printf("ECB %p - timed out ECB already completed\n",
1255		       (void *)ecb);
1256		splx(s);
1257		return;
1258	}
1259	/*
1260	 * In order to simplify the recovery process, we ask the XPT
1261	 * layer to halt the queue of new transactions and we traverse
1262	 * the list of pending CCBs and remove their timeouts. This
1263	 * means that the driver attempts to clear only one error
1264	 * condition at a time.  In general, timeouts that occur
1265	 * close together are related anyway, so there is no benefit
1266	 * in attempting to handle errors in parrallel.  Timeouts will
1267	 * be reinstated when the recovery process ends.
1268	 */
1269	if ((ecb->state & ECB_DEVICE_RESET) == 0) {
1270		struct ccb_hdr *ccb_h;
1271
1272		if ((ecb->state & ECB_RELEASE_SIMQ) == 0) {
1273			xpt_freeze_simq(ahb->sim, /*count*/1);
1274			ecb->state |= ECB_RELEASE_SIMQ;
1275		}
1276
1277		ccb_h = LIST_FIRST(&ahb->pending_ccbs);
1278		while (ccb_h != NULL) {
1279			struct ecb *pending_ecb;
1280
1281			pending_ecb = (struct ecb *)ccb_h->ccb_ecb_ptr;
1282			untimeout(ahbtimeout, pending_ecb, ccb_h->timeout_ch);
1283			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
1284		}
1285
1286		/* Store for our interrupt handler */
1287		ahb->immed_ecb = ecb;
1288
1289		/*
1290		 * Send a Bus Device Reset message:
1291		 * The target that is holding up the bus may not
1292		 * be the same as the one that triggered this timeout
1293		 * (different commands have different timeout lengths),
1294		 * but we have no way of determining this from our
1295		 * timeout handler.  Our strategy here is to queue a
1296		 * BDR message to the target of the timed out command.
1297		 * If this fails, we'll get another timeout 2 seconds
1298		 * later which will attempt a bus reset.
1299		 */
1300		xpt_print_path(ccb->ccb_h.path);
1301		printf("Queuing BDR\n");
1302		ecb->state |= ECB_DEVICE_RESET;
1303		ccb->ccb_h.timeout_ch =
1304		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
1305
1306		ahb->immed_cmd = IMMED_RESET;
1307		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
1308	} else if ((ecb->state & ECB_SCSIBUS_RESET) != 0) {
1309		/*
1310		 * Try a SCSI bus reset.  We do this only if we
1311		 * have already attempted to clear the condition with a BDR.
1312		 */
1313		xpt_print_path(ccb->ccb_h.path);
1314		printf("Attempting SCSI Bus reset\n");
1315		ecb->state |= ECB_SCSIBUS_RESET;
1316		ccb->ccb_h.timeout_ch =
1317		    timeout(ahbtimeout, (caddr_t)ecb, 2 * hz);
1318		ahb->immed_cmd = IMMED_RESET;
1319		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
1320	} else {
1321		/* Bring out the hammer... */
1322		ahbreset(ahb);
1323
1324		/* Simulate the reset complete interrupt */
1325		ahbhandleimmed(ahb, 0, ahb->scsi_id|INTSTAT_IMMED_OK);
1326	}
1327
1328	splx(s);
1329}
1330
1331static device_method_t ahb_eisa_methods[] = {
1332	/* Device interface */
1333	DEVMETHOD(device_probe,		ahbprobe),
1334	DEVMETHOD(device_attach,	ahbattach),
1335
1336	{ 0, 0 }
1337};
1338
1339static driver_t ahb_eisa_driver = {
1340	"ahb",
1341	ahb_eisa_methods,
1342	1,			/* unused */
1343};
1344
1345static devclass_t ahb_devclass;
1346
1347DRIVER_MODULE(ahb, eisa, ahb_eisa_driver, ahb_devclass, 0, 0);
1348