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