1 /* $NetBSD: wds.c,v 1.73 2009/05/12 09:10:16 cegger Exp $ */
10 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
11 * All rights reserved.
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.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
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.
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.
40 * Copyright (c) 1994, 1995 Julian Highfield. All rights reserved.
41 * Portions copyright (c) 1994, 1996, 1997
42 * Charles M. Hannum. All rights reserved.
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
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.
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.
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.
78 * Loosely based on Theo Deraadt's unfinished attempt.
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: wds.c,v 1.73 2009/05/12 09:10:16 cegger Exp $");
90 #define integrate static inline
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/malloc.h>
101 #include <sys/proc.h>
103 #include <uvm/uvm_extern.h>
106 #include <sys/intr.h>
108 #include <dev/scsipi/scsi_all.h>
109 #include <dev/scsipi/scsipi_all.h>
110 #include <dev/scsipi/scsiconf.h>
112 #include <dev/isa/isavar.h>
113 #include <dev/isa/isadmavar.h>
115 #include <dev/isa/wdsreg.h>
117 #define WDS_ISA_IOSIZE 8
120 #define Debugger() panic("should call debugger here (wds.c)")
123 #define WDS_MAXXFER ((WDS_NSEG - 1) << PGSHIFT)
125 #define WDS_MBX_SIZE 16
127 #define WDS_SCB_MAX 32
128 #define SCB_HASH_SIZE 32 /* hash table size for phystokv */
129 #define SCB_HASH_SHIFT 9
130 #define SCB_HASH(x) ((((long)(x))>>SCB_HASH_SHIFT) & (SCB_HASH_SIZE - 1))
132 #define wds_nextmbx(wmb, mbx, mbio) \
133 if ((wmb) == &(mbx)->mbio[WDS_MBX_SIZE - 1]) \
134 (wmb) = &(mbx)->mbio[0]; \
139 struct wds_mbx_out mbo
[WDS_MBX_SIZE
];
140 struct wds_mbx_in mbi
[WDS_MBX_SIZE
];
141 struct wds_mbx_out
*cmbo
; /* Collection Mail Box out */
142 struct wds_mbx_out
*tmbo
; /* Target Mail Box out */
143 struct wds_mbx_in
*tmbi
; /* Target Mail Box in */
147 struct device sc_dev
;
149 bus_space_tag_t sc_iot
;
150 bus_space_handle_t sc_ioh
;
151 bus_dma_tag_t sc_dmat
;
152 bus_dmamap_t sc_dmamap_mbox
; /* maps the mailbox */
155 struct wds_mbx
*sc_mbx
;
156 #define wmbx (sc->sc_mbx)
157 struct wds_scb
*sc_scbhash
[SCB_HASH_SIZE
];
158 TAILQ_HEAD(, wds_scb
) sc_free_scb
, sc_waiting_scb
;
159 int sc_numscbs
, sc_mbofull
;
161 struct scsipi_adapter sc_adapter
;
162 struct scsipi_channel sc_channel
;
168 struct wds_probe_data
{
176 wds_wait(bus_space_tag_t
, bus_space_handle_t
, int, int, int);
177 int wds_cmd(bus_space_tag_t
, bus_space_handle_t
, u_char
*, int);
178 integrate
void wds_finish_scbs(struct wds_softc
*);
180 integrate
void wds_reset_scb(struct wds_softc
*, struct wds_scb
*);
181 void wds_free_scb(struct wds_softc
*, struct wds_scb
*);
182 integrate
int wds_init_scb(struct wds_softc
*, struct wds_scb
*);
183 struct wds_scb
*wds_get_scb(struct wds_softc
*);
184 struct wds_scb
*wds_scb_phys_kv(struct wds_softc
*, u_long
);
185 void wds_queue_scb(struct wds_softc
*, struct wds_scb
*);
186 void wds_collect_mbo(struct wds_softc
*);
187 void wds_start_scbs(struct wds_softc
*);
188 void wds_done(struct wds_softc
*, struct wds_scb
*, u_char
);
189 int wds_find(bus_space_tag_t
, bus_space_handle_t
, struct wds_probe_data
*);
190 void wds_attach(struct wds_softc
*, struct wds_probe_data
*);
191 void wds_init(struct wds_softc
*, int);
192 void wds_inquire_setup_information(struct wds_softc
*);
193 void wdsminphys(struct buf
*);
194 void wds_scsipi_request(struct scsipi_channel
*,
195 scsipi_adapter_req_t
, void *);
196 int wds_poll(struct wds_softc
*, struct scsipi_xfer
*, int);
197 int wds_ipoll(struct wds_softc
*, struct wds_scb
*, int);
198 void wds_timeout(void *);
199 int wds_create_scbs(struct wds_softc
*, void *, size_t);
201 int wdsprobe(device_t
, cfdata_t
, void *);
202 void wdsattach(device_t
, device_t
, void *);
204 CFATTACH_DECL(wds
, sizeof(struct wds_softc
),
205 wdsprobe
, wdsattach
, NULL
, NULL
);
211 #define WDS_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
214 wds_wait(bus_space_tag_t iot
, bus_space_handle_t ioh
, int port
, int mask
, int val
)
217 while ((bus_space_read_1(iot
, ioh
, port
) & mask
) != val
)
222 * Write a command to the board's I/O ports.
225 wds_cmd(bus_space_tag_t iot
, bus_space_handle_t ioh
, u_char
*ibuf
, int icnt
)
229 wds_wait(iot
, ioh
, WDS_STAT
, WDSS_RDY
, WDSS_RDY
);
232 bus_space_write_1(iot
, ioh
, WDS_CMD
, *ibuf
++);
233 wds_wait(iot
, ioh
, WDS_STAT
, WDSS_RDY
, WDSS_RDY
);
234 c
= bus_space_read_1(iot
, ioh
, WDS_STAT
);
243 * Check for the presence of a WD7000 SCSI controller.
246 wdsprobe(device_t parent
, cfdata_t match
, void *aux
)
248 struct isa_attach_args
*ia
= aux
;
249 bus_space_tag_t iot
= ia
->ia_iot
;
250 bus_space_handle_t ioh
;
251 struct wds_probe_data wpd
;
261 if (ISA_DIRECT_CONFIG(ia
))
264 /* Disallow wildcarded i/o address. */
265 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
)
268 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, WDS_ISA_IOSIZE
, 0, &ioh
))
271 rv
= wds_find(iot
, ioh
, &wpd
);
273 bus_space_unmap(iot
, ioh
, WDS_ISA_IOSIZE
);
277 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
&&
278 ia
->ia_irq
[0].ir_irq
!= wpd
.sc_irq
)
280 if (ia
->ia_drq
[0].ir_drq
!= ISA_UNKNOWN_DRQ
&&
281 ia
->ia_drq
[0].ir_drq
!= wpd
.sc_drq
)
285 ia
->ia_irq
[0].ir_irq
= wpd
.sc_irq
;
288 ia
->ia_drq
[0].ir_drq
= wpd
.sc_drq
;
290 if (ia
->ia_irq
[0].ir_irq
== ISA_UNKNOWN_IRQ
)
292 if (ia
->ia_drq
[0].ir_drq
== ISA_UNKNOWN_DRQ
)
299 ia
->ia_io
[0].ir_size
= WDS_ISA_IOSIZE
;
307 * Attach all available units.
310 wdsattach(device_t parent
, device_t self
, void *aux
)
312 struct isa_attach_args
*ia
= aux
;
313 struct wds_softc
*sc
= (void *)self
;
314 bus_space_tag_t iot
= ia
->ia_iot
;
315 bus_space_handle_t ioh
;
316 struct wds_probe_data wpd
;
317 isa_chipset_tag_t ic
= ia
->ia_ic
;
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");
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");
335 bus_space_write_1(iot
, ioh
, WDS_HCR
, WDSH_DRQEN
);
337 if (wpd
.sc_drq
!= -1) {
338 if ((error
= isa_dmacascade(ic
, wpd
.sc_drq
)) != 0) {
339 aprint_error_dev(&sc
->sc_dev
, "unable to cascade DRQ, error = %d\n", error
);
344 sc
->sc_ih
= isa_intr_establish(ic
, wpd
.sc_irq
, IST_EDGE
, IPL_BIO
,
347 if ((error
= isa_dmacascade(ic
, ia
->ia_drq
[0].ir_drq
)) != 0) {
348 aprint_error_dev(&sc
->sc_dev
, "unable to cascade DRQ, error = %d\n", error
);
352 sc
->sc_ih
= isa_intr_establish(ic
, ia
->ia_irq
[0].ir_irq
, IST_EDGE
,
353 IPL_BIO
, wdsintr
, sc
);
355 if (sc
->sc_ih
== NULL
) {
356 aprint_error_dev(&sc
->sc_dev
, "couldn't establish interrupt\n");
360 wds_attach(sc
, &wpd
);
364 wds_attach(struct wds_softc
*sc
, struct wds_probe_data
*wpd
)
366 struct scsipi_adapter
*adapt
= &sc
->sc_adapter
;
367 struct scsipi_channel
*chan
= &sc
->sc_channel
;
369 TAILQ_INIT(&sc
->sc_free_scb
);
370 TAILQ_INIT(&sc
->sc_waiting_scb
);
373 * Fill in the scsipi_adapter.
375 memset(adapt
, 0, sizeof(*adapt
));
376 adapt
->adapt_dev
= &sc
->sc_dev
;
377 adapt
->adapt_nchannels
= 1;
378 /* adapt_openings initialized below */
379 adapt
->adapt_max_periph
= 1;
380 adapt
->adapt_request
= wds_scsipi_request
;
381 adapt
->adapt_minphys
= minphys
;
384 * Fill in the scsipi_channel.
386 memset(chan
, 0, sizeof(*chan
));
387 chan
->chan_adapter
= adapt
;
388 chan
->chan_bustype
= &scsi_bustype
;
389 chan
->chan_channel
= 0;
390 chan
->chan_ntargets
= 8;
391 chan
->chan_nluns
= 8;
392 chan
->chan_id
= wpd
->sc_scsi_dev
;
395 wds_inquire_setup_information(sc
);
397 /* XXX add support for GROW */
398 adapt
->adapt_openings
= sc
->sc_numscbs
;
401 * ask the adapter what subunits are present
403 config_found(&sc
->sc_dev
, &sc
->sc_channel
, scsiprint
);
407 wds_finish_scbs(struct wds_softc
*sc
)
409 struct wds_mbx_in
*wmbi
;
415 if (wmbi
->stat
== WDS_MBI_FREE
) {
416 for (i
= 0; i
< WDS_MBX_SIZE
; i
++) {
417 if (wmbi
->stat
!= WDS_MBI_FREE
) {
418 printf("%s: mbi not in round-robin order\n",
419 device_xname(&sc
->sc_dev
));
422 wds_nextmbx(wmbi
, wmbx
, mbi
);
425 printf("%s: mbi interrupt with no full mailboxes\n",
426 device_xname(&sc
->sc_dev
));
433 scb
= wds_scb_phys_kv(sc
, phystol(wmbi
->scb_addr
));
435 printf("%s: bad mbi scb pointer; skipping\n",
436 device_xname(&sc
->sc_dev
));
442 u_char
*cp
= scb
->cmd
.xx
;
443 printf("op=%x %x %x %x %x %x\n",
444 cp
[0], cp
[1], cp
[2], cp
[3], cp
[4], cp
[5]);
445 printf("stat %x for mbi addr = %p, ",
447 printf("scb addr = %p\n", scb
);
449 #endif /* WDSDEBUG */
451 callout_stop(&scb
->xs
->xs_callout
);
452 wds_done(sc
, scb
, wmbi
->stat
);
455 wmbi
->stat
= WDS_MBI_FREE
;
456 wds_nextmbx(wmbi
, wmbx
, mbi
);
457 } while (wmbi
->stat
!= WDS_MBI_FREE
);
463 * Process an interrupt.
468 struct wds_softc
*sc
= arg
;
469 bus_space_tag_t iot
= sc
->sc_iot
;
470 bus_space_handle_t ioh
= sc
->sc_ioh
;
473 /* Was it really an interrupt from the board? */
474 if ((bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_IRQ
) == 0)
477 /* Get the interrupt status byte. */
478 c
= bus_space_read_1(iot
, ioh
, WDS_IRQSTAT
) & WDSI_MASK
;
480 /* Acknowledge (which resets) the interrupt. */
481 bus_space_write_1(iot
, ioh
, WDS_IRQACK
, 0x00);
493 aprint_error_dev(&sc
->sc_dev
, "unrecognized interrupt type %02x", c
);
501 wds_reset_scb(struct wds_softc
*sc
, struct wds_scb
*scb
)
508 * Free the command structure, the outgoing mailbox and the data buffer.
511 wds_free_scb(struct wds_softc
*sc
, struct wds_scb
*scb
)
516 wds_reset_scb(sc
, scb
);
517 TAILQ_INSERT_HEAD(&sc
->sc_free_scb
, scb
, chain
);
522 wds_init_scb(struct wds_softc
*sc
, struct wds_scb
*scb
)
524 bus_dma_tag_t dmat
= sc
->sc_dmat
;
528 * XXX Should we put a DIAGNOSTIC check for multiple
529 * XXX SCB inits here?
532 memset(scb
, 0, sizeof(struct wds_scb
));
535 * Create DMA maps for this SCB.
537 error
= bus_dmamap_create(dmat
, sizeof(struct wds_scb
), 1,
538 sizeof(struct wds_scb
), 0, BUS_DMA_NOWAIT
, &scb
->dmamap_self
);
540 aprint_error_dev(&sc
->sc_dev
, "can't create scb dmamap_self\n");
544 error
= bus_dmamap_create(dmat
, WDS_MAXXFER
, WDS_NSEG
, WDS_MAXXFER
,
545 0, BUS_DMA_NOWAIT
|BUS_DMA_ALLOCNOW
, &scb
->dmamap_xfer
);
547 aprint_error_dev(&sc
->sc_dev
, "can't create scb dmamap_xfer\n");
548 bus_dmamap_destroy(dmat
, scb
->dmamap_self
);
553 * Load the permanent DMA maps.
555 error
= bus_dmamap_load(dmat
, scb
->dmamap_self
, scb
,
556 sizeof(struct wds_scb
), NULL
, BUS_DMA_NOWAIT
);
558 aprint_error_dev(&sc
->sc_dev
, "can't load scb dmamap_self\n");
559 bus_dmamap_destroy(dmat
, scb
->dmamap_self
);
560 bus_dmamap_destroy(dmat
, scb
->dmamap_xfer
);
565 * put in the phystokv hash table
566 * Never gets taken out.
568 scb
->hashkey
= scb
->dmamap_self
->dm_segs
[0].ds_addr
;
569 hashnum
= SCB_HASH(scb
->hashkey
);
570 scb
->nexthash
= sc
->sc_scbhash
[hashnum
];
571 sc
->sc_scbhash
[hashnum
] = scb
;
572 wds_reset_scb(sc
, scb
);
577 * Create a set of scbs and add them to the free list.
580 wds_create_scbs(struct wds_softc
*sc
, void *mem
, size_t size
)
582 bus_dma_segment_t seg
;
586 if (sc
->sc_numscbs
>= WDS_SCB_MAX
)
589 if ((scb
= mem
) != NULL
)
593 error
= bus_dmamem_alloc(sc
->sc_dmat
, size
, PAGE_SIZE
, 0, &seg
,
594 1, &rseg
, BUS_DMA_NOWAIT
);
596 aprint_error_dev(&sc
->sc_dev
, "can't allocate memory for scbs\n");
600 error
= bus_dmamem_map(sc
->sc_dmat
, &seg
, rseg
, size
,
601 (void *)&scb
, BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
);
603 aprint_error_dev(&sc
->sc_dev
, "can't map memory for scbs\n");
604 bus_dmamem_free(sc
->sc_dmat
, &seg
, rseg
);
609 memset(scb
, 0, size
);
610 while (size
> sizeof(struct wds_scb
) && sc
->sc_numscbs
< WDS_SCB_MAX
) {
611 error
= wds_init_scb(sc
, scb
);
613 aprint_error_dev(&sc
->sc_dev
, "can't initialize scb\n");
616 TAILQ_INSERT_TAIL(&sc
->sc_free_scb
, scb
, chain
);
617 scb
= (struct wds_scb
*)((char *)scb
+
618 ALIGN(sizeof(struct wds_scb
)));
619 size
-= ALIGN(sizeof(struct wds_scb
));
629 * If there are none, see if we can allocate a new one. If so, put it in
630 * the hash table too otherwise either return an error or sleep.
633 wds_get_scb(struct wds_softc
*sc
)
639 scb
= TAILQ_FIRST(&sc
->sc_free_scb
);
641 TAILQ_REMOVE(&sc
->sc_free_scb
, scb
, chain
);
642 scb
->flags
|= SCB_ALLOC
;
649 wds_scb_phys_kv(struct wds_softc
*sc
, u_long scb_phys
)
651 int hashnum
= SCB_HASH(scb_phys
);
652 struct wds_scb
*scb
= sc
->sc_scbhash
[hashnum
];
655 if (scb
->hashkey
== scb_phys
)
657 /* XXX Check to see if it matches the sense command block. */
658 if (scb
->hashkey
== (scb_phys
- sizeof(struct wds_cmd
)))
666 * Queue a SCB to be sent to the controller, and send it if possible.
669 wds_queue_scb(struct wds_softc
*sc
, struct wds_scb
*scb
)
672 TAILQ_INSERT_TAIL(&sc
->sc_waiting_scb
, scb
, chain
);
677 * Garbage collect mailboxes that are no longer in use.
680 wds_collect_mbo(struct wds_softc
*sc
)
682 struct wds_mbx_out
*wmbo
; /* Mail Box Out pointer */
689 while (sc
->sc_mbofull
> 0) {
690 if (wmbo
->cmd
!= WDS_MBO_FREE
)
694 scb
= wds_scb_phys_kv(sc
, phystol(wmbo
->scb_addr
));
695 scb
->flags
&= ~SCB_SENDING
;
699 wds_nextmbx(wmbo
, wmbx
, mbo
);
706 * Send as many SCBs as we have empty mailboxes for.
709 wds_start_scbs(struct wds_softc
*sc
)
711 bus_space_tag_t iot
= sc
->sc_iot
;
712 bus_space_handle_t ioh
= sc
->sc_ioh
;
713 struct wds_mbx_out
*wmbo
; /* Mail Box Out pointer */
719 while ((scb
= sc
->sc_waiting_scb
.tqh_first
) != NULL
) {
720 if (sc
->sc_mbofull
>= WDS_MBX_SIZE
) {
722 if (sc
->sc_mbofull
>= WDS_MBX_SIZE
) {
724 wds_cmd(iot
, ioh
, &c
, sizeof c
);
729 TAILQ_REMOVE(&sc
->sc_waiting_scb
, scb
, chain
);
731 scb
->flags
|= SCB_SENDING
;
734 /* Link scb to mbo. */
735 ltophys(scb
->dmamap_self
->dm_segs
[0].ds_addr
+
736 offsetof(struct wds_scb
, cmd
), wmbo
->scb_addr
);
737 /* XXX What about aborts? */
738 wmbo
->cmd
= WDS_MBO_START
;
740 /* Tell the card to poll immediately. */
741 c
= WDSC_MSTART(wmbo
- wmbx
->mbo
);
742 wds_cmd(sc
->sc_iot
, sc
->sc_ioh
, &c
, sizeof c
);
744 if ((scb
->flags
& SCB_POLLED
) == 0)
745 callout_reset(&scb
->xs
->xs_callout
,
746 mstohz(scb
->timeout
), wds_timeout
, scb
);
749 wds_nextmbx(wmbo
, wmbx
, mbo
);
756 * Process the result of a SCSI command.
759 wds_done(struct wds_softc
*sc
, struct wds_scb
*scb
, u_char stat
)
761 bus_dma_tag_t dmat
= sc
->sc_dmat
;
762 struct scsipi_xfer
*xs
= scb
->xs
;
766 /* Don't release the SCB if it was an internal command. */
768 scb
->flags
|= SCB_DONE
;
773 * If we were a data transfer, unload the map that described
777 bus_dmamap_sync(dmat
, scb
->dmamap_xfer
, 0,
778 scb
->dmamap_xfer
->dm_mapsize
,
779 (xs
->xs_control
& XS_CTL_DATA_IN
) ?
780 BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
781 bus_dmamap_unload(dmat
, scb
->dmamap_xfer
);
783 if (xs
->error
== XS_NOERROR
) {
784 /* If all went well, or an error is acceptable. */
785 if (stat
== WDS_MBI_OK
) {
786 /* OK, set the result */
789 /* Check the mailbox status. */
793 * SCSI error recorded in scb,
794 * counts as WDS_MBI_OK
796 switch (scb
->cmd
.venderr
) {
798 aprint_error_dev(&sc
->sc_dev
, "Is this "
801 xs
->error
= XS_DRIVER_STUFFUP
;
805 aprint_error_dev(&sc
->sc_dev
, "OK, see SCSI "
808 if (scb
->cmd
.stat
== SCSI_CHECK
||
809 scb
->cmd
.stat
== SCSI_BUSY
) {
810 xs
->status
= scb
->cmd
.stat
;
816 printf("%s: DMA underrun!\n",
817 device_xname(&sc
->sc_dev
));
820 * Hits this if the target
821 * returns fewer that datalen
822 * bytes (eg my CD-ROM, which
823 * returns a short version
824 * string, or if DMA is
830 printf("%s: VENDOR ERROR "
832 device_xname(&sc
->sc_dev
),
836 xs
->error
= XS_DRIVER_STUFFUP
;
842 * The documentation isn't clear on
843 * what conditions might generate this,
844 * but selection timeouts are the only
845 * one I can think of.
847 xs
->error
= XS_SELTIMEOUT
;
850 case WDS_MBI_ETARCMD
:
854 case WDS_MBI_ESRESET
:
855 case WDS_MBI_EHRESET
:
856 xs
->error
= XS_DRIVER_STUFFUP
;
862 wds_free_scb(sc
, scb
);
867 wds_find(bus_space_tag_t iot
, bus_space_handle_t ioh
, struct wds_probe_data
*sc
)
874 * Sending a command causes the CMDRDY bit to clear.
876 for (i
= 5; i
; i
--) {
877 if ((bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_RDY
) != 0)
884 bus_space_write_1(iot
, ioh
, WDS_CMD
, WDSC_NOOP
);
885 if ((bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_RDY
) != 0)
888 bus_space_write_1(iot
, ioh
, WDS_HCR
, WDSH_SCSIRESET
|WDSH_ASCRESET
);
890 bus_space_write_1(iot
, ioh
, WDS_HCR
, 0x00);
892 wds_wait(iot
, ioh
, WDS_STAT
, WDSS_RDY
, WDSS_RDY
);
893 if (bus_space_read_1(iot
, ioh
, WDS_IRQSTAT
) != 1)
894 if (bus_space_read_1(iot
, ioh
, WDS_IRQSTAT
) != 7)
897 for (i
= 2000; i
; i
--) {
898 if ((bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_RDY
) != 0)
910 /* XXX Can we do this better? */
918 * Initialise the board and driver.
921 wds_init(struct wds_softc
*sc
, int isreset
)
923 bus_space_tag_t iot
= sc
->sc_iot
;
924 bus_space_handle_t ioh
= sc
->sc_ioh
;
925 bus_dma_segment_t seg
;
926 struct wds_setup init
;
934 * Allocate the mailbox.
936 if (bus_dmamem_alloc(sc
->sc_dmat
, PAGE_SIZE
, PAGE_SIZE
, 0, &seg
, 1,
937 &rseg
, BUS_DMA_NOWAIT
) ||
938 bus_dmamem_map(sc
->sc_dmat
, &seg
, rseg
, PAGE_SIZE
,
939 (void **)&wmbx
, BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
))
940 panic("wds_init: can't create or map mailbox");
943 * Since DMA memory allocation is always rounded up to a
944 * page size, create some scbs from the leftovers.
946 if (wds_create_scbs(sc
, ((char *)wmbx
) +
947 ALIGN(sizeof(struct wds_mbx
)),
948 PAGE_SIZE
- ALIGN(sizeof(struct wds_mbx
))))
949 panic("wds_init: can't create scbs");
952 * Create and load the mailbox DMA map.
954 if (bus_dmamap_create(sc
->sc_dmat
, sizeof(struct wds_mbx
), 1,
955 sizeof(struct wds_mbx
), 0, BUS_DMA_NOWAIT
, &sc
->sc_dmamap_mbox
) ||
956 bus_dmamap_load(sc
->sc_dmat
, sc
->sc_dmamap_mbox
, wmbx
,
957 sizeof(struct wds_mbx
), NULL
, BUS_DMA_NOWAIT
))
958 panic("wds_ionit: can't create or load mailbox DMA map");
962 * Set up initial mail box for round-robin operation.
964 for (i
= 0; i
< WDS_MBX_SIZE
; i
++) {
965 wmbx
->mbo
[i
].cmd
= WDS_MBO_FREE
;
966 wmbx
->mbi
[i
].stat
= WDS_MBI_FREE
;
968 wmbx
->cmbo
= wmbx
->tmbo
= &wmbx
->mbo
[0];
969 wmbx
->tmbi
= &wmbx
->mbi
[0];
972 init
.opcode
= WDSC_INIT
;
973 init
.scsi_id
= sc
->sc_channel
.chan_id
;
977 ltophys(sc
->sc_dmamap_mbox
->dm_segs
[0].ds_addr
, init
.mbaddr
);
978 init
.nomb
= init
.nimb
= WDS_MBX_SIZE
;
979 wds_cmd(iot
, ioh
, (u_char
*)&init
, sizeof init
);
981 wds_wait(iot
, ioh
, WDS_STAT
, WDSS_INIT
, WDSS_INIT
);
984 wds_cmd(iot
, ioh
, &c
, sizeof c
);
988 * Read the board's firmware revision information.
991 wds_inquire_setup_information(struct wds_softc
*sc
)
993 bus_space_tag_t iot
= sc
->sc_iot
;
994 bus_space_handle_t ioh
= sc
->sc_ioh
;
1001 scb
= wds_get_scb(sc
);
1003 panic("wds_inquire_setup_information: no scb available");
1008 memset(&scb
->cmd
, 0, sizeof scb
->cmd
);
1009 scb
->cmd
.write
= 0x80;
1010 scb
->cmd
.opcode
= WDSX_GETFIRMREV
;
1012 /* Will poll card, await result. */
1013 bus_space_write_1(iot
, ioh
, WDS_HCR
, WDSH_DRQEN
);
1014 scb
->flags
|= SCB_POLLED
;
1017 wds_queue_scb(sc
, scb
);
1020 if (wds_ipoll(sc
, scb
, scb
->timeout
))
1023 /* Print the version number. */
1024 printf("%s: version %x.%02x ", device_xname(&sc
->sc_dev
),
1025 scb
->cmd
.targ
, scb
->cmd
.scb
[0]);
1026 sc
->sc_revision
= (scb
->cmd
.targ
<< 8) | scb
->cmd
.scb
[0];
1027 /* Print out the version string. */
1028 j
= 2 + &(scb
->cmd
.targ
);
1029 while ((*j
>= 32) && (*j
< 128)) {
1035 * Determine if we can use scatter/gather.
1037 if (sc
->sc_revision
>= 0x800)
1038 sc
->sc_maxsegs
= WDS_NSEG
;
1044 * Free up the resources used by this scb.
1046 wds_free_scb(sc
, scb
);
1050 wdsminphys(struct buf
*bp
)
1053 if (bp
->b_bcount
> WDS_MAXXFER
)
1054 bp
->b_bcount
= WDS_MAXXFER
;
1059 * Send a SCSI command.
1062 wds_scsipi_request(struct scsipi_channel
*chan
, scsipi_adapter_req_t req
, void *arg
)
1064 struct scsipi_xfer
*xs
;
1065 struct scsipi_periph
*periph
;
1066 struct wds_softc
*sc
= (void *)chan
->chan_adapter
->adapt_dev
;
1067 bus_dma_tag_t dmat
= sc
->sc_dmat
;
1068 struct wds_scb
*scb
;
1069 int error
, seg
, flags
, s
;
1072 case ADAPTER_REQ_RUN_XFER
:
1074 periph
= xs
->xs_periph
;
1076 if (xs
->xs_control
& XS_CTL_RESET
) {
1078 printf("%s: reset!\n", device_xname(&sc
->sc_dev
));
1084 if (xs
->xs_control
& XS_CTL_DATA_UIO
) {
1087 * Let's not worry about UIO. There isn't any code
1088 * for the non-SG boards anyway!
1090 aprint_error_dev(&sc
->sc_dev
, "UIO is untested and disabled!\n");
1091 xs
->error
= XS_DRIVER_STUFFUP
;
1096 flags
= xs
->xs_control
;
1098 /* Get an SCB to use. */
1099 scb
= wds_get_scb(sc
);
1102 * This should never happen as we track the resources
1106 scsipi_printaddr(periph
);
1107 printf("unable to allocate scb\n");
1108 panic("wds_scsipi_request");
1113 scb
->timeout
= xs
->timeout
;
1115 /* Zero out the command structure. */
1116 if (xs
->cmdlen
> sizeof(scb
->cmd
.scb
)) {
1117 aprint_error_dev(&sc
->sc_dev
, "cmdlen %d too large for SCB\n",
1119 xs
->error
= XS_DRIVER_STUFFUP
;
1122 memset(&scb
->cmd
, 0, sizeof scb
->cmd
);
1123 memcpy(&scb
->cmd
.scb
, xs
->cmd
, xs
->cmdlen
);
1125 /* Set up some of the command fields. */
1126 scb
->cmd
.targ
= (periph
->periph_target
<< 5) |
1130 * NOTE: cmd.write may be OK as 0x40 (disable direction
1131 * checking) on boards other than the WD-7000V-ASE. Need
1134 scb
->cmd
.write
= (xs
->xs_control
& XS_CTL_DATA_IN
) ?
1140 if (flags
& XS_CTL_DATA_UIO
) {
1141 error
= bus_dmamap_load_uio(dmat
,
1142 scb
->dmamap_xfer
, (struct uio
*)xs
->data
,
1144 ((flags
& XS_CTL_DATA_IN
) ? BUS_DMA_READ
:
1149 error
= bus_dmamap_load(dmat
,
1150 scb
->dmamap_xfer
, xs
->data
, xs
->datalen
,
1151 NULL
, BUS_DMA_NOWAIT
|
1152 ((flags
& XS_CTL_DATA_IN
) ? BUS_DMA_READ
:
1162 xs
->error
= XS_RESOURCE_SHORTAGE
;
1166 xs
->error
= XS_DRIVER_STUFFUP
;
1167 aprint_error_dev(&sc
->sc_dev
, "error %d loading DMA map\n", error
);
1169 wds_free_scb(sc
, scb
);
1174 bus_dmamap_sync(dmat
, scb
->dmamap_xfer
, 0,
1175 scb
->dmamap_xfer
->dm_mapsize
,
1176 (flags
& XS_CTL_DATA_IN
) ? BUS_DMASYNC_PREREAD
:
1177 BUS_DMASYNC_PREWRITE
);
1179 if (sc
->sc_maxsegs
> 1) {
1181 * Load the hardware scatter/gather map with the
1182 * contents of the DMA map.
1185 seg
< scb
->dmamap_xfer
->dm_nsegs
; seg
++) {
1186 ltophys(scb
->dmamap_xfer
->dm_segs
[seg
].ds_addr
,
1187 scb
->scat_gath
[seg
].seg_addr
);
1188 ltophys(scb
->dmamap_xfer
->dm_segs
[seg
].ds_len
,
1189 scb
->scat_gath
[seg
].seg_len
);
1193 * Set up for scatter/gather transfer.
1195 scb
->cmd
.opcode
= WDSX_SCSISG
;
1196 ltophys(scb
->dmamap_self
->dm_segs
[0].ds_addr
+
1197 offsetof(struct wds_scb
, scat_gath
),
1199 ltophys(scb
->dmamap_self
->dm_nsegs
*
1200 sizeof(struct wds_scat_gath
), scb
->cmd
.len
);
1203 * This board is an ASC or an ASE, and the
1204 * transfer has been mapped contig for us.
1206 scb
->cmd
.opcode
= WDSX_SCSICMD
;
1207 ltophys(scb
->dmamap_xfer
->dm_segs
[0].ds_addr
,
1209 ltophys(scb
->dmamap_xfer
->dm_segs
[0].ds_len
,
1213 scb
->cmd
.opcode
= WDSX_SCSICMD
;
1214 ltophys(0, scb
->cmd
.data
);
1215 ltophys(0, scb
->cmd
.len
);
1218 scb
->cmd
.stat
= 0x00;
1219 scb
->cmd
.venderr
= 0x00;
1220 ltophys(0, scb
->cmd
.link
);
1222 /* XXX Do we really want to do this? */
1223 if (flags
& XS_CTL_POLL
) {
1224 /* Will poll card, await result. */
1225 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
1226 WDS_HCR
, WDSH_DRQEN
);
1227 scb
->flags
|= SCB_POLLED
;
1230 * Will send command, let interrupt routine
1233 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, WDS_HCR
,
1234 WDSH_IRQEN
| WDSH_DRQEN
);
1238 wds_queue_scb(sc
, scb
);
1241 if ((flags
& XS_CTL_POLL
) == 0)
1244 if (wds_poll(sc
, xs
, scb
->timeout
)) {
1246 if (wds_poll(sc
, xs
, scb
->timeout
))
1251 case ADAPTER_REQ_GROW_RESOURCES
:
1252 /* XXX Not supported. */
1255 case ADAPTER_REQ_SET_XFER_MODE
:
1256 /* XXX How do we do this? */
1262 * Poll a particular unit, looking for a particular scb
1265 wds_poll(struct wds_softc
*sc
, struct scsipi_xfer
*xs
, int count
)
1267 bus_space_tag_t iot
= sc
->sc_iot
;
1268 bus_space_handle_t ioh
= sc
->sc_ioh
;
1270 /* timeouts are in msec, so we loop in 1000 usec cycles */
1273 * If we had interrupts enabled, would we
1274 * have got an interrupt?
1276 if (bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_IRQ
)
1278 if (xs
->xs_status
& XS_STS_DONE
)
1280 delay(1000); /* only happens in boot so ok */
1287 * Poll a particular unit, looking for a particular scb
1290 wds_ipoll(struct wds_softc
*sc
, struct wds_scb
*scb
, int count
)
1292 bus_space_tag_t iot
= sc
->sc_iot
;
1293 bus_space_handle_t ioh
= sc
->sc_ioh
;
1295 /* timeouts are in msec, so we loop in 1000 usec cycles */
1298 * If we had interrupts enabled, would we
1299 * have got an interrupt?
1301 if (bus_space_read_1(iot
, ioh
, WDS_STAT
) & WDSS_IRQ
)
1303 if (scb
->flags
& SCB_DONE
)
1305 delay(1000); /* only happens in boot so ok */
1312 wds_timeout(void *arg
)
1314 struct wds_scb
*scb
= arg
;
1315 struct scsipi_xfer
*xs
= scb
->xs
;
1316 struct scsipi_periph
*periph
= xs
->xs_periph
;
1317 struct wds_softc
*sc
=
1318 (void *)periph
->periph_channel
->chan_adapter
->adapt_dev
;
1321 scsipi_printaddr(periph
);
1322 printf("timed out");
1328 * If The scb's mbx is not free, then the board has gone south?
1330 wds_collect_mbo(sc
);
1331 if (scb
->flags
& SCB_SENDING
) {
1332 aprint_error_dev(&sc
->sc_dev
, "not taking commands!\n");
1338 * If it has been through before, then
1339 * a previous abort has failed, don't
1342 if (scb
->flags
& SCB_ABORT
) {
1343 /* abort timed out */
1345 /* XXX Must reset! */
1347 /* abort the operation that has timed out */
1349 scb
->xs
->error
= XS_TIMEOUT
;
1350 scb
->timeout
= WDS_ABORT_TIMEOUT
;
1351 scb
->flags
|= SCB_ABORT
;
1352 wds_queue_scb(sc
, scb
);