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