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