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