xref: /netbsd-src/sys/dev/isa/wds.c (revision 32e99855fddafbb739620b382c086434e27be259)
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 
135 struct 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 
143 struct 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 
165 struct wds_probe_data {
166 #ifdef notyet
167 	int sc_irq, sc_drq;
168 #endif
169 	int sc_scsi_dev;
170 };
171 
172 integrate void
173 	wds_wait(bus_space_tag_t, bus_space_handle_t, int, int, int);
174 int     wds_cmd(bus_space_tag_t, bus_space_handle_t, u_char *, int);
175 integrate void wds_finish_scbs(struct wds_softc *);
176 int     wdsintr(void *);
177 integrate void wds_reset_scb(struct wds_softc *, struct wds_scb *);
178 void    wds_free_scb(struct wds_softc *, struct wds_scb *);
179 integrate int wds_init_scb(struct wds_softc *, struct wds_scb *);
180 struct	wds_scb *wds_get_scb(struct wds_softc *);
181 struct	wds_scb *wds_scb_phys_kv(struct wds_softc *, u_long);
182 void	wds_queue_scb(struct wds_softc *, struct wds_scb *);
183 void	wds_collect_mbo(struct wds_softc *);
184 void	wds_start_scbs(struct wds_softc *);
185 void    wds_done(struct wds_softc *, struct wds_scb *, u_char);
186 int	wds_find(bus_space_tag_t, bus_space_handle_t, struct wds_probe_data *);
187 void	wds_attach(struct wds_softc *, struct wds_probe_data *);
188 void	wds_init(struct wds_softc *, int);
189 void	wds_inquire_setup_information(struct wds_softc *);
190 void    wdsminphys(struct buf *);
191 void	wds_scsipi_request(struct scsipi_channel *,
192 	    scsipi_adapter_req_t, void *);
193 int	wds_poll(struct wds_softc *, struct scsipi_xfer *, int);
194 int	wds_ipoll(struct wds_softc *, struct wds_scb *, int);
195 void	wds_timeout(void *);
196 int	wds_create_scbs(struct wds_softc *, void *, size_t);
197 
198 int	wdsprobe(device_t, cfdata_t, void *);
199 void	wdsattach(device_t, device_t, void *);
200 
201 CFATTACH_DECL_NEW(wds, sizeof(struct wds_softc),
202     wdsprobe, wdsattach, NULL, NULL);
203 
204 #ifdef WDSDEBUG
205 int wds_debug = 0;
206 #endif
207 
208 #define	WDS_ABORT_TIMEOUT	2000	/* time to wait for abort (mSec) */
209 
210 integrate void
wds_wait(bus_space_tag_t iot,bus_space_handle_t ioh,int port,int mask,int val)211 wds_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  */
222 int
wds_cmd(bus_space_tag_t iot,bus_space_handle_t ioh,u_char * ibuf,int icnt)223 wds_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  */
243 int
wdsprobe(device_t parent,cfdata_t match,void * aux)244 wdsprobe(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  */
307 void
wdsattach(device_t parent,device_t self,void * aux)308 wdsattach(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 
365 void
wds_attach(struct wds_softc * sc,struct wds_probe_data * wpd)366 wds_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 
408 integrate void
wds_finish_scbs(struct wds_softc * sc)409 wds_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 
433 AGAIN:
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  */
467 int
wdsintr(void * arg)468 wdsintr(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 
503 integrate void
wds_reset_scb(struct wds_softc * sc,struct wds_scb * scb)504 wds_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  */
513 void
wds_free_scb(struct wds_softc * sc,struct wds_scb * scb)514 wds_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 
524 integrate int
wds_init_scb(struct wds_softc * sc,struct wds_scb * scb)525 wds_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  */
582 int
wds_create_scbs(struct wds_softc * sc,void * mem,size_t size)583 wds_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  */
636 struct wds_scb *
wds_get_scb(struct wds_softc * sc)637 wds_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 
652 struct wds_scb *
wds_scb_phys_kv(struct wds_softc * sc,u_long scb_phys)653 wds_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  */
672 void
wds_queue_scb(struct wds_softc * sc,struct wds_scb * scb)673 wds_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  */
683 void
wds_collect_mbo(struct wds_softc * sc)684 wds_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  */
712 void
wds_start_scbs(struct wds_softc * sc)713 wds_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  */
762 void
wds_done(struct wds_softc * sc,struct wds_scb * scb,u_char stat)763 wds_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 
870 int
wds_find(bus_space_tag_t iot,bus_space_handle_t ioh,struct wds_probe_data * sc)871 wds_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  */
925 void
wds_init(struct wds_softc * sc,int isreset)926 wds_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  */
995 void
wds_inquire_setup_information(struct wds_softc * sc)996 wds_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 
1045 out:
1046 	printf("\n");
1047 
1048 	/*
1049 	 * Free up the resources used by this scb.
1050 	 */
1051 	wds_free_scb(sc, scb);
1052 }
1053 
1054 void
wdsminphys(struct buf * bp)1055 wdsminphys(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  */
1066 void
wds_scsipi_request(struct scsipi_channel * chan,scsipi_adapter_req_t req,void * arg)1067 wds_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  */
1272 int
wds_poll(struct wds_softc * sc,struct scsipi_xfer * xs,int count)1273 wds_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  */
1297 int
wds_ipoll(struct wds_softc * sc,struct wds_scb * scb,int count)1298 wds_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 
1319 void
wds_timeout(void * arg)1320 wds_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