xref: /netbsd-src/sys/dev/isa/wds.c (revision 8a8f936f250a330d54f8a24ed0e92aadf9743a7b)
1 /*	$NetBSD: wds.c,v 1.45 2001/07/19 16:38:40 thorpej Exp $	*/
2 
3 #include "opt_ddb.h"
4 
5 #undef WDSDIAG
6 #ifdef DDB
7 #define	integrate
8 #else
9 #define	integrate	static inline
10 #endif
11 
12 /*
13  * XXX
14  * aborts
15  * resets
16  */
17 
18 /*-
19  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
20  * All rights reserved.
21  *
22  * This code is derived from software contributed to The NetBSD Foundation
23  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
24  * NASA Ames Research Center.
25  *
26  * Redistribution and use in source and binary forms, with or without
27  * modification, are permitted provided that the following conditions
28  * are met:
29  * 1. Redistributions of source code must retain the above copyright
30  *    notice, this list of conditions and the following disclaimer.
31  * 2. Redistributions in binary form must reproduce the above copyright
32  *    notice, this list of conditions and the following disclaimer in the
33  *    documentation and/or other materials provided with the distribution.
34  * 3. All advertising materials mentioning features or use of this software
35  *    must display the following acknowledgement:
36  *	This product includes software developed by the NetBSD
37  *	Foundation, Inc. and its contributors.
38  * 4. Neither the name of The NetBSD Foundation nor the names of its
39  *    contributors may be used to endorse or promote products derived
40  *    from this software without specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
43  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
44  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
45  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
46  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
47  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
48  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
49  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
50  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
52  * POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 /*
56  * Copyright (c) 1994, 1995 Julian Highfield.  All rights reserved.
57  * Portions copyright (c) 1994, 1996, 1997
58  *	Charles M. Hannum.  All rights reserved.
59  *
60  * Redistribution and use in source and binary forms, with or without
61  * modification, are permitted provided that the following conditions
62  * are met:
63  * 1. Redistributions of source code must retain the above copyright
64  *    notice, this list of conditions and the following disclaimer.
65  * 2. Redistributions in binary form must reproduce the above copyright
66  *    notice, this list of conditions and the following disclaimer in the
67  *    documentation and/or other materials provided with the distribution.
68  * 3. All advertising materials mentioning features or use of this software
69  *    must display the following acknowledgement:
70  *	This product includes software developed by Julian Highfield.
71  * 4. The name of the author may not be used to endorse or promote products
72  *    derived from this software without specific prior written permission.
73  *
74  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
75  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
76  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
77  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
78  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
79  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
80  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
81  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
82  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
83  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
84  */
85 
86 /*
87  * This driver is for the WD7000 family of SCSI controllers:
88  *   the WD7000-ASC, a bus-mastering DMA controller,
89  *   the WD7000-FASST2, an -ASC with new firmware and scatter-gather,
90  *   and the WD7000-ASE, which was custom manufactured for Apollo
91  *      workstations and seems to include an -ASC as well as floppy
92  *      and ESDI interfaces.
93  *
94  * Loosely based on Theo Deraadt's unfinished attempt.
95  */
96 
97 #include <sys/types.h>
98 #include <sys/param.h>
99 #include <sys/systm.h>
100 #include <sys/kernel.h>
101 #include <sys/errno.h>
102 #include <sys/ioctl.h>
103 #include <sys/device.h>
104 #include <sys/malloc.h>
105 #include <sys/buf.h>
106 #include <sys/proc.h>
107 #include <sys/user.h>
108 
109 #include <uvm/uvm_extern.h>
110 
111 #include <machine/bus.h>
112 #include <machine/intr.h>
113 
114 #include <dev/scsipi/scsi_all.h>
115 #include <dev/scsipi/scsipi_all.h>
116 #include <dev/scsipi/scsiconf.h>
117 
118 #include <dev/isa/isavar.h>
119 #include <dev/isa/isadmavar.h>
120 
121 #include <dev/isa/wdsreg.h>
122 
123 #define	WDS_ISA_IOSIZE	8
124 
125 #ifndef DDB
126 #define Debugger() panic("should call debugger here (wds.c)")
127 #endif /* ! DDB */
128 
129 #define	WDS_MAXXFER	((WDS_NSEG - 1) << PGSHIFT)
130 
131 #define WDS_MBX_SIZE	16
132 
133 #define WDS_SCB_MAX	32
134 #define	SCB_HASH_SIZE	32	/* hash table size for phystokv */
135 #define	SCB_HASH_SHIFT	9
136 #define	SCB_HASH(x)	((((long)(x))>>SCB_HASH_SHIFT) & (SCB_HASH_SIZE - 1))
137 
138 #define	wds_nextmbx(wmb, mbx, mbio) \
139 	if ((wmb) == &(mbx)->mbio[WDS_MBX_SIZE - 1])	\
140 		(wmb) = &(mbx)->mbio[0];		\
141 	else						\
142 		(wmb)++;
143 
144 struct wds_mbx {
145 	struct wds_mbx_out mbo[WDS_MBX_SIZE];
146 	struct wds_mbx_in mbi[WDS_MBX_SIZE];
147 	struct wds_mbx_out *cmbo;	/* Collection Mail Box out */
148 	struct wds_mbx_out *tmbo;	/* Target Mail Box out */
149 	struct wds_mbx_in *tmbi;	/* Target Mail Box in */
150 };
151 
152 struct wds_softc {
153 	struct device sc_dev;
154 
155 	bus_space_tag_t sc_iot;
156 	bus_space_handle_t sc_ioh;
157 	bus_dma_tag_t sc_dmat;
158 	bus_dmamap_t sc_dmamap_mbox;	/* maps the mailbox */
159 	void *sc_ih;
160 
161 	struct wds_mbx *sc_mbx;
162 #define	wmbx	(sc->sc_mbx)
163 	struct wds_scb *sc_scbhash[SCB_HASH_SIZE];
164 	TAILQ_HEAD(, wds_scb) sc_free_scb, sc_waiting_scb;
165 	int sc_numscbs, sc_mbofull;
166 
167 	struct scsipi_adapter sc_adapter;
168 	struct scsipi_channel sc_channel;
169 
170 	int sc_revision;
171 	int sc_maxsegs;
172 };
173 
174 struct wds_probe_data {
175 #ifdef notyet
176 	int sc_irq, sc_drq;
177 #endif
178 	int sc_scsi_dev;
179 };
180 
181 integrate void
182 	wds_wait __P((bus_space_tag_t, bus_space_handle_t, int, int, int));
183 int     wds_cmd __P((bus_space_tag_t, bus_space_handle_t, u_char *, int));
184 integrate void wds_finish_scbs __P((struct wds_softc *));
185 int     wdsintr __P((void *));
186 integrate void wds_reset_scb __P((struct wds_softc *, struct wds_scb *));
187 void    wds_free_scb __P((struct wds_softc *, struct wds_scb *));
188 integrate int wds_init_scb __P((struct wds_softc *, struct wds_scb *));
189 struct	wds_scb *wds_get_scb __P((struct wds_softc *));
190 struct	wds_scb *wds_scb_phys_kv __P((struct wds_softc *, u_long));
191 void	wds_queue_scb __P((struct wds_softc *, struct wds_scb *));
192 void	wds_collect_mbo __P((struct wds_softc *));
193 void	wds_start_scbs __P((struct wds_softc *));
194 void    wds_done __P((struct wds_softc *, struct wds_scb *, u_char));
195 int	wds_find __P((bus_space_tag_t, bus_space_handle_t, struct wds_probe_data *));
196 void	wds_attach __P((struct wds_softc *, struct wds_probe_data *));
197 void	wds_init __P((struct wds_softc *, int));
198 void	wds_inquire_setup_information __P((struct wds_softc *));
199 void    wdsminphys __P((struct buf *));
200 void	wds_scsipi_request __P((struct scsipi_channel *,
201 	    scsipi_adapter_req_t, void *));
202 int	wds_poll __P((struct wds_softc *, struct scsipi_xfer *, int));
203 int	wds_ipoll __P((struct wds_softc *, struct wds_scb *, int));
204 void	wds_timeout __P((void *));
205 int	wds_create_scbs __P((struct wds_softc *, void *, size_t));
206 
207 int	wdsprobe __P((struct device *, struct cfdata *, void *));
208 void	wdsattach __P((struct device *, struct device *, void *));
209 
210 struct cfattach wds_ca = {
211 	sizeof(struct wds_softc), wdsprobe, wdsattach
212 };
213 
214 #define	WDS_ABORT_TIMEOUT	2000	/* time to wait for abort (mSec) */
215 
216 integrate void
217 wds_wait(iot, ioh, port, mask, val)
218 	bus_space_tag_t iot;
219 	bus_space_handle_t ioh;
220 	int port;
221 	int mask, val;
222 {
223 
224 	while ((bus_space_read_1(iot, ioh, port) & mask) != val)
225 		;
226 }
227 
228 /*
229  * Write a command to the board's I/O ports.
230  */
231 int
232 wds_cmd(iot, ioh, ibuf, icnt)
233 	bus_space_tag_t iot;
234 	bus_space_handle_t ioh;
235 	u_char *ibuf;
236 	int icnt;
237 {
238 	u_char c;
239 
240 	wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY);
241 
242 	while (icnt--) {
243 		bus_space_write_1(iot, ioh, WDS_CMD, *ibuf++);
244 		wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY);
245 		c = bus_space_read_1(iot, ioh, WDS_STAT);
246 		if (c & WDSS_REJ)
247 			return 1;
248 	}
249 
250 	return 0;
251 }
252 
253 /*
254  * Check for the presence of a WD7000 SCSI controller.
255  */
256 int
257 wdsprobe(parent, match, aux)
258 	struct device *parent;
259 	struct cfdata *match;
260 	void *aux;
261 {
262 	struct isa_attach_args *ia = aux;
263 	bus_space_tag_t iot = ia->ia_iot;
264 	bus_space_handle_t ioh;
265 	struct wds_probe_data wpd;
266 	int rv;
267 
268 	/* Disallow wildcarded i/o address. */
269 	if (ia->ia_iobase == ISACF_PORT_DEFAULT)
270 		return (0);
271 
272 	if (bus_space_map(iot, ia->ia_iobase, WDS_ISA_IOSIZE, 0, &ioh))
273 		return (0);
274 
275 	rv = wds_find(iot, ioh, &wpd);
276 
277 	bus_space_unmap(iot, ioh, WDS_ISA_IOSIZE);
278 
279 	if (rv) {
280 #ifdef notyet
281 		if (ia->ia_irq != -1 && ia->ia_irq != wpd.sc_irq)
282 			return (0);
283 		if (ia->ia_drq != -1 && ia->ia_drq != wpd.sc_drq)
284 			return (0);
285 		ia->ia_irq = wpd.sc_irq;
286 		ia->ia_drq = wpd.sc_drq;
287 #else
288 		if (ia->ia_irq == -1)
289 			return (0);
290 		if (ia->ia_drq == -1)
291 			return (0);
292 #endif
293 		ia->ia_msize = 0;
294 		ia->ia_iosize = WDS_ISA_IOSIZE;
295 	}
296 	return (rv);
297 }
298 
299 /*
300  * Attach all available units.
301  */
302 void
303 wdsattach(parent, self, aux)
304 	struct device *parent, *self;
305 	void *aux;
306 {
307 	struct isa_attach_args *ia = aux;
308 	struct wds_softc *sc = (void *)self;
309 	bus_space_tag_t iot = ia->ia_iot;
310 	bus_space_handle_t ioh;
311 	struct wds_probe_data wpd;
312 	isa_chipset_tag_t ic = ia->ia_ic;
313 	int error;
314 
315 	printf("\n");
316 
317 	if (bus_space_map(iot, ia->ia_iobase, WDS_ISA_IOSIZE, 0, &ioh)) {
318 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
319 		return;
320 	}
321 
322 	sc->sc_iot = iot;
323 	sc->sc_ioh = ioh;
324 	sc->sc_dmat = ia->ia_dmat;
325 	if (!wds_find(iot, ioh, &wpd)) {
326 		printf("%s: wds_find failed\n", sc->sc_dev.dv_xname);
327 		return;
328 	}
329 
330 	bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN);
331 #ifdef notyet
332 	if (wpd.sc_drq != -1) {
333 		if ((error = isa_dmacascade(ic, wpd.sc_drq)) != 0) {
334 			printf("%s: unable to cascade DRQ, error = %d\n",
335 			    sc->sc_dev.dv_xname, error);
336 			return;
337 		}
338 	}
339 
340 	sc->sc_ih = isa_intr_establish(ic, wpd.sc_irq, IST_EDGE, IPL_BIO,
341 	    wdsintr, sc);
342 #else
343 	if (ia->ia_drq != -1) {
344 		if ((error = isa_dmacascade(ic, ia->ia_drq)) != 0) {
345 			printf("%s: unable to cascade DRQ, error = %d\n",
346 			    sc->sc_dev.dv_xname, error);
347 			return;
348 		}
349 	}
350 
351 	sc->sc_ih = isa_intr_establish(ic, ia->ia_irq, IST_EDGE, IPL_BIO,
352 	    wdsintr, sc);
353 #endif
354 	if (sc->sc_ih == NULL) {
355 		printf("%s: couldn't establish interrupt\n",
356 		    sc->sc_dev.dv_xname);
357 		return;
358 	}
359 
360 	wds_attach(sc, &wpd);
361 }
362 
363 void
364 wds_attach(sc, wpd)
365 	struct wds_softc *sc;
366 	struct wds_probe_data *wpd;
367 {
368 	struct scsipi_adapter *adapt = &sc->sc_adapter;
369 	struct scsipi_channel *chan = &sc->sc_channel;
370 
371 	TAILQ_INIT(&sc->sc_free_scb);
372 	TAILQ_INIT(&sc->sc_waiting_scb);
373 
374 	/*
375 	 * Fill in the scsipi_adapter.
376 	 */
377 	memset(adapt, 0, sizeof(*adapt));
378 	adapt->adapt_dev = &sc->sc_dev;
379 	adapt->adapt_nchannels = 1;
380 	/* adapt_openings initialized below */
381 	adapt->adapt_max_periph = 1;
382 	adapt->adapt_request = wds_scsipi_request;
383 	adapt->adapt_minphys = minphys;
384 
385 	/*
386 	 * Fill in the scsipi_channel.
387 	 */
388 	memset(chan, 0, sizeof(*chan));
389 	chan->chan_adapter = adapt;
390 	chan->chan_bustype = &scsi_bustype;
391 	chan->chan_channel = 0;
392 	chan->chan_ntargets = 8;
393 	chan->chan_nluns = 8;
394 	chan->chan_id = wpd->sc_scsi_dev;
395 
396 	wds_init(sc, 0);
397 	wds_inquire_setup_information(sc);
398 
399 	/* XXX add support for GROW */
400 	adapt->adapt_openings = sc->sc_numscbs;
401 
402 	/*
403 	 * ask the adapter what subunits are present
404 	 */
405 	config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
406 }
407 
408 integrate void
409 wds_finish_scbs(sc)
410 	struct wds_softc *sc;
411 {
412 	struct wds_mbx_in *wmbi;
413 	struct wds_scb *scb;
414 	int i;
415 
416 	wmbi = wmbx->tmbi;
417 
418 	if (wmbi->stat == WDS_MBI_FREE) {
419 		for (i = 0; i < WDS_MBX_SIZE; i++) {
420 			if (wmbi->stat != WDS_MBI_FREE) {
421 				printf("%s: mbi not in round-robin order\n",
422 				    sc->sc_dev.dv_xname);
423 				goto AGAIN;
424 			}
425 			wds_nextmbx(wmbi, wmbx, mbi);
426 		}
427 #ifdef WDSDIAGnot
428 		printf("%s: mbi interrupt with no full mailboxes\n",
429 		    sc->sc_dev.dv_xname);
430 #endif
431 		return;
432 	}
433 
434 AGAIN:
435 	do {
436 		scb = wds_scb_phys_kv(sc, phystol(wmbi->scb_addr));
437 		if (!scb) {
438 			printf("%s: bad mbi scb pointer; skipping\n",
439 			    sc->sc_dev.dv_xname);
440 			goto next;
441 		}
442 
443 #ifdef WDSDEBUG
444 		if (wds_debug) {
445 			u_char *cp = &scb->scsipi_cmd;
446 			printf("op=%x %x %x %x %x %x\n",
447 			    cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
448 			printf("stat %x for mbi addr = 0x%08x, ",
449 			    wmbi->stat, wmbi);
450 			printf("scb addr = 0x%x\n", scb);
451 		}
452 #endif /* WDSDEBUG */
453 
454 		callout_stop(&scb->xs->xs_callout);
455 		wds_done(sc, scb, wmbi->stat);
456 
457 	next:
458 		wmbi->stat = WDS_MBI_FREE;
459 		wds_nextmbx(wmbi, wmbx, mbi);
460 	} while (wmbi->stat != WDS_MBI_FREE);
461 
462 	wmbx->tmbi = wmbi;
463 }
464 
465 /*
466  * Process an interrupt.
467  */
468 int
469 wdsintr(arg)
470 	void *arg;
471 {
472 	struct wds_softc *sc = arg;
473 	bus_space_tag_t iot = sc->sc_iot;
474 	bus_space_handle_t ioh = sc->sc_ioh;
475 	u_char c;
476 
477 	/* Was it really an interrupt from the board? */
478 	if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ) == 0)
479 		return 0;
480 
481 	/* Get the interrupt status byte. */
482 	c = bus_space_read_1(iot, ioh, WDS_IRQSTAT) & WDSI_MASK;
483 
484 	/* Acknowledge (which resets) the interrupt. */
485 	bus_space_write_1(iot, ioh, WDS_IRQACK, 0x00);
486 
487 	switch (c) {
488 	case WDSI_MSVC:
489 		wds_finish_scbs(sc);
490 		break;
491 
492 	case WDSI_MFREE:
493 		wds_start_scbs(sc);
494 		break;
495 
496 	default:
497 		printf("%s: unrecognized interrupt type %02x",
498 		    sc->sc_dev.dv_xname, c);
499 		break;
500 	}
501 
502 	return 1;
503 }
504 
505 integrate void
506 wds_reset_scb(sc, scb)
507 	struct wds_softc *sc;
508 	struct wds_scb *scb;
509 {
510 
511 	scb->flags = 0;
512 }
513 
514 /*
515  * Free the command structure, the outgoing mailbox and the data buffer.
516  */
517 void
518 wds_free_scb(sc, scb)
519 	struct wds_softc *sc;
520 	struct wds_scb *scb;
521 {
522 	int s;
523 
524 	s = splbio();
525 	wds_reset_scb(sc, scb);
526 	TAILQ_INSERT_HEAD(&sc->sc_free_scb, scb, chain);
527 	splx(s);
528 }
529 
530 integrate int
531 wds_init_scb(sc, scb)
532 	struct wds_softc *sc;
533 	struct wds_scb *scb;
534 {
535 	bus_dma_tag_t dmat = sc->sc_dmat;
536 	int hashnum, error;
537 
538 	/*
539 	 * XXX Should we put a DIAGNOSTIC check for multiple
540 	 * XXX SCB inits here?
541 	 */
542 
543 	memset(scb, 0, sizeof(struct wds_scb));
544 
545 	/*
546 	 * Create DMA maps for this SCB.
547 	 */
548 	error = bus_dmamap_create(dmat, sizeof(struct wds_scb), 1,
549 	    sizeof(struct wds_scb), 0, BUS_DMA_NOWAIT, &scb->dmamap_self);
550 	if (error) {
551 		printf("%s: can't create scb dmamap_self\n",
552 		    sc->sc_dev.dv_xname);
553 		return (error);
554 	}
555 
556 	error = bus_dmamap_create(dmat, WDS_MAXXFER, WDS_NSEG, WDS_MAXXFER,
557 	    0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &scb->dmamap_xfer);
558 	if (error) {
559 		printf("%s: can't create scb dmamap_xfer\n",
560 		    sc->sc_dev.dv_xname);
561 		bus_dmamap_destroy(dmat, scb->dmamap_self);
562 		return (error);
563 	}
564 
565 	/*
566 	 * Load the permanent DMA maps.
567 	 */
568 	error = bus_dmamap_load(dmat, scb->dmamap_self, scb,
569 	    sizeof(struct wds_scb), NULL, BUS_DMA_NOWAIT);
570 	if (error) {
571 		printf("%s: can't load scb dmamap_self\n",
572 		    sc->sc_dev.dv_xname);
573 		bus_dmamap_destroy(dmat, scb->dmamap_self);
574 		bus_dmamap_destroy(dmat, scb->dmamap_xfer);
575 		return (error);
576 	}
577 
578 	/*
579 	 * put in the phystokv hash table
580 	 * Never gets taken out.
581 	 */
582 	scb->hashkey = scb->dmamap_self->dm_segs[0].ds_addr;
583 	hashnum = SCB_HASH(scb->hashkey);
584 	scb->nexthash = sc->sc_scbhash[hashnum];
585 	sc->sc_scbhash[hashnum] = scb;
586 	wds_reset_scb(sc, scb);
587 	return (0);
588 }
589 
590 /*
591  * Create a set of scbs and add them to the free list.
592  */
593 int
594 wds_create_scbs(sc, mem, size)
595 	struct wds_softc *sc;
596 	void *mem;
597 	size_t size;
598 {
599 	bus_dma_segment_t seg;
600 	struct wds_scb *scb;
601 	int rseg, error;
602 
603 	if (sc->sc_numscbs >= WDS_SCB_MAX)
604 		return (0);
605 
606 	if ((scb = mem) != NULL)
607 		goto have_mem;
608 
609 	size = PAGE_SIZE;
610 	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg,
611 	    1, &rseg, BUS_DMA_NOWAIT);
612 	if (error) {
613 		printf("%s: can't allocate memory for scbs\n",
614 		    sc->sc_dev.dv_xname);
615 		return (error);
616 	}
617 
618 	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
619 	    (caddr_t *)&scb, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
620 	if (error) {
621 		printf("%s: can't map memory for scbs\n",
622 		    sc->sc_dev.dv_xname);
623 		bus_dmamem_free(sc->sc_dmat, &seg, rseg);
624 		return (error);
625 	}
626 
627  have_mem:
628 	memset(scb, 0, size);
629 	while (size > sizeof(struct wds_scb) && sc->sc_numscbs < WDS_SCB_MAX) {
630 		error = wds_init_scb(sc, scb);
631 		if (error) {
632 			printf("%s: can't initialize scb\n",
633 			    sc->sc_dev.dv_xname);
634 			return (error);
635 		}
636 		TAILQ_INSERT_TAIL(&sc->sc_free_scb, scb, chain);
637 		(caddr_t)scb += ALIGN(sizeof(struct wds_scb));
638 		size -= ALIGN(sizeof(struct wds_scb));
639 		sc->sc_numscbs++;
640 	}
641 
642 	return (0);
643 }
644 
645 /*
646  * Get a free scb
647  *
648  * If there are none, see if we can allocate a new one.  If so, put it in
649  * the hash table too otherwise either return an error or sleep.
650  */
651 struct wds_scb *
652 wds_get_scb(sc)
653 	struct wds_softc *sc;
654 {
655 	struct wds_scb *scb;
656 	int s;
657 
658 	s = splbio();
659 	scb = TAILQ_FIRST(&sc->sc_free_scb);
660 	if (scb != NULL) {
661 		TAILQ_REMOVE(&sc->sc_free_scb, scb, chain);
662 		scb->flags |= SCB_ALLOC;
663 	}
664 	splx(s);
665 	return (scb);
666 }
667 
668 struct wds_scb *
669 wds_scb_phys_kv(sc, scb_phys)
670 	struct wds_softc *sc;
671 	u_long scb_phys;
672 {
673 	int hashnum = SCB_HASH(scb_phys);
674 	struct wds_scb *scb = sc->sc_scbhash[hashnum];
675 
676 	while (scb) {
677 		if (scb->hashkey == scb_phys)
678 			break;
679 		/* XXX Check to see if it matches the sense command block. */
680 		if (scb->hashkey == (scb_phys - sizeof(struct wds_cmd)))
681 			break;
682 		scb = scb->nexthash;
683 	}
684 	return (scb);
685 }
686 
687 /*
688  * Queue a SCB to be sent to the controller, and send it if possible.
689  */
690 void
691 wds_queue_scb(sc, scb)
692 	struct wds_softc *sc;
693 	struct wds_scb *scb;
694 {
695 
696 	TAILQ_INSERT_TAIL(&sc->sc_waiting_scb, scb, chain);
697 	wds_start_scbs(sc);
698 }
699 
700 /*
701  * Garbage collect mailboxes that are no longer in use.
702  */
703 void
704 wds_collect_mbo(sc)
705 	struct wds_softc *sc;
706 {
707 	struct wds_mbx_out *wmbo;	/* Mail Box Out pointer */
708 #ifdef WDSDIAG
709 	struct wds_scb *scb;
710 #endif
711 
712 	wmbo = wmbx->cmbo;
713 
714 	while (sc->sc_mbofull > 0) {
715 		if (wmbo->cmd != WDS_MBO_FREE)
716 			break;
717 
718 #ifdef WDSDIAG
719 		scb = wds_scb_phys_kv(sc, phystol(wmbo->scb_addr));
720 		scb->flags &= ~SCB_SENDING;
721 #endif
722 
723 		--sc->sc_mbofull;
724 		wds_nextmbx(wmbo, wmbx, mbo);
725 	}
726 
727 	wmbx->cmbo = wmbo;
728 }
729 
730 /*
731  * Send as many SCBs as we have empty mailboxes for.
732  */
733 void
734 wds_start_scbs(sc)
735 	struct wds_softc *sc;
736 {
737 	bus_space_tag_t iot = sc->sc_iot;
738 	bus_space_handle_t ioh = sc->sc_ioh;
739 	struct wds_mbx_out *wmbo;	/* Mail Box Out pointer */
740 	struct wds_scb *scb;
741 	u_char c;
742 
743 	wmbo = wmbx->tmbo;
744 
745 	while ((scb = sc->sc_waiting_scb.tqh_first) != NULL) {
746 		if (sc->sc_mbofull >= WDS_MBX_SIZE) {
747 			wds_collect_mbo(sc);
748 			if (sc->sc_mbofull >= WDS_MBX_SIZE) {
749 				c = WDSC_IRQMFREE;
750 				wds_cmd(iot, ioh, &c, sizeof c);
751 				break;
752 			}
753 		}
754 
755 		TAILQ_REMOVE(&sc->sc_waiting_scb, scb, chain);
756 #ifdef WDSDIAG
757 		scb->flags |= SCB_SENDING;
758 #endif
759 
760 		/* Link scb to mbo. */
761 		ltophys(scb->dmamap_self->dm_segs[0].ds_addr +
762 		    offsetof(struct wds_scb, cmd), wmbo->scb_addr);
763 		/* XXX What about aborts? */
764 		wmbo->cmd = WDS_MBO_START;
765 
766 		/* Tell the card to poll immediately. */
767 		c = WDSC_MSTART(wmbo - wmbx->mbo);
768 		wds_cmd(sc->sc_iot, sc->sc_ioh, &c, sizeof c);
769 
770 		if ((scb->flags & SCB_POLLED) == 0)
771 			callout_reset(&scb->xs->xs_callout,
772 			    (scb->timeout * hz) / 1000, wds_timeout, scb);
773 
774 		++sc->sc_mbofull;
775 		wds_nextmbx(wmbo, wmbx, mbo);
776 	}
777 
778 	wmbx->tmbo = wmbo;
779 }
780 
781 /*
782  * Process the result of a SCSI command.
783  */
784 void
785 wds_done(sc, scb, stat)
786 	struct wds_softc *sc;
787 	struct wds_scb *scb;
788 	u_char stat;
789 {
790 	bus_dma_tag_t dmat = sc->sc_dmat;
791 	struct scsipi_xfer *xs = scb->xs;
792 
793 	/* XXXXX */
794 
795 	/* Don't release the SCB if it was an internal command. */
796 	if (xs == 0) {
797 		scb->flags |= SCB_DONE;
798 		return;
799 	}
800 
801 	/*
802 	 * If we were a data transfer, unload the map that described
803 	 * the data buffer.
804 	 */
805 	if (xs->datalen) {
806 		bus_dmamap_sync(dmat, scb->dmamap_xfer, 0,
807 		    scb->dmamap_xfer->dm_mapsize,
808 		    (xs->xs_control & XS_CTL_DATA_IN) ?
809 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
810 		bus_dmamap_unload(dmat, scb->dmamap_xfer);
811 	}
812 	if (xs->error == XS_NOERROR) {
813 		/* If all went well, or an error is acceptable. */
814 		if (stat == WDS_MBI_OK) {
815 			/* OK, set the result */
816 			xs->resid = 0;
817 		} else {
818 			/* Check the mailbox status. */
819 			switch (stat) {
820 			case WDS_MBI_OKERR:
821 				/*
822 				 * SCSI error recorded in scb,
823 				 * counts as WDS_MBI_OK
824 				 */
825 				switch (scb->cmd.venderr) {
826 				case 0x00:
827 					printf("%s: Is this "
828 					    "an error?\n",
829 					    sc->sc_dev.dv_xname);
830 					/* Experiment. */
831 					xs->error = XS_DRIVER_STUFFUP;
832 					break;
833 				case 0x01:
834 #if 0
835 					printf("%s: OK, see SCSI "
836 					    "error field.\n",
837 					    sc->sc_dev.dv_xname);
838 #endif
839 					if (scb->cmd.stat == SCSI_CHECK ||
840 					    scb->cmd.stat == SCSI_BUSY) {
841 						xs->status = scb->cmd.stat;
842 						xs->error = XS_BUSY;
843 					}
844 					break;
845 				case 0x40:
846 #if 0
847 					printf("%s: DMA underrun!\n",
848 					    sc->sc_dev.dv_xname);
849 #endif
850 					/*
851 					 * Hits this if the target
852 					 * returns fewer that datalen
853 					 * bytes (eg my CD-ROM, which
854 					 * returns a short version
855 					 * string, or if DMA is
856 					 * turned off etc.
857 					 */
858 					xs->resid = 0;
859 					break;
860 				default:
861 					printf("%s: VENDOR ERROR "
862 					    "%02x, scsi %02x\n",
863 					    sc->sc_dev.dv_xname,
864 					    scb->cmd.venderr,
865 					    scb->cmd.stat);
866 					/* Experiment. */
867 					xs->error = XS_DRIVER_STUFFUP;
868 					break;
869 				}
870 					break;
871 			case WDS_MBI_ETIME:
872 				/*
873 				 * The documentation isn't clear on
874 				 * what conditions might generate this,
875 				 * but selection timeouts are the only
876 				 * one I can think of.
877 				 */
878 				xs->error = XS_SELTIMEOUT;
879 				break;
880 			case WDS_MBI_ERESET:
881 			case WDS_MBI_ETARCMD:
882 			case WDS_MBI_ERESEL:
883 			case WDS_MBI_ESEL:
884 			case WDS_MBI_EABORT:
885 			case WDS_MBI_ESRESET:
886 			case WDS_MBI_EHRESET:
887 				xs->error = XS_DRIVER_STUFFUP;
888 				break;
889 			}
890 		}
891 	} /* XS_NOERROR */
892 
893 	wds_free_scb(sc, scb);
894 	scsipi_done(xs);
895 }
896 
897 int
898 wds_find(iot, ioh, sc)
899 	bus_space_tag_t iot;
900 	bus_space_handle_t ioh;
901 	struct wds_probe_data *sc;
902 {
903 	int i;
904 
905 	/* XXXXX */
906 
907 	/*
908 	 * Sending a command causes the CMDRDY bit to clear.
909  	 */
910 	for (i = 5; i; i--) {
911 		if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0)
912 			break;
913 		delay(100);
914 	}
915 	if (!i)
916 		return 0;
917 
918 	bus_space_write_1(iot, ioh, WDS_CMD, WDSC_NOOP);
919 	if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0)
920 		return 0;
921 
922 	bus_space_write_1(iot, ioh, WDS_HCR, WDSH_SCSIRESET|WDSH_ASCRESET);
923 	delay(10000);
924 	bus_space_write_1(iot, ioh, WDS_HCR, 0x00);
925 	delay(500000);
926 	wds_wait(iot, ioh, WDS_STAT, WDSS_RDY, WDSS_RDY);
927 	if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 1)
928 		if (bus_space_read_1(iot, ioh, WDS_IRQSTAT) != 7)
929 			return 0;
930 
931 	for (i = 2000; i; i--) {
932 		if ((bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_RDY) != 0)
933 			break;
934 		delay(100);
935 	}
936 	if (!i)
937 		return 0;
938 
939 	if (sc) {
940 #ifdef notyet
941 		sc->sc_irq = ...;
942 		sc->sc_drq = ...;
943 #endif
944 		/* XXX Can we do this better? */
945 		sc->sc_scsi_dev = 7;
946 	}
947 
948 	return 1;
949 }
950 
951 /*
952  * Initialise the board and driver.
953  */
954 void
955 wds_init(sc, isreset)
956 	struct wds_softc *sc;
957 	int isreset;
958 {
959 	bus_space_tag_t iot = sc->sc_iot;
960 	bus_space_handle_t ioh = sc->sc_ioh;
961 	bus_dma_segment_t seg;
962 	struct wds_setup init;
963 	u_char c;
964 	int i, rseg;
965 
966 	if (isreset)
967 		goto doinit;
968 
969 	/*
970 	 * Allocate the mailbox.
971 	 */
972 	if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0, &seg, 1,
973 	    &rseg, BUS_DMA_NOWAIT) ||
974 	    bus_dmamem_map(sc->sc_dmat, &seg, rseg, PAGE_SIZE,
975 	    (caddr_t *)&wmbx, BUS_DMA_NOWAIT|BUS_DMA_COHERENT))
976 		panic("wds_init: can't create or map mailbox");
977 
978 	/*
979 	 * Since DMA memory allocation is always rounded up to a
980 	 * page size, create some scbs from the leftovers.
981 	 */
982 	if (wds_create_scbs(sc, ((caddr_t)wmbx) +
983 	    ALIGN(sizeof(struct wds_mbx)),
984 	    PAGE_SIZE - ALIGN(sizeof(struct wds_mbx))))
985 		panic("wds_init: can't create scbs");
986 
987 	/*
988 	 * Create and load the mailbox DMA map.
989 	 */
990 	if (bus_dmamap_create(sc->sc_dmat, sizeof(struct wds_mbx), 1,
991 	    sizeof(struct wds_mbx), 0, BUS_DMA_NOWAIT, &sc->sc_dmamap_mbox) ||
992 	    bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx,
993 	    sizeof(struct wds_mbx), NULL, BUS_DMA_NOWAIT))
994 		panic("wds_ionit: can't craete or load mailbox dma map");
995 
996  doinit:
997 	/*
998 	 * Set up initial mail box for round-robin operation.
999 	 */
1000 	for (i = 0; i < WDS_MBX_SIZE; i++) {
1001 		wmbx->mbo[i].cmd = WDS_MBO_FREE;
1002 		wmbx->mbi[i].stat = WDS_MBI_FREE;
1003 	}
1004 	wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
1005 	wmbx->tmbi = &wmbx->mbi[0];
1006 	sc->sc_mbofull = 0;
1007 
1008 	init.opcode = WDSC_INIT;
1009 	init.scsi_id = sc->sc_channel.chan_id;
1010 	init.buson_t = 48;
1011 	init.busoff_t = 24;
1012 	init.xx = 0;
1013 	ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, init.mbaddr);
1014 	init.nomb = init.nimb = WDS_MBX_SIZE;
1015 	wds_cmd(iot, ioh, (u_char *)&init, sizeof init);
1016 
1017 	wds_wait(iot, ioh, WDS_STAT, WDSS_INIT, WDSS_INIT);
1018 
1019 	c = WDSC_DISUNSOL;
1020 	wds_cmd(iot, ioh, &c, sizeof c);
1021 }
1022 
1023 /*
1024  * Read the board's firmware revision information.
1025  */
1026 void
1027 wds_inquire_setup_information(sc)
1028 	struct wds_softc *sc;
1029 {
1030 	bus_space_tag_t iot = sc->sc_iot;
1031 	bus_space_handle_t ioh = sc->sc_ioh;
1032 	struct wds_scb *scb;
1033 	u_char *j;
1034 	int s;
1035 
1036 	sc->sc_maxsegs = 1;
1037 
1038 	scb = wds_get_scb(sc);
1039 	if (scb == 0)
1040 		panic("wds_inquire_setup_information: no scb available");
1041 
1042 	scb->xs = NULL;
1043 	scb->timeout = 40;
1044 
1045 	memset(&scb->cmd, 0, sizeof scb->cmd);
1046 	scb->cmd.write = 0x80;
1047 	scb->cmd.opcode = WDSX_GETFIRMREV;
1048 
1049 	/* Will poll card, await result. */
1050 	bus_space_write_1(iot, ioh, WDS_HCR, WDSH_DRQEN);
1051 	scb->flags |= SCB_POLLED;
1052 
1053 	s = splbio();
1054 	wds_queue_scb(sc, scb);
1055 	splx(s);
1056 
1057 	if (wds_ipoll(sc, scb, scb->timeout))
1058 		goto out;
1059 
1060 	/* Print the version number. */
1061 	printf("%s: version %x.%02x ", sc->sc_dev.dv_xname,
1062 	    scb->cmd.targ, scb->cmd.scb.opcode);
1063 	sc->sc_revision = (scb->cmd.targ << 8) | scb->cmd.scb.opcode;
1064 	/* Print out the version string. */
1065 	j = 2 + &(scb->cmd.targ);
1066 	while ((*j >= 32) && (*j < 128)) {
1067 		printf("%c", *j);
1068 		j++;
1069 	}
1070 
1071 	/*
1072 	 * Determine if we can use scatter/gather.
1073 	 */
1074 	if (sc->sc_revision >= 0x800)
1075 		sc->sc_maxsegs = WDS_NSEG;
1076 
1077 out:
1078 	printf("\n");
1079 
1080 	/*
1081 	 * Free up the resources used by this scb.
1082 	 */
1083 	wds_free_scb(sc, scb);
1084 }
1085 
1086 void
1087 wdsminphys(bp)
1088 	struct buf *bp;
1089 {
1090 
1091 	if (bp->b_bcount > WDS_MAXXFER)
1092 		bp->b_bcount = WDS_MAXXFER;
1093 	minphys(bp);
1094 }
1095 
1096 /*
1097  * Send a SCSI command.
1098  */
1099 void
1100 wds_scsipi_request(chan, req, arg)
1101 	struct scsipi_channel *chan;
1102 	scsipi_adapter_req_t req;
1103 	void *arg;
1104 {
1105 	struct scsipi_xfer *xs;
1106 	struct scsipi_periph *periph;
1107 	struct wds_softc *sc = (void *)chan->chan_adapter->adapt_dev;
1108 	bus_dma_tag_t dmat = sc->sc_dmat;
1109 	struct wds_scb *scb;
1110 	struct wds_scat_gath *sg;
1111 	int error, seg, flags, s;
1112 
1113 	switch (req) {
1114 	case ADAPTER_REQ_RUN_XFER:
1115 		xs = arg;
1116 		periph = xs->xs_periph;
1117 
1118 		if (xs->xs_control & XS_CTL_RESET) {
1119 			/* XXX Fix me! */
1120 			printf("%s: reset!\n", sc->sc_dev.dv_xname);
1121 			wds_init(sc, 1);
1122 			scsipi_done(xs);
1123 			return;
1124 		}
1125 
1126 		if (xs->xs_control & XS_CTL_DATA_UIO) {
1127 			/* XXX Fix me! */
1128 			/*
1129 			 * Let's not worry about UIO. There isn't any code
1130 			 * for the non-SG boards anyway!
1131 			 */
1132 			printf("%s: UIO is untested and disabled!\n",
1133 			    sc->sc_dev.dv_xname);
1134 			xs->error = XS_DRIVER_STUFFUP;
1135 			scsipi_done(xs);
1136 			return;
1137 		}
1138 
1139 		flags = xs->xs_control;
1140 
1141 		/* Get an SCB to use. */
1142 		scb = wds_get_scb(sc);
1143 #ifdef DIAGNOSTIC
1144 		/*
1145 		 * This should never happen as we track the resources
1146 		 * in the mid-layer.
1147 		 */
1148 		if (scb == NULL) {
1149 			scsipi_printaddr(periph);
1150 			printf("unable to allocate scb\n");
1151 			panic("wds_scsipi_request");
1152 		}
1153 #endif
1154 
1155 		scb->xs = xs;
1156 		scb->timeout = xs->timeout;
1157 
1158 		/* Zero out the command structure. */
1159 		memset(&scb->cmd, 0, sizeof scb->cmd);
1160 		memcpy(&scb->cmd.scb, xs->cmd,
1161 		    xs->cmdlen < 12 ? xs->cmdlen : 12);
1162 
1163 		/* Set up some of the command fields. */
1164 		scb->cmd.targ = (periph->periph_target << 5) |
1165 		    periph->periph_lun;
1166 
1167 		/*
1168 		 * NOTE: cmd.write may be OK as 0x40 (disable direction
1169 		 * checking) on boards other than the WD-7000V-ASE. Need
1170 		 * this for the ASE:
1171  		 */
1172 		scb->cmd.write = (xs->xs_control & XS_CTL_DATA_IN) ?
1173 		    0x80 : 0x00;
1174 
1175 		if (xs->datalen) {
1176 			sg = scb->scat_gath;
1177 			seg = 0;
1178 #ifdef TFS
1179 			if (flags & XS_CTL_DATA_UIO) {
1180 				error = bus_dmamap_load_uio(dmat,
1181 				    scb->dmamap_xfer, (struct uio *)xs->data,
1182 				    BUS_DMA_NOWAIT |
1183 				    ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ :
1184 				     BUS_DMA_WRITE));
1185 			} else
1186 #endif /* TFS */
1187 			{
1188 				error = bus_dmamap_load(dmat,
1189 				    scb->dmamap_xfer, xs->data, xs->datalen,
1190 				    NULL, BUS_DMA_NOWAIT |
1191 				    ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ :
1192 				     BUS_DMA_WRITE));
1193 			}
1194 
1195 			switch (error) {
1196 			case 0:
1197 				break;
1198 
1199 			case ENOMEM:
1200 			case EAGAIN:
1201 				xs->error = XS_RESOURCE_SHORTAGE;
1202 				goto out_bad;
1203 
1204 			default:
1205 				xs->error = XS_DRIVER_STUFFUP;
1206 				printf("%s: error %d loading DMA map\n",
1207 				    sc->sc_dev.dv_xname, error);
1208  out_bad:
1209 				wds_free_scb(sc, scb);
1210 				scsipi_done(xs);
1211 				return;
1212 			}
1213 
1214 			bus_dmamap_sync(dmat, scb->dmamap_xfer, 0,
1215 			    scb->dmamap_xfer->dm_mapsize,
1216 			    (flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD :
1217 			    BUS_DMASYNC_PREWRITE);
1218 
1219 			if (sc->sc_maxsegs > 1) {
1220 				/*
1221 				 * Load the hardware scatter/gather map with the
1222 				 * contents of the DMA map.
1223 				 */
1224 				for (seg = 0;
1225 				     seg < scb->dmamap_xfer->dm_nsegs; seg++) {
1226 				ltophys(scb->dmamap_xfer->dm_segs[seg].ds_addr,
1227 					    scb->scat_gath[seg].seg_addr);
1228 				ltophys(scb->dmamap_xfer->dm_segs[seg].ds_len,
1229 					    scb->scat_gath[seg].seg_len);
1230 				}
1231 
1232 				/*
1233 				 * Set up for scatter/gather transfer.
1234 				 */
1235 				scb->cmd.opcode = WDSX_SCSISG;
1236 				ltophys(scb->dmamap_self->dm_segs[0].ds_addr +
1237 				    offsetof(struct wds_scb, scat_gath),
1238 				    scb->cmd.data);
1239 				ltophys(scb->dmamap_self->dm_nsegs *
1240 				    sizeof(struct wds_scat_gath), scb->cmd.len);
1241 			} else {
1242 				/*
1243 				 * This board is an ASC or an ASE, and the
1244 				 * transfer has been mapped contig for us.
1245 				 */
1246 				scb->cmd.opcode = WDSX_SCSICMD;
1247 				ltophys(scb->dmamap_xfer->dm_segs[0].ds_addr,
1248 				    scb->cmd.data);
1249 				ltophys(scb->dmamap_xfer->dm_segs[0].ds_len,
1250 				    scb->cmd.len);
1251 			}
1252 		} else {
1253 			scb->cmd.opcode = WDSX_SCSICMD;
1254 			ltophys(0, scb->cmd.data);
1255 			ltophys(0, scb->cmd.len);
1256 		}
1257 
1258 		scb->cmd.stat = 0x00;
1259 		scb->cmd.venderr = 0x00;
1260 		ltophys(0, scb->cmd.link);
1261 
1262 		/* XXX Do we really want to do this? */
1263 		if (flags & XS_CTL_POLL) {
1264 			/* Will poll card, await result. */
1265 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
1266 			    WDS_HCR, WDSH_DRQEN);
1267 			scb->flags |= SCB_POLLED;
1268 		} else {
1269 			/*
1270 			 * Will send command, let interrupt routine
1271 			 * handle result.
1272 			 */
1273 			bus_space_write_1(sc->sc_iot, sc->sc_ioh, WDS_HCR,
1274 			    WDSH_IRQEN | WDSH_DRQEN);
1275 		}
1276 
1277 		s = splbio();
1278 		wds_queue_scb(sc, scb);
1279 		splx(s);
1280 
1281 		if ((flags & XS_CTL_POLL) == 0)
1282 			return;
1283 
1284 		if (wds_poll(sc, xs, scb->timeout)) {
1285 			wds_timeout(scb);
1286 			if (wds_poll(sc, xs, scb->timeout))
1287 				wds_timeout(scb);
1288 		}
1289 		return;
1290 
1291 	case ADAPTER_REQ_GROW_RESOURCES:
1292 		/* XXX Not supported. */
1293 		return;
1294 
1295 	case ADAPTER_REQ_SET_XFER_MODE:
1296 		/* XXX How do we do this? */
1297 		return;
1298 	}
1299 }
1300 
1301 /*
1302  * Poll a particular unit, looking for a particular scb
1303  */
1304 int
1305 wds_poll(sc, xs, count)
1306 	struct wds_softc *sc;
1307 	struct scsipi_xfer *xs;
1308 	int count;
1309 {
1310 	bus_space_tag_t iot = sc->sc_iot;
1311 	bus_space_handle_t ioh = sc->sc_ioh;
1312 
1313 	/* timeouts are in msec, so we loop in 1000 usec cycles */
1314 	while (count) {
1315 		/*
1316 		 * If we had interrupts enabled, would we
1317 		 * have got an interrupt?
1318 		 */
1319 		if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ)
1320 			wdsintr(sc);
1321 		if (xs->xs_status & XS_STS_DONE)
1322 			return 0;
1323 		delay(1000);	/* only happens in boot so ok */
1324 		count--;
1325 	}
1326 	return 1;
1327 }
1328 
1329 /*
1330  * Poll a particular unit, looking for a particular scb
1331  */
1332 int
1333 wds_ipoll(sc, scb, count)
1334 	struct wds_softc *sc;
1335 	struct wds_scb *scb;
1336 	int count;
1337 {
1338 	bus_space_tag_t iot = sc->sc_iot;
1339 	bus_space_handle_t ioh = sc->sc_ioh;
1340 
1341 	/* timeouts are in msec, so we loop in 1000 usec cycles */
1342 	while (count) {
1343 		/*
1344 		 * If we had interrupts enabled, would we
1345 		 * have got an interrupt?
1346 		 */
1347 		if (bus_space_read_1(iot, ioh, WDS_STAT) & WDSS_IRQ)
1348 			wdsintr(sc);
1349 		if (scb->flags & SCB_DONE)
1350 			return 0;
1351 		delay(1000);	/* only happens in boot so ok */
1352 		count--;
1353 	}
1354 	return 1;
1355 }
1356 
1357 void
1358 wds_timeout(arg)
1359 	void *arg;
1360 {
1361 	struct wds_scb *scb = arg;
1362 	struct scsipi_xfer *xs = scb->xs;
1363 	struct scsipi_periph *periph = xs->xs_periph;
1364 	struct wds_softc *sc =
1365 	    (void *)periph->periph_channel->chan_adapter->adapt_dev;
1366 	int s;
1367 
1368 	scsipi_printaddr(periph);
1369 	printf("timed out");
1370 
1371 	s = splbio();
1372 
1373 #ifdef WDSDIAG
1374 	/*
1375 	 * If The scb's mbx is not free, then the board has gone south?
1376 	 */
1377 	wds_collect_mbo(sc);
1378 	if (scb->flags & SCB_SENDING) {
1379 		printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
1380 		Debugger();
1381 	}
1382 #endif
1383 
1384 	/*
1385 	 * If it has been through before, then
1386 	 * a previous abort has failed, don't
1387 	 * try abort again
1388 	 */
1389 	if (scb->flags & SCB_ABORT) {
1390 		/* abort timed out */
1391 		printf(" AGAIN\n");
1392 		/* XXX Must reset! */
1393 	} else {
1394 		/* abort the operation that has timed out */
1395 		printf("\n");
1396 		scb->xs->error = XS_TIMEOUT;
1397 		scb->timeout = WDS_ABORT_TIMEOUT;
1398 		scb->flags |= SCB_ABORT;
1399 		wds_queue_scb(sc, scb);
1400 	}
1401 
1402 	splx(s);
1403 }
1404