xref: /netbsd-src/sys/dev/podulebus/hcsc.c (revision d1579b2d70337e1b895f03478838f880e450f6da)
1*d1579b2dSriastradh /*	$NetBSD: hcsc.c,v 1.22 2018/09/03 16:29:33 riastradh Exp $	*/
25cc459efSbjh21 
35cc459efSbjh21 /*
4c5260261Sbjh21  * Copyright (c) 2001 Ben Harris
55cc459efSbjh21  * Copyright (c) 1998 The NetBSD Foundation, Inc.
65cc459efSbjh21  * All rights reserved.
75cc459efSbjh21  *
85cc459efSbjh21  * This code is derived from software contributed to The NetBSD Foundation
95cc459efSbjh21  * by Mark Brinicombe of Causality Limited.
105cc459efSbjh21  *
115cc459efSbjh21  * Redistribution and use in source and binary forms, with or without
125cc459efSbjh21  * modification, are permitted provided that the following conditions
135cc459efSbjh21  * are met:
145cc459efSbjh21  * 1. Redistributions of source code must retain the above copyright
155cc459efSbjh21  *    notice, this list of conditions and the following disclaimer.
165cc459efSbjh21  * 2. Redistributions in binary form must reproduce the above copyright
175cc459efSbjh21  *    notice, this list of conditions and the following disclaimer in the
185cc459efSbjh21  *    documentation and/or other materials provided with the distribution.
195cc459efSbjh21  *
205cc459efSbjh21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
215cc459efSbjh21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225cc459efSbjh21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235cc459efSbjh21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
245cc459efSbjh21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255cc459efSbjh21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265cc459efSbjh21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275cc459efSbjh21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285cc459efSbjh21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295cc459efSbjh21  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305cc459efSbjh21  * POSSIBILITY OF SUCH DAMAGE.
315cc459efSbjh21  */
32c5260261Sbjh21 /*
33c5260261Sbjh21  * Copyright (c) 1996, 1997 Matthias Pfaller.
34c5260261Sbjh21  * All rights reserved.
35c5260261Sbjh21  *
36c5260261Sbjh21  * Redistribution and use in source and binary forms, with or without
37c5260261Sbjh21  * modification, are permitted provided that the following conditions
38c5260261Sbjh21  * are met:
39c5260261Sbjh21  * 1. Redistributions of source code must retain the above copyright
40c5260261Sbjh21  *    notice, this list of conditions and the following disclaimer.
41c5260261Sbjh21  * 2. Redistributions in binary form must reproduce the above copyright
42c5260261Sbjh21  *    notice, this list of conditions and the following disclaimer in the
43c5260261Sbjh21  *    documentation and/or other materials provided with the distribution.
44c5260261Sbjh21  *
45c5260261Sbjh21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46c5260261Sbjh21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47c5260261Sbjh21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48c5260261Sbjh21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49c5260261Sbjh21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50c5260261Sbjh21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51c5260261Sbjh21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52c5260261Sbjh21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53c5260261Sbjh21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54c5260261Sbjh21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55c5260261Sbjh21  */
565cc459efSbjh21 
575cc459efSbjh21 /*
585cc459efSbjh21  * HCCS 8-bit SCSI driver using the generic NCR5380 driver
59cb6b68a9Sbjh21  *
60cb6b68a9Sbjh21  * Andy Armstrong gives some details of the HCCS SCSI cards at
61cb6b68a9Sbjh21  * <URL:http://www.armlinux.org/~webmail/linux-arm/1997-08/msg00042.html>.
625cc459efSbjh21  */
635cc459efSbjh21 
649ab2c471Slukem #include <sys/cdefs.h>
65*d1579b2dSriastradh __KERNEL_RCSID(0, "$NetBSD: hcsc.c,v 1.22 2018/09/03 16:29:33 riastradh Exp $");
665cc459efSbjh21 
679ab2c471Slukem #include <sys/param.h>
685cc459efSbjh21 
695cc459efSbjh21 #include <sys/systm.h>
705cc459efSbjh21 #include <sys/kernel.h>
715cc459efSbjh21 #include <sys/device.h>
725cc459efSbjh21 #include <sys/buf.h>
735cc459efSbjh21 #include <dev/scsipi/scsi_all.h>
745cc459efSbjh21 #include <dev/scsipi/scsipi_all.h>
755cc459efSbjh21 #include <dev/scsipi/scsiconf.h>
765cc459efSbjh21 
775cc459efSbjh21 #include <dev/ic/ncr5380reg.h>
785cc459efSbjh21 #include <dev/ic/ncr5380var.h>
795cc459efSbjh21 
805cc459efSbjh21 #include <machine/bootconfig.h>
815cc459efSbjh21 
825cc459efSbjh21 #include <dev/podulebus/podulebus.h>
835cc459efSbjh21 #include <dev/podulebus/podules.h>
84e02efcb8Sbjh21 #include <dev/podulebus/powerromreg.h>
855cc459efSbjh21 
8694769968Sbjh21 #include <dev/podulebus/hcscreg.h>
8794769968Sbjh21 
8851475713Stsutsui int  hcsc_match(device_t, cfdata_t, void *);
8951475713Stsutsui void hcsc_attach(device_t, device_t, void *);
905cc459efSbjh21 
9151475713Stsutsui static int hcsc_pdma_in(struct ncr5380_softc *, int, int, uint8_t *);
9251475713Stsutsui static int hcsc_pdma_out(struct ncr5380_softc *, int, int, uint8_t *);
93c5260261Sbjh21 
94c5260261Sbjh21 
955cc459efSbjh21 /*
965cc459efSbjh21  * HCCS 8-bit SCSI softc structure.
975cc459efSbjh21  *
985cc459efSbjh21  * Contains the generic ncr5380 device node, podule information and
995cc459efSbjh21  * global information required by the driver.
1005cc459efSbjh21  */
1015cc459efSbjh21 
1025cc459efSbjh21 struct hcsc_softc {
1035cc459efSbjh21 	struct ncr5380_softc	sc_ncr5380;
104c5260261Sbjh21 	bus_space_tag_t		sc_pdmat;
105c5260261Sbjh21 	bus_space_handle_t	sc_pdmah;
1065cc459efSbjh21 	void		*sc_ih;
1075cc459efSbjh21 	struct evcnt	sc_intrcnt;
1085cc459efSbjh21 };
1095cc459efSbjh21 
11051475713Stsutsui CFATTACH_DECL_NEW(hcsc, sizeof(struct hcsc_softc),
111b75a007dSthorpej     hcsc_match, hcsc_attach, NULL, NULL);
1125cc459efSbjh21 
1135cc459efSbjh21 /*
1145cc459efSbjh21  * Card probe function
1155cc459efSbjh21  *
1165cc459efSbjh21  * Just match the manufacturer and podule ID's
1175cc459efSbjh21  */
1185cc459efSbjh21 
1195cc459efSbjh21 int
hcsc_match(device_t parent,cfdata_t cf,void * aux)12051475713Stsutsui hcsc_match(device_t parent, cfdata_t cf, void *aux)
1215cc459efSbjh21 {
1225cc459efSbjh21 	struct podulebus_attach_args *pa = aux;
1235cc459efSbjh21 
124e02efcb8Sbjh21 	/* Normal ROM */
125fd7e9d6dSbjh21 	if (pa->pa_product == PODULE_HCCS_IDESCSI &&
126fd7e9d6dSbjh21 	    strncmp(pa->pa_descr, "SCSI", 4) == 0)
127fd7e9d6dSbjh21 		return 1;
128e02efcb8Sbjh21 	/* PowerROM */
129e02efcb8Sbjh21 	if (pa->pa_product == PODULE_ALSYSTEMS_SCSI &&
130e02efcb8Sbjh21 	    podulebus_initloader(pa) == 0 &&
131e02efcb8Sbjh21 	    podloader_callloader(pa, 0, 0) == PRID_HCCS_SCSI1)
132e02efcb8Sbjh21 		return 1;
133fd7e9d6dSbjh21 	return 0;
1345cc459efSbjh21 }
1355cc459efSbjh21 
1365cc459efSbjh21 /*
1375cc459efSbjh21  * Card attach function
1385cc459efSbjh21  *
1395cc459efSbjh21  */
1405cc459efSbjh21 
1415cc459efSbjh21 void
hcsc_attach(device_t parent,device_t self,void * aux)14251475713Stsutsui hcsc_attach(device_t parent, device_t self, void *aux)
1435cc459efSbjh21 {
144838ee1e0Sthorpej 	struct hcsc_softc *sc = device_private(self);
14551475713Stsutsui 	struct ncr5380_softc *ncr_sc = &sc->sc_ncr5380;
1465cc459efSbjh21 	struct podulebus_attach_args *pa = aux;
14796dda214Sbjh21 #ifndef NCR5380_USE_BUS_SPACE
14851475713Stsutsui 	uint8_t *iobase;
14996dda214Sbjh21 #endif
150cbab9cadSchs 	char hi_option[sizeof(device_xname(self)) + 8];
1515cc459efSbjh21 
15251475713Stsutsui 	ncr_sc->sc_dev = self;
15351475713Stsutsui 	ncr_sc->sc_min_dma_len = 0;
15451475713Stsutsui 	ncr_sc->sc_no_disconnect = 0;
15551475713Stsutsui 	ncr_sc->sc_parity_disable = 0;
1565cc459efSbjh21 
15751475713Stsutsui 	ncr_sc->sc_dma_alloc = NULL;
15851475713Stsutsui 	ncr_sc->sc_dma_free = NULL;
15951475713Stsutsui 	ncr_sc->sc_dma_poll = NULL;
16051475713Stsutsui 	ncr_sc->sc_dma_setup = NULL;
16151475713Stsutsui 	ncr_sc->sc_dma_start = NULL;
16251475713Stsutsui 	ncr_sc->sc_dma_eop = NULL;
16351475713Stsutsui 	ncr_sc->sc_dma_stop = NULL;
16451475713Stsutsui 	ncr_sc->sc_intr_on = NULL;
16551475713Stsutsui 	ncr_sc->sc_intr_off = NULL;
1665cc459efSbjh21 
1675cc459efSbjh21 #ifdef NCR5380_USE_BUS_SPACE
16851475713Stsutsui 	ncr_sc->sc_regt = pa->pa_fast_t;
16951475713Stsutsui 	bus_space_map(ncr_sc->sc_regt,
17094769968Sbjh21 	    pa->pa_fast_base + HCSC_DP8490_OFFSET, 8, 0,
17151475713Stsutsui 	    &ncr_sc->sc_regh);
17251475713Stsutsui 	ncr_sc->sci_r0 = 0;
17351475713Stsutsui 	ncr_sc->sci_r1 = 1;
17451475713Stsutsui 	ncr_sc->sci_r2 = 2;
17551475713Stsutsui 	ncr_sc->sci_r3 = 3;
17651475713Stsutsui 	ncr_sc->sci_r4 = 4;
17751475713Stsutsui 	ncr_sc->sci_r5 = 5;
17851475713Stsutsui 	ncr_sc->sci_r6 = 6;
17951475713Stsutsui 	ncr_sc->sci_r7 = 7;
1805cc459efSbjh21 #else
18194769968Sbjh21 	iobase = (u_char *)pa->pa_fast_base + HCSC_DP8490_OFFSET;
18251475713Stsutsui 	ncr_sc->sci_r0 = iobase + 0;
18351475713Stsutsui 	ncr_sc->sci_r1 = iobase + 4;
18451475713Stsutsui 	ncr_sc->sci_r2 = iobase + 8;
18551475713Stsutsui 	ncr_sc->sci_r3 = iobase + 12;
18651475713Stsutsui 	ncr_sc->sci_r4 = iobase + 16;
18751475713Stsutsui 	ncr_sc->sci_r5 = iobase + 20;
18851475713Stsutsui 	ncr_sc->sci_r6 = iobase + 24;
18951475713Stsutsui 	ncr_sc->sci_r7 = iobase + 28;
1905cc459efSbjh21 #endif
191c5260261Sbjh21 	sc->sc_pdmat = pa->pa_mod_t;
19294769968Sbjh21 	bus_space_map(sc->sc_pdmat, pa->pa_mod_base + HCSC_PDMA_OFFSET, 1, 0,
19394769968Sbjh21 	    &sc->sc_pdmah);
1945cc459efSbjh21 
19551475713Stsutsui 	ncr_sc->sc_rev = NCR_VARIANT_DP8490;
1965cc459efSbjh21 
19751475713Stsutsui 	ncr_sc->sc_pio_in = hcsc_pdma_in;
19851475713Stsutsui 	ncr_sc->sc_pio_out = hcsc_pdma_out;
1995cc459efSbjh21 
2005cc459efSbjh21 	/* Provide an override for the host id */
20151475713Stsutsui 	ncr_sc->sc_channel.chan_id = 7;
202aca4c091Sitojun 	snprintf(hi_option, sizeof(hi_option), "%s.hostid",
20351475713Stsutsui 	    device_xname(self));
2045cc459efSbjh21 	(void)get_bootconf_option(boot_args, hi_option,
20551475713Stsutsui 	    BOOTOPT_TYPE_INT, &ncr_sc->sc_channel.chan_id);
20651475713Stsutsui 	ncr_sc->sc_adapter.adapt_minphys = minphys;
2075cc459efSbjh21 
20851475713Stsutsui 	aprint_normal(": host ID %d\n", ncr_sc->sc_channel.chan_id);
2095cc459efSbjh21 
2105cc459efSbjh21 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
21151475713Stsutsui 	    device_xname(self), "intr");
2125cc459efSbjh21 	sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, ncr5380_intr,
2135cc459efSbjh21 	    sc, &sc->sc_intrcnt);
2145cc459efSbjh21 
21551475713Stsutsui 	ncr5380_attach(ncr_sc);
2165cc459efSbjh21 }
217c5260261Sbjh21 
218c5260261Sbjh21 #ifndef HCSC_TSIZE_OUT
219c5260261Sbjh21 #define HCSC_TSIZE_OUT	512
220c5260261Sbjh21 #endif
221c5260261Sbjh21 
222c5260261Sbjh21 #ifndef HCSC_TSIZE_IN
223c5260261Sbjh21 #define HCSC_TSIZE_IN	512
224c5260261Sbjh21 #endif
225c5260261Sbjh21 
226c5260261Sbjh21 #define TIMEOUT 1000000
227c5260261Sbjh21 
22893124077Sperry static inline int
hcsc_ready(struct ncr5380_softc * sc)229c5260261Sbjh21 hcsc_ready(struct ncr5380_softc *sc)
230c5260261Sbjh21 {
231c5260261Sbjh21 	int i;
232c5260261Sbjh21 
233c5260261Sbjh21 	for (i = TIMEOUT; i > 0; i--) {
234c5260261Sbjh21 		if ((NCR5380_READ(sc,sci_csr) &
235c5260261Sbjh21 		    (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH)) ==
236c5260261Sbjh21 		    (SCI_CSR_DREQ | SCI_CSR_PHASE_MATCH))
23751475713Stsutsui 		    	return 1;
238c5260261Sbjh21 
239c5260261Sbjh21 		if ((NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 ||
240c5260261Sbjh21 		    SCI_BUSY(sc) == 0)
24151475713Stsutsui 			return 0;
242c5260261Sbjh21 	}
24351475713Stsutsui 	printf("%s: ready timeout\n", device_xname(sc->sc_dev));
24451475713Stsutsui 	return 0;
245c5260261Sbjh21 }
246c5260261Sbjh21 
247c5260261Sbjh21 
248c5260261Sbjh21 
249c5260261Sbjh21 /* Return zero on success. */
hcsc_wait_not_req(struct ncr5380_softc * sc)25093124077Sperry static inline void hcsc_wait_not_req(struct ncr5380_softc *sc)
251c5260261Sbjh21 {
252c5260261Sbjh21 	int timo;
25351475713Stsutsui 
254c5260261Sbjh21 	for (timo = TIMEOUT; timo; timo--) {
255c5260261Sbjh21 		if ((NCR5380_READ(sc, sci_bus_csr) & SCI_BUS_REQ) == 0 ||
256c5260261Sbjh21 		    (NCR5380_READ(sc, sci_csr) & SCI_CSR_PHASE_MATCH) == 0 ||
257c5260261Sbjh21 		    SCI_BUSY(sc) == 0) {
258c5260261Sbjh21 			return;
259c5260261Sbjh21 		}
260c5260261Sbjh21 	}
26151475713Stsutsui 	printf("%s: pdma not_req timeout\n", device_xname(sc->sc_dev));
262c5260261Sbjh21 }
263c5260261Sbjh21 
264c5260261Sbjh21 static int
hcsc_pdma_in(struct ncr5380_softc * ncr_sc,int phase,int datalen,uint8_t * data)265c5260261Sbjh21 hcsc_pdma_in(struct ncr5380_softc *ncr_sc, int phase, int datalen,
26651475713Stsutsui     uint8_t *data)
267c5260261Sbjh21 {
26851475713Stsutsui 	struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc;
269c5260261Sbjh21 	bus_space_tag_t pdmat = sc->sc_pdmat;
270c5260261Sbjh21 	bus_space_handle_t pdmah = sc->sc_pdmah;
271c5260261Sbjh21 	int s, resid, len;
272c5260261Sbjh21 
273c5260261Sbjh21 	s = splbio();
274c5260261Sbjh21 
275c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_mode,
276c5260261Sbjh21 	    NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA);
277c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_irecv, 0);
278c5260261Sbjh21 
279c5260261Sbjh21 	resid = datalen;
280c5260261Sbjh21 	while (resid > 0) {
281*d1579b2dSriastradh 		len = uimin(resid, HCSC_TSIZE_IN);
282c5260261Sbjh21 		if (hcsc_ready(ncr_sc) == 0)
283c5260261Sbjh21 			goto interrupt;
284c5260261Sbjh21 		bus_space_read_multi_1(pdmat, pdmah, 0, data, len);
285c5260261Sbjh21 		data += len;
286c5260261Sbjh21 		resid -= len;
287c5260261Sbjh21 	}
288c5260261Sbjh21 
289c5260261Sbjh21 	hcsc_wait_not_req(ncr_sc);
290c5260261Sbjh21 
291c5260261Sbjh21 interrupt:
292c5260261Sbjh21 	SCI_CLR_INTR(ncr_sc);
293c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_mode,
294c5260261Sbjh21 	    NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA);
295c5260261Sbjh21 	splx(s);
296c5260261Sbjh21 	return datalen - resid;
297c5260261Sbjh21 }
298c5260261Sbjh21 
299c5260261Sbjh21 static int
hcsc_pdma_out(struct ncr5380_softc * ncr_sc,int phase,int datalen,uint8_t * data)300c5260261Sbjh21 hcsc_pdma_out(struct ncr5380_softc *ncr_sc, int phase, int datalen,
30151475713Stsutsui     uint8_t *data)
302c5260261Sbjh21 {
30351475713Stsutsui 	struct hcsc_softc *sc = (struct hcsc_softc *)ncr_sc;
304c5260261Sbjh21 	bus_space_tag_t pdmat = sc->sc_pdmat;
305c5260261Sbjh21 	bus_space_handle_t pdmah = sc->sc_pdmah;
306c5260261Sbjh21 	int i, s, icmd, resid;
307c5260261Sbjh21 
308c5260261Sbjh21 	s = splbio();
309c5260261Sbjh21 	icmd = NCR5380_READ(ncr_sc, sci_icmd) & SCI_ICMD_RMASK;
310c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_icmd, icmd | SCI_ICMD_DATA);
311c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_mode,
312c5260261Sbjh21 	    NCR5380_READ(ncr_sc, sci_mode) | SCI_MODE_DMA);
313c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_dma_send, 0);
314c5260261Sbjh21 
315c5260261Sbjh21 	resid = datalen;
316c5260261Sbjh21 	if (hcsc_ready(ncr_sc) == 0)
317c5260261Sbjh21 		goto interrupt;
318c5260261Sbjh21 
319c5260261Sbjh21 	if (resid > HCSC_TSIZE_OUT) {
320c5260261Sbjh21 		/*
321c5260261Sbjh21 		 * Because of the chips DMA prefetch, phase changes
322c5260261Sbjh21 		 * etc, won't be detected until we have written at
323c5260261Sbjh21 		 * least one byte more. We pre-write 4 bytes so
324c5260261Sbjh21 		 * subsequent transfers will be aligned to a 4 byte
325c5260261Sbjh21 		 * boundary. Assuming disconects will only occur on
326c5260261Sbjh21 		 * block boundaries, we then correct for the pre-write
327c5260261Sbjh21 		 * when and if we get a phase change. If the chip had
328c5260261Sbjh21 		 * DMA byte counting hardware, the assumption would not
329c5260261Sbjh21 		 * be necessary.
330c5260261Sbjh21 		 */
331c5260261Sbjh21 		bus_space_write_multi_1(pdmat, pdmah, 0, data, 4);
332c5260261Sbjh21 		data += 4;
333c5260261Sbjh21 		resid -= 4;
334c5260261Sbjh21 
335c5260261Sbjh21 		for (; resid >= HCSC_TSIZE_OUT; resid -= HCSC_TSIZE_OUT) {
336c5260261Sbjh21 			if (hcsc_ready(ncr_sc) == 0) {
337c5260261Sbjh21 				resid += 4; /* Overshot */
338c5260261Sbjh21 				goto interrupt;
339c5260261Sbjh21 			}
340c5260261Sbjh21 			bus_space_write_multi_1(pdmat, pdmah, 0, data,
341c5260261Sbjh21 			    HCSC_TSIZE_OUT);
342c5260261Sbjh21 			data += HCSC_TSIZE_OUT;
343c5260261Sbjh21 		}
344c5260261Sbjh21 		if (hcsc_ready(ncr_sc) == 0) {
345c5260261Sbjh21 			resid += 4; /* Overshot */
346c5260261Sbjh21 			goto interrupt;
347c5260261Sbjh21 		}
348c5260261Sbjh21 	}
349c5260261Sbjh21 
350c5260261Sbjh21 	if (resid) {
351c5260261Sbjh21 		bus_space_write_multi_1(pdmat, pdmah, 0, data, resid);
352c5260261Sbjh21 		resid = 0;
353c5260261Sbjh21 	}
354c5260261Sbjh21 	for (i = TIMEOUT; i > 0; i--) {
355c5260261Sbjh21 		if ((NCR5380_READ(ncr_sc, sci_csr)
356c5260261Sbjh21 		    & (SCI_CSR_DREQ|SCI_CSR_PHASE_MATCH))
357c5260261Sbjh21 		    != SCI_CSR_DREQ)
358c5260261Sbjh21 			break;
359c5260261Sbjh21 	}
360c5260261Sbjh21 	if (i != 0)
361c5260261Sbjh21 		bus_space_write_1(pdmat, pdmah, 0, 0);
362c5260261Sbjh21 	else
363c5260261Sbjh21 		printf("%s: timeout waiting for final SCI_DSR_DREQ.\n",
36451475713Stsutsui 		    device_xname(ncr_sc->sc_dev));
365c5260261Sbjh21 
366c5260261Sbjh21 	hcsc_wait_not_req(ncr_sc);
367c5260261Sbjh21 interrupt:
368c5260261Sbjh21 	SCI_CLR_INTR(ncr_sc);
369c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_mode,
370c5260261Sbjh21 	    NCR5380_READ(ncr_sc, sci_mode) & ~SCI_MODE_DMA);
371c5260261Sbjh21 	NCR5380_WRITE(ncr_sc, sci_icmd, icmd);
372c5260261Sbjh21 	splx(s);
37351475713Stsutsui 	return datalen - resid;
374c5260261Sbjh21 }
375