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