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