1 /* $NetBSD: hcsc.c,v 1.19 2008/04/28 20:23:56 martin Exp $ */
4 * Copyright (c) 2001 Ben Harris
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Mark Brinicombe of Causality Limited.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1996, 1997 Matthias Pfaller.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * HCCS 8-bit SCSI driver using the generic NCR5380 driver
60 * Andy Armstrong gives some details of the HCCS SCSI cards at
61 * <URL:http://www.armlinux.org/~webmail/linux-arm/1997-08/msg00042.html>.
64 #include <sys/cdefs.h>
65 __KERNEL_RCSID(0, "$NetBSD: hcsc.c,v 1.19 2008/04/28 20:23:56 martin Exp $");
67 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/device.h>
73 #include <dev/scsipi/scsi_all.h>
74 #include <dev/scsipi/scsipi_all.h>
75 #include <dev/scsipi/scsiconf.h>
77 #include <dev/ic/ncr5380reg.h>
78 #include <dev/ic/ncr5380var.h>
80 #include <machine/bootconfig.h>
82 #include <dev/podulebus/podulebus.h>
83 #include <dev/podulebus/podules.h>
84 #include <dev/podulebus/powerromreg.h>
86 #include <dev/podulebus/hcscreg.h>
88 int hcsc_match(device_t
, cfdata_t
, void *);
89 void hcsc_attach(device_t
, device_t
, void *);
91 static int hcsc_pdma_in(struct ncr5380_softc
*, int, int, uint8_t *);
92 static int hcsc_pdma_out(struct ncr5380_softc
*, int, int, uint8_t *);
96 * HCCS 8-bit SCSI softc structure.
98 * Contains the generic ncr5380 device node, podule information and
99 * global information required by the driver.
103 struct ncr5380_softc sc_ncr5380
;
104 bus_space_tag_t sc_pdmat
;
105 bus_space_handle_t sc_pdmah
;
107 struct evcnt sc_intrcnt
;
110 CFATTACH_DECL_NEW(hcsc
, sizeof(struct hcsc_softc
),
111 hcsc_match
, hcsc_attach
, NULL
, NULL
);
114 * Card probe function
116 * Just match the manufacturer and podule ID's
120 hcsc_match(device_t parent
, cfdata_t cf
, void *aux
)
122 struct podulebus_attach_args
*pa
= aux
;
125 if (pa
->pa_product
== PODULE_HCCS_IDESCSI
&&
126 strncmp(pa
->pa_descr
, "SCSI", 4) == 0)
129 if (pa
->pa_product
== PODULE_ALSYSTEMS_SCSI
&&
130 podulebus_initloader(pa
) == 0 &&
131 podloader_callloader(pa
, 0, 0) == PRID_HCCS_SCSI1
)
137 * Card attach function
142 hcsc_attach(device_t parent
, device_t self
, void *aux
)
144 struct hcsc_softc
*sc
= device_private(self
);
145 struct ncr5380_softc
*ncr_sc
= &sc
->sc_ncr5380
;
146 struct podulebus_attach_args
*pa
= aux
;
147 #ifndef NCR5380_USE_BUS_SPACE
150 char hi_option
[sizeof(self
->dv_xname
) + 8];
152 ncr_sc
->sc_dev
= self
;
153 ncr_sc
->sc_min_dma_len
= 0;
154 ncr_sc
->sc_no_disconnect
= 0;
155 ncr_sc
->sc_parity_disable
= 0;
157 ncr_sc
->sc_dma_alloc
= NULL
;
158 ncr_sc
->sc_dma_free
= NULL
;
159 ncr_sc
->sc_dma_poll
= NULL
;
160 ncr_sc
->sc_dma_setup
= NULL
;
161 ncr_sc
->sc_dma_start
= NULL
;
162 ncr_sc
->sc_dma_eop
= NULL
;
163 ncr_sc
->sc_dma_stop
= NULL
;
164 ncr_sc
->sc_intr_on
= NULL
;
165 ncr_sc
->sc_intr_off
= NULL
;
167 #ifdef NCR5380_USE_BUS_SPACE
168 ncr_sc
->sc_regt
= pa
->pa_fast_t
;
169 bus_space_map(ncr_sc
->sc_regt
,
170 pa
->pa_fast_base
+ HCSC_DP8490_OFFSET
, 8, 0,
181 iobase
= (u_char
*)pa
->pa_fast_base
+ HCSC_DP8490_OFFSET
;
182 ncr_sc
->sci_r0
= iobase
+ 0;
183 ncr_sc
->sci_r1
= iobase
+ 4;
184 ncr_sc
->sci_r2
= iobase
+ 8;
185 ncr_sc
->sci_r3
= iobase
+ 12;
186 ncr_sc
->sci_r4
= iobase
+ 16;
187 ncr_sc
->sci_r5
= iobase
+ 20;
188 ncr_sc
->sci_r6
= iobase
+ 24;
189 ncr_sc
->sci_r7
= iobase
+ 28;
191 sc
->sc_pdmat
= pa
->pa_mod_t
;
192 bus_space_map(sc
->sc_pdmat
, pa
->pa_mod_base
+ HCSC_PDMA_OFFSET
, 1, 0,
195 ncr_sc
->sc_rev
= NCR_VARIANT_DP8490
;
197 ncr_sc
->sc_pio_in
= hcsc_pdma_in
;
198 ncr_sc
->sc_pio_out
= hcsc_pdma_out
;
200 /* Provide an override for the host id */
201 ncr_sc
->sc_channel
.chan_id
= 7;
202 snprintf(hi_option
, sizeof(hi_option
), "%s.hostid",
204 (void)get_bootconf_option(boot_args
, hi_option
,
205 BOOTOPT_TYPE_INT
, &ncr_sc
->sc_channel
.chan_id
);
206 ncr_sc
->sc_adapter
.adapt_minphys
= minphys
;
208 aprint_normal(": host ID %d\n", ncr_sc
->sc_channel
.chan_id
);
210 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
211 device_xname(self
), "intr");
212 sc
->sc_ih
= podulebus_irq_establish(pa
->pa_ih
, IPL_BIO
, ncr5380_intr
,
213 sc
, &sc
->sc_intrcnt
);
215 ncr5380_attach(ncr_sc
);
218 #ifndef HCSC_TSIZE_OUT
219 #define HCSC_TSIZE_OUT 512
222 #ifndef HCSC_TSIZE_IN
223 #define HCSC_TSIZE_IN 512
226 #define TIMEOUT 1000000
229 hcsc_ready(struct ncr5380_softc
*sc
)
233 for (i
= TIMEOUT
; i
> 0; i
--) {
234 if ((NCR5380_READ(sc
,sci_csr
) &
235 (SCI_CSR_DREQ
| SCI_CSR_PHASE_MATCH
)) ==
236 (SCI_CSR_DREQ
| SCI_CSR_PHASE_MATCH
))
239 if ((NCR5380_READ(sc
, sci_csr
) & SCI_CSR_PHASE_MATCH
) == 0 ||
243 printf("%s: ready timeout\n", device_xname(sc
->sc_dev
));
249 /* Return zero on success. */
250 static inline void hcsc_wait_not_req(struct ncr5380_softc
*sc
)
254 for (timo
= TIMEOUT
; timo
; timo
--) {
255 if ((NCR5380_READ(sc
, sci_bus_csr
) & SCI_BUS_REQ
) == 0 ||
256 (NCR5380_READ(sc
, sci_csr
) & SCI_CSR_PHASE_MATCH
) == 0 ||
261 printf("%s: pdma not_req timeout\n", device_xname(sc
->sc_dev
));
265 hcsc_pdma_in(struct ncr5380_softc
*ncr_sc
, int phase
, int datalen
,
268 struct hcsc_softc
*sc
= (struct hcsc_softc
*)ncr_sc
;
269 bus_space_tag_t pdmat
= sc
->sc_pdmat
;
270 bus_space_handle_t pdmah
= sc
->sc_pdmah
;
275 NCR5380_WRITE(ncr_sc
, sci_mode
,
276 NCR5380_READ(ncr_sc
, sci_mode
) | SCI_MODE_DMA
);
277 NCR5380_WRITE(ncr_sc
, sci_irecv
, 0);
281 len
= min(resid
, HCSC_TSIZE_IN
);
282 if (hcsc_ready(ncr_sc
) == 0)
284 bus_space_read_multi_1(pdmat
, pdmah
, 0, data
, len
);
289 hcsc_wait_not_req(ncr_sc
);
292 SCI_CLR_INTR(ncr_sc
);
293 NCR5380_WRITE(ncr_sc
, sci_mode
,
294 NCR5380_READ(ncr_sc
, sci_mode
) & ~SCI_MODE_DMA
);
296 return datalen
- resid
;
300 hcsc_pdma_out(struct ncr5380_softc
*ncr_sc
, int phase
, int datalen
,
303 struct hcsc_softc
*sc
= (struct hcsc_softc
*)ncr_sc
;
304 bus_space_tag_t pdmat
= sc
->sc_pdmat
;
305 bus_space_handle_t pdmah
= sc
->sc_pdmah
;
306 int i
, s
, icmd
, resid
;
309 icmd
= NCR5380_READ(ncr_sc
, sci_icmd
) & SCI_ICMD_RMASK
;
310 NCR5380_WRITE(ncr_sc
, sci_icmd
, icmd
| SCI_ICMD_DATA
);
311 NCR5380_WRITE(ncr_sc
, sci_mode
,
312 NCR5380_READ(ncr_sc
, sci_mode
) | SCI_MODE_DMA
);
313 NCR5380_WRITE(ncr_sc
, sci_dma_send
, 0);
316 if (hcsc_ready(ncr_sc
) == 0)
319 if (resid
> HCSC_TSIZE_OUT
) {
321 * Because of the chips DMA prefetch, phase changes
322 * etc, won't be detected until we have written at
323 * least one byte more. We pre-write 4 bytes so
324 * subsequent transfers will be aligned to a 4 byte
325 * boundary. Assuming disconects will only occur on
326 * block boundaries, we then correct for the pre-write
327 * when and if we get a phase change. If the chip had
328 * DMA byte counting hardware, the assumption would not
331 bus_space_write_multi_1(pdmat
, pdmah
, 0, data
, 4);
335 for (; resid
>= HCSC_TSIZE_OUT
; resid
-= HCSC_TSIZE_OUT
) {
336 if (hcsc_ready(ncr_sc
) == 0) {
337 resid
+= 4; /* Overshot */
340 bus_space_write_multi_1(pdmat
, pdmah
, 0, data
,
342 data
+= HCSC_TSIZE_OUT
;
344 if (hcsc_ready(ncr_sc
) == 0) {
345 resid
+= 4; /* Overshot */
351 bus_space_write_multi_1(pdmat
, pdmah
, 0, data
, resid
);
354 for (i
= TIMEOUT
; i
> 0; i
--) {
355 if ((NCR5380_READ(ncr_sc
, sci_csr
)
356 & (SCI_CSR_DREQ
|SCI_CSR_PHASE_MATCH
))
361 bus_space_write_1(pdmat
, pdmah
, 0, 0);
363 printf("%s: timeout waiting for final SCI_DSR_DREQ.\n",
364 device_xname(ncr_sc
->sc_dev
));
366 hcsc_wait_not_req(ncr_sc
);
368 SCI_CLR_INTR(ncr_sc
);
369 NCR5380_WRITE(ncr_sc
, sci_mode
,
370 NCR5380_READ(ncr_sc
, sci_mode
) & ~SCI_MODE_DMA
);
371 NCR5380_WRITE(ncr_sc
, sci_icmd
, icmd
);
373 return datalen
- resid
;