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