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