ncr53c500.c revision 126928
1/*	$NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $	*/
2/*	$NetBSD$	*/
3
4#define	NCV_DEBUG
5#define	NCV_STATICS
6#define	NCV_IO_CONTROL_FLAGS	(0)
7
8/*
9 * [NetBSD for NEC PC-98 series]
10 *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
11 *	NetBSD/pc98 porting staff. All rights reserved.
12 *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
13 *	Naofumi HONDA. All rights reserved.
14 *
15 *  Redistribution and use in source and binary forms, with or without
16 *  modification, are permitted provided that the following conditions
17 *  are met:
18 *  1. Redistributions of source code must retain the above copyright
19 *     notice, this list of conditions and the following disclaimer.
20 *  2. Redistributions in binary form must reproduce the above copyright
21 *     notice, this list of conditions and the following disclaimer in the
22 *     documentation and/or other materials provided with the distribution.
23 *  3. The name of the author may not be used to endorse or promote products
24 *     derived from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/dev/ncv/ncr53c500.c 126928 2004-03-13 19:46:27Z peter $");
41#include "opt_ddb.h"
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
47#include <sys/bio.h>
48#endif	/* __FreeBSD__ */
49#include <sys/buf.h>
50#include <sys/queue.h>
51#include <sys/malloc.h>
52#include <sys/errno.h>
53
54#ifdef __NetBSD__
55#include <sys/device.h>
56#include <machine/bus.h>
57#include <machine/intr.h>
58
59#include <dev/scsipi/scsi_all.h>
60#include <dev/scsipi/scsipi_all.h>
61#include <dev/scsipi/scsiconf.h>
62#include <dev/scsipi/scsi_disk.h>
63
64#include <machine/dvcfg.h>
65#include <machine/physio_proc.h>
66
67#include <i386/Cbus/dev/scsi_low.h>
68
69#include <i386/Cbus/dev/ncr53c500reg.h>
70#include <i386/Cbus/dev/ncr53c500hw.h>
71#include <i386/Cbus/dev/ncr53c500var.h>
72
73#include <i386/Cbus/dev/ncr53c500hwtab.h>
74#endif /* __NetBSD__ */
75
76#ifdef __FreeBSD__
77#include <machine/clock.h>
78#include <machine/cpu.h>
79#include <machine/bus_pio.h>
80#include <machine/bus.h>
81
82#include <compat/netbsd/dvcfg.h>
83#include <compat/netbsd/physio_proc.h>
84
85#include <cam/scsi/scsi_low.h>
86
87#include <dev/ncv/ncr53c500reg.h>
88#include <dev/ncv/ncr53c500hw.h>
89#include <dev/ncv/ncr53c500var.h>
90
91#include <dev/ncv/ncr53c500hwtab.h>
92#endif /* __FreeBSD__ */
93
94#define	NCV_MAX_DATA_SIZE	(64 * 1024)
95#define	NCV_DELAY_MAX		(2 * 1000 * 1000)
96#define	NCV_DELAY_INTERVAL	(1)
97#define	NCV_PADDING_SIZE	(32)
98
99/***************************************************
100 * IO control
101 ***************************************************/
102#define	NCV_READ_INTERRUPTS_DRIVEN	0x0001
103#define	NCV_WRITE_INTERRUPTS_DRIVEN	0x0002
104#define	NCV_ENABLE_FAST_SCSI		0x0010
105#define	NCV_FAST_INTERRUPTS		0x0100
106
107u_int ncv_io_control = NCV_IO_CONTROL_FLAGS;
108int ncv_data_read_bytes = 4096;
109int ncv_data_write_bytes = 4096;
110
111/***************************************************
112 * DEBUG
113 ***************************************************/
114#ifdef	NCV_DEBUG
115static int ncv_debug;
116#endif	/* NCV_DEBUG */
117
118#ifdef	NCV_STATICS
119static struct ncv_statics {
120	int disconnect;
121	int reselect;
122} ncv_statics;
123#endif	/* NCV_STATICS */
124
125/***************************************************
126 * DEVICE STRUCTURE
127 ***************************************************/
128extern struct cfdriver ncv_cd;
129
130/**************************************************************
131 * DECLARE
132 **************************************************************/
133/* static */
134static void ncv_pio_read(struct ncv_softc *, u_int8_t *, u_int);
135static void ncv_pio_write(struct ncv_softc *, u_int8_t *, u_int);
136static int ncv_msg(struct ncv_softc *, struct targ_info *, u_int);
137static int ncv_reselected(struct ncv_softc *);
138static int ncv_disconnected(struct ncv_softc *, struct targ_info *);
139
140static __inline void ncvhw_set_count(bus_space_tag_t, bus_space_handle_t, int);
141static __inline u_int ncvhw_get_count(bus_space_tag_t, bus_space_handle_t);
142static __inline void ncvhw_select_register_0(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
143static __inline void ncvhw_select_register_1(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
144static __inline void ncvhw_fpush(bus_space_tag_t, bus_space_handle_t, u_int8_t *, int);
145
146static void ncv_pdma_end(struct ncv_softc *sc, struct targ_info *);
147static int ncv_world_start(struct ncv_softc *, int);
148static void ncvhw_bus_reset(struct ncv_softc *);
149static void ncvhw_reset(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
150static int ncvhw_check(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
151static void ncvhw_init(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *);
152static int ncvhw_start_selection(struct ncv_softc *sc, struct slccb *);
153static void ncvhw_attention(struct ncv_softc *);
154static int ncv_ccb_nexus_establish(struct ncv_softc *);
155static int ncv_lun_nexus_establish(struct ncv_softc *);
156static int ncv_target_nexus_establish(struct ncv_softc *);
157static int ncv_targ_init(struct ncv_softc *, struct targ_info *, int);
158static int ncv_catch_intr(struct ncv_softc *);
159#ifdef	NCV_POWER_CONTROL
160static int ncvhw_power(struct ncv_softc *, u_int);
161#endif	/* NCV_POWER_CONTROL */
162static __inline void ncv_setup_and_start_pio(struct ncv_softc *, u_int);
163
164struct scsi_low_funcs ncv_funcs = {
165	SC_LOW_INIT_T ncv_world_start,
166	SC_LOW_BUSRST_T ncvhw_bus_reset,
167	SC_LOW_TARG_INIT_T ncv_targ_init,
168	SC_LOW_LUN_INIT_T NULL,
169
170	SC_LOW_SELECT_T ncvhw_start_selection,
171	SC_LOW_NEXUS_T ncv_lun_nexus_establish,
172	SC_LOW_NEXUS_T ncv_ccb_nexus_establish,
173
174	SC_LOW_ATTEN_T ncvhw_attention,
175	SC_LOW_MSG_T ncv_msg,
176
177	SC_LOW_TIMEOUT_T NULL,
178	SC_LOW_POLL_T ncvintr,
179
180	NULL,	/* SC_LOW_POWER_T ncvhw_power, */
181};
182
183/**************************************************************
184 * hwfuncs
185 **************************************************************/
186static __inline void
187ncvhw_select_register_0(iot, ioh, hw)
188	bus_space_tag_t iot;
189	bus_space_handle_t ioh;
190	struct ncv_hw *hw;
191{
192
193	bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4);
194}
195
196static __inline void
197ncvhw_select_register_1(iot, ioh, hw)
198	bus_space_tag_t iot;
199	bus_space_handle_t ioh;
200	struct ncv_hw *hw;
201{
202
203	bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5);
204}
205
206static __inline void
207ncvhw_fpush(iot, ioh, buf, len)
208	bus_space_tag_t iot;
209	bus_space_handle_t ioh;
210	u_int8_t *buf;
211	int len;
212{
213	int ptr;
214
215	for (ptr = 0; ptr < len; ptr ++)
216		bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]);
217}
218
219static __inline void
220ncvhw_set_count(iot, ioh, count)
221	bus_space_tag_t iot;
222	bus_space_handle_t ioh;
223	int count;
224{
225
226	bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
227	bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
228	bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
229}
230
231static __inline u_int
232ncvhw_get_count(iot, ioh)
233	bus_space_tag_t iot;
234	bus_space_handle_t ioh;
235{
236	u_int count;
237
238	count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
239	count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
240	count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
241	return count;
242}
243
244static int
245ncvhw_check(iot, ioh, hw)
246	bus_space_tag_t iot;
247	bus_space_handle_t ioh;
248	struct ncv_hw *hw;
249{
250	u_int8_t stat;
251
252	ncvhw_select_register_0(iot, ioh, hw);
253	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
254	if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA))
255	{
256#ifdef	NCV_DEBUG
257		printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n");
258#endif	/* NCV_DEBUG */
259		return ENODEV;
260	}
261
262	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
263	if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP)
264	{
265#ifdef	NCV_DEBUG
266		printf("ncv: cr0_cmd CMD_NOP failed\n");
267#endif	/* NCV_DEBUG */
268		return ENODEV;
269	}
270
271	/* hardware reset */
272	ncvhw_reset(iot, ioh, hw);
273	ncvhw_init(iot, ioh, hw);
274
275	/* bus reset */
276	ncvhw_select_register_0(iot, ioh, hw);
277	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
278	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
279	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
280	SCSI_LOW_DELAY(100 * 1000);
281
282	/* check response */
283	bus_space_read_1(iot, ioh, cr0_stat);
284	stat = bus_space_read_1(iot, ioh, cr0_istat);
285	SCSI_LOW_DELAY(1000);
286
287	if (((stat & INTR_SBR) == 0) ||
288	    (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR))
289	{
290#ifdef	NCV_DEBUG
291		printf("ncv: cr0_istat SCSI BUS RESET failed\n");
292#endif	/* NCV_DEBUG */
293		return ENODEV;
294	}
295
296	return 0;
297}
298
299static void
300ncvhw_reset(iot, ioh, hw)
301	bus_space_tag_t iot;
302	bus_space_handle_t ioh;
303	struct ncv_hw *hw;
304{
305
306	ncvhw_select_register_0(iot, ioh, hw);
307
308	/* dummy cmd twice */
309	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
310	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
311
312	/* chip reset */
313	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP);
314
315	/* again dummy cmd twice */
316	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
317	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
318}
319
320static void
321ncvhw_init(iot, ioh, hw)
322	bus_space_tag_t iot;
323	bus_space_handle_t ioh;
324	struct ncv_hw *hw;
325{
326
327	ncvhw_select_register_0(iot, ioh, hw);
328	bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk);
329	bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT);
330	bus_space_write_1(iot, ioh, cr0_period, 0);
331	bus_space_write_1(iot, ioh, cr0_offs, 0);
332
333	bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1);
334	bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2);
335	bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3);
336	bus_space_write_1(iot, ioh, cr0_tchsb, 0);
337
338	ncvhw_select_register_1(iot, ioh, hw);
339	bus_space_write_1(iot, ioh, cr1_fstat, 0x0);
340	bus_space_write_1(iot, ioh, cr1_pflag, 0x0);
341	bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
342
343	ncvhw_select_register_0(iot, ioh, hw);
344}
345
346#ifdef	NCV_POWER_CONTROL
347static int
348ncvhw_power(sc, flags)
349	struct ncv_softc *sc;
350	u_int flags;
351{
352	struct scsi_low_softc *slp = &sc->sc_sclow;
353	bus_space_tag_t iot = sc->sc_iot;
354	bus_space_handle_t ioh = sc->sc_ioh;
355
356	if (flags == SCSI_LOW_POWDOWN)
357	{
358		printf("%s power down\n", slp->sl_xname);
359		ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
360		bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN);
361	}
362	else
363	{
364		switch (sc->sc_rstep)
365		{
366		case 0:
367			printf("%s resume step O\n", slp->sl_xname);
368			ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
369			bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
370			break;
371
372		case 1:
373			printf("%s resume step I\n", slp->sl_xname);
374			ncvhw_reset(iot, ioh, &sc->sc_hw);
375			ncvhw_init(iot, ioh, &sc->sc_hw);
376			break;
377		}
378	}
379
380	return 0;
381}
382#endif	/* NCV_POWER_CONTROL */
383
384/**************************************************************
385 * scsi low interface
386 **************************************************************/
387static void
388ncvhw_attention(sc)
389	struct ncv_softc *sc;
390{
391
392	bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN);
393	SCSI_LOW_DELAY(10);
394}
395
396static void
397ncvhw_bus_reset(sc)
398	struct ncv_softc *sc;
399{
400	bus_space_tag_t iot = sc->sc_iot;
401	bus_space_handle_t ioh = sc->sc_ioh;
402
403	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
404	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
405	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
406	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
407}
408
409static int
410ncvhw_start_selection(sc, cb)
411	struct ncv_softc *sc;
412	struct slccb *cb;
413{
414	struct scsi_low_softc *slp = &sc->sc_sclow;
415	bus_space_tag_t iot = sc->sc_iot;
416	bus_space_handle_t ioh = sc->sc_ioh;
417	struct targ_info *ti = cb->ti;
418	int s, len;
419	u_int flags;
420	u_int8_t cmd;
421
422	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
423	sc->sc_compseq = 0;
424	if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
425	{
426		cmd = CMD_SELATN;
427		sc->sc_selstop = 0;
428		flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
429	}
430	else if (scsi_low_is_msgout_continue(ti,
431			SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0)
432	{
433		cmd = CMD_SELATN3;
434		sc->sc_selstop = 0;
435		flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
436	}
437	else
438	{
439		cmd = CMD_SELATNS;
440		sc->sc_selstop = 1;
441		flags = SCSI_LOW_MSGOUT_INIT;
442	}
443
444	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
445	if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
446		return SCSI_LOW_START_FAIL;
447
448	ncv_target_nexus_establish(sc);
449
450	len = scsi_low_msgout(slp, ti, flags);
451	if (sc->sc_selstop == 0)
452		scsi_low_cmd(slp, ti);
453
454	s = splhigh();
455	if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0)
456	{
457		splx(s);
458		return SCSI_LOW_START_FAIL;
459	}
460
461	bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id);
462	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
463	ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
464	if (sc->sc_selstop == 0)
465	{
466		ncvhw_fpush(iot, ioh,
467			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
468	}
469	bus_space_write_1(iot, ioh, cr0_cmd, cmd);
470	splx(s);
471
472	SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
473	return SCSI_LOW_START_OK;
474}
475
476static int
477ncv_world_start(sc, fdone)
478	struct ncv_softc *sc;
479	int fdone;
480{
481	struct scsi_low_softc *slp = &sc->sc_sclow;
482	bus_space_tag_t iot = sc->sc_iot;
483	bus_space_handle_t ioh = sc->sc_ioh;
484	u_int8_t stat;
485
486	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
487		sc->sc_hw.hw_cfg1 |= C1_PARENB;
488	else
489		sc->sc_hw.hw_cfg1 &= ~C1_PARENB;
490
491	ncvhw_reset(iot, ioh, &sc->sc_hw);
492	ncvhw_init(iot, ioh, &sc->sc_hw);
493
494	scsi_low_bus_reset(slp);
495
496	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
497	bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat);
498	stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat);
499	SCSI_LOW_DELAY(1000);
500
501	if (((stat & INTR_SBR) == 0) ||
502	    (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR))
503		return ENODEV;
504
505	SOFT_INTR_REQUIRED(slp);
506	return 0;
507}
508
509static int
510ncv_msg(sc, ti, msg)
511	struct ncv_softc *sc;
512	struct targ_info *ti;
513	u_int msg;
514{
515	bus_space_tag_t iot = sc->sc_iot;
516	bus_space_handle_t ioh = sc->sc_ioh;
517	struct ncv_targ_info *nti = (void *) ti;
518	u_int hwcycle, period;
519
520	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
521	{
522		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
523		{
524			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
525			return EINVAL;
526		}
527		return 0;
528	}
529
530	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
531		return 0;
532
533	period = ti->ti_maxsynch.period;
534	hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk);
535	hwcycle = 1000 / hwcycle;
536
537	if (period < 200 / 4 && period >= 100 / 4)
538		nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi;
539	else
540		nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi;
541
542	period = ((period * 40 / hwcycle) + 5) / 10;
543	nti->nti_reg_period = period & 0x1f;
544	nti->nti_reg_offset = ti->ti_maxsynch.offset;
545
546	bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
547	bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
548	bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
549	return 0;
550}
551
552static int
553ncv_targ_init(sc, ti, action)
554	struct ncv_softc *sc;
555	struct targ_info *ti;
556	int action;
557{
558	struct ncv_targ_info *nti = (void *) ti;
559
560	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
561	{
562		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
563		ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod;
564		ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset;
565
566		nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3;
567		nti->nti_reg_period = 0;
568		nti->nti_reg_offset = 0;
569	}
570	return 0;
571}
572
573/**************************************************************
574 * General probe attach
575 **************************************************************/
576static int ncv_setup_img(struct ncv_hw *, u_int, int);
577
578static int
579ncv_setup_img(hw, dvcfg, hostid)
580	struct ncv_hw *hw;
581	u_int dvcfg;
582	int hostid;
583{
584
585	if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
586	{
587		printf("ncv: invalid dvcfg flags\n");
588		return EINVAL;
589	}
590
591	if (NCV_C5IMG(dvcfg) != 0)
592	{
593		hw->hw_cfg5 = NCV_C5IMG(dvcfg);
594		hw->hw_clk = NCV_CLKFACTOR(dvcfg);
595
596		if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 &&
597		    (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0)
598			hw->hw_mperiod = 100 / 4;
599
600		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
601			hw->hw_cfg3_fclk = 0x04;
602
603		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
604			hw->hw_cfg2 &= ~C2_SCSI2;
605
606		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
607			hw->hw_cfg1 |= C1_SLOW;
608	}
609
610	/* setup configuration image 3 */
611	if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F)
612		hw->hw_cfg3 &= ~hw->hw_cfg3_fclk;
613	else
614		hw->hw_cfg3 |= hw->hw_cfg3_fclk;
615
616	/* setup configuration image 1 */
617	hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid;
618	return 0;
619}
620
621int
622ncvprobesubr(iot, ioh, dvcfg, hsid)
623	bus_space_tag_t iot;
624	bus_space_handle_t ioh;
625	u_int dvcfg;
626	int hsid;
627{
628	struct ncv_hw hwtab;
629
630	hwtab = ncv_template;
631	if (ncv_setup_img(&hwtab, dvcfg, hsid))
632		return 0;
633	if (ncvhw_check(iot, ioh, &hwtab) != 0)
634		return 0;
635
636	return 1;
637}
638
639int
640ncvprint(aux, name)
641	void *aux;
642	const char *name;
643{
644
645	if (name != NULL)
646		printf("%s: scsibus ", name);
647	return UNCONF;
648}
649
650void
651ncvattachsubr(sc)
652	struct ncv_softc *sc;
653{
654	struct scsi_low_softc *slp = &sc->sc_sclow;
655
656	printf("\n");
657	sc->sc_hw = ncv_template;
658	ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
659	slp->sl_funcs = &ncv_funcs;
660	slp->sl_flags |= HW_READ_PADDING;
661	sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
662
663	(void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS,
664			       sizeof(struct ncv_targ_info), 0);
665}
666
667/**************************************************************
668 * PDMA
669 **************************************************************/
670static __inline void
671ncv_setup_and_start_pio(sc, reqlen)
672	struct ncv_softc *sc;
673	u_int reqlen;
674{
675	bus_space_tag_t iot = sc->sc_iot;
676	bus_space_handle_t ioh = sc->sc_ioh;
677
678	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
679	ncvhw_set_count(iot, ioh, reqlen);
680	bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
681
682	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
683	bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
684}
685
686static void
687ncv_pdma_end(sc, ti)
688	struct ncv_softc *sc;
689	struct targ_info *ti;
690{
691	struct scsi_low_softc *slp = &sc->sc_sclow;
692	bus_space_tag_t iot = sc->sc_iot;
693	bus_space_handle_t ioh = sc->sc_ioh;
694	int len;
695
696	slp->sl_flags &= ~HW_PDMASTART;
697	if (slp->sl_Qnexus == NULL)
698	{
699		slp->sl_error |= PDMAERR;
700		goto out;
701	}
702
703	if (ti->ti_phase == PH_DATA)
704	{
705		len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh);
706		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
707			len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
708				cr0_sffl) & CR0_SFFLR_BMASK);
709
710		if ((u_int) len <= (u_int) sc->sc_sdatalen)
711		{
712			if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
713			    sc->sc_tdatalen != len)
714				goto bad;
715
716			len = sc->sc_sdatalen - len;
717			if ((u_int) len > (u_int) slp->sl_scp.scp_datalen)
718				goto bad;
719
720			slp->sl_scp.scp_data += len;
721			slp->sl_scp.scp_datalen -= len;
722		}
723		else
724		{
725bad:
726			if ((slp->sl_error & PDMAERR) == 0)
727			{
728				printf("%s: stragne cnt hw 0x%x soft 0x%x\n",
729					slp->sl_xname, len,
730					slp->sl_scp.scp_datalen);
731			}
732			slp->sl_error |= PDMAERR;
733		}
734		scsi_low_data_finish(slp);
735	}
736	else
737	{
738		printf("%s: data phase miss\n", slp->sl_xname);
739		slp->sl_error |= PDMAERR;
740	}
741
742out:
743	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
744	bus_space_write_1(iot, ioh, cr1_fstat, 0);
745	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
746}
747
748static void
749ncv_pio_read(sc, buf, reqlen)
750	struct ncv_softc *sc;
751	u_int8_t *buf;
752	u_int reqlen;
753{
754	struct scsi_low_softc *slp = &sc->sc_sclow;
755	bus_space_tag_t iot = sc->sc_iot;
756	bus_space_handle_t ioh = sc->sc_ioh;
757	int tout;
758	register u_int8_t fstat;
759
760	ncv_setup_and_start_pio(sc, reqlen);
761	slp->sl_flags |= HW_PDMASTART;
762	sc->sc_sdatalen = reqlen;
763	tout = sc->sc_tmaxcnt;
764
765	while (reqlen >= FIFO_F_SZ && tout -- > 0)
766	{
767		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
768		if (fstat == (u_int8_t) -1)
769			goto out;
770		if (fstat & FIFO_F)
771		{
772#define	NCV_FAST32_ACCESS
773#ifdef	NCV_FAST32_ACCESS
774			bus_space_read_multi_4(iot, ioh, cr1_fdata,
775				(u_int32_t *) buf, FIFO_F_SZ / 4);
776#else	/* !NCV_FAST32_ACCESS */
777			bus_space_read_multi_2(iot, ioh, cr1_fdata,
778				(u_int16_t *) buf, FIFO_F_SZ / 2);
779#endif	/* !NCV_FAST32_ACCESS */
780			buf += FIFO_F_SZ;
781			reqlen -= FIFO_F_SZ;
782		}
783		else
784		{
785			if (fstat & FIFO_BRK)
786				break;
787
788			SCSI_LOW_DELAY(1);
789		}
790	}
791
792	while (reqlen > 0 && tout -- > 0)
793	{
794		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
795		if ((fstat & FIFO_E) == 0)
796		{
797			*buf++ = bus_space_read_1(iot, ioh, cr1_fdata);
798			reqlen --;
799		}
800		else
801		{
802			 if (fstat & FIFO_BRK)
803				break;
804
805			SCSI_LOW_DELAY(1);
806		}
807	}
808
809out:
810	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
811	sc->sc_tdatalen = reqlen;
812}
813
814static void
815ncv_pio_write(sc, buf, reqlen)
816	struct ncv_softc *sc;
817	u_int8_t *buf;
818	u_int reqlen;
819{
820	struct scsi_low_softc *slp = &sc->sc_sclow;
821	bus_space_tag_t iot = sc->sc_iot;
822	bus_space_handle_t ioh = sc->sc_ioh;
823	int tout;
824	register u_int8_t fstat;
825
826	ncv_setup_and_start_pio(sc, reqlen);
827	sc->sc_sdatalen = reqlen;
828	tout = sc->sc_tmaxcnt;
829	slp->sl_flags |= HW_PDMASTART;
830
831	while (reqlen >= FIFO_F_SZ && tout -- > 0)
832	{
833		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
834		if (fstat & FIFO_BRK)
835			goto done;
836
837		if ((fstat & FIFO_E) != 0)
838		{
839#ifdef	NCV_FAST32_ACCESS
840			bus_space_write_multi_4(iot, ioh, cr1_fdata,
841				(u_int32_t *) buf, FIFO_F_SZ / 4);
842#else	/* !NCV_FAST32_ACCESS */
843			bus_space_write_multi_2(iot, ioh, cr1_fdata,
844				(u_int16_t *) buf, FIFO_F_SZ / 2);
845#endif	/* !NCV_FAST32_ACCESS */
846			buf += FIFO_F_SZ;
847			reqlen -= FIFO_F_SZ;
848		}
849		else
850		{
851			SCSI_LOW_DELAY(1);
852		}
853	}
854
855	while (reqlen > 0 && tout -- > 0)
856	{
857		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
858		if (fstat & FIFO_BRK)
859			break;
860
861		if ((fstat & FIFO_F) == 0) /* fifo not full */
862		{
863			bus_space_write_1(iot, ioh, cr1_fdata, *buf++);
864			reqlen --;
865		}
866		else
867		{
868			SCSI_LOW_DELAY(1);
869		}
870	}
871
872done:
873	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
874}
875
876/**************************************************************
877 * disconnect & reselect (HW low)
878 **************************************************************/
879static int
880ncv_reselected(sc)
881	struct ncv_softc *sc;
882{
883	struct scsi_low_softc *slp = &sc->sc_sclow;
884	bus_space_tag_t iot = sc->sc_iot;
885	bus_space_handle_t ioh = sc->sc_ioh;
886	struct targ_info *ti;
887	u_int sid;
888
889	if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2)
890	{
891		printf("%s illegal fifo bytes\n", slp->sl_xname);
892		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused");
893		return EJUSTRETURN;
894	}
895
896	sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo);
897	sid &= ~(1 << slp->sl_hostid);
898	sid = ffs(sid) - 1;
899	ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
900	if (ti == NULL)
901		return EJUSTRETURN;
902
903#ifdef	NCV_STATICS
904	ncv_statics.reselect ++;
905#endif	/* NCV_STATICS */
906	bus_space_write_1(iot, ioh, cr0_dstid, sid);
907	return 0;
908}
909
910static int
911ncv_disconnected(sc, ti)
912	struct ncv_softc *sc;
913	struct targ_info *ti;
914{
915	struct scsi_low_softc *slp = &sc->sc_sclow;
916	bus_space_tag_t iot = sc->sc_iot;
917	bus_space_handle_t ioh = sc->sc_ioh;
918
919	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
920	bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL);
921
922#ifdef	NCV_STATICS
923	ncv_statics.disconnect ++;
924#endif	/* NCV_STATICS */
925
926	scsi_low_disconnected(slp, ti);
927	return 1;
928}
929
930/**************************************************************
931 * SEQUENCER
932 **************************************************************/
933static int
934ncv_target_nexus_establish(sc)
935	struct ncv_softc *sc;
936{
937	struct scsi_low_softc *slp = &sc->sc_sclow;
938	struct targ_info *ti = slp->sl_Tnexus;
939	struct ncv_targ_info *nti = (void *) ti;
940	bus_space_tag_t iot = sc->sc_iot;
941	bus_space_handle_t ioh = sc->sc_ioh;
942
943	bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
944	bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
945	bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
946	return 0;
947}
948
949static int
950ncv_lun_nexus_establish(sc)
951	struct ncv_softc *sc;
952{
953
954	return 0;
955}
956
957static int
958ncv_ccb_nexus_establish(sc)
959	struct ncv_softc *sc;
960{
961	struct scsi_low_softc *slp = &sc->sc_sclow;
962	struct slccb *cb = slp->sl_Qnexus;
963
964	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
965	return 0;
966}
967
968static int
969ncv_catch_intr(sc)
970	struct ncv_softc *sc;
971{
972	bus_space_tag_t iot = sc->sc_iot;
973	bus_space_handle_t ioh = sc->sc_ioh;
974	int wc;
975	register u_int8_t status;
976
977	for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++)
978	{
979		status = bus_space_read_1(iot, ioh, cr0_stat);
980		if ((status & STAT_INT) != 0)
981			return 0;
982
983		SCSI_LOW_DELAY(NCV_DELAY_INTERVAL);
984	}
985	return EJUSTRETURN;
986}
987
988int
989ncvintr(arg)
990	void *arg;
991{
992	struct ncv_softc *sc = arg;
993	struct scsi_low_softc *slp = &sc->sc_sclow;
994	bus_space_tag_t iot = sc->sc_iot;
995	bus_space_handle_t ioh = sc->sc_ioh;
996	struct targ_info *ti;
997	struct physio_proc *pp;
998	struct buf *bp;
999	u_int derror, flags;
1000	int len;
1001	u_int8_t regv, status, ireason;
1002
1003again:
1004	if (slp->sl_flags & HW_INACTIVE)
1005		return 0;
1006
1007	/********************************************
1008	 * Status
1009	 ********************************************/
1010	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
1011	status = bus_space_read_1(iot, ioh, cr0_stat);
1012	if ((status & STAT_INT) == 0 || status == (u_int8_t) -1)
1013		return 0;
1014
1015	ireason = bus_space_read_1(iot, ioh, cr0_istat);
1016	if ((ireason & INTR_SBR) != 0)
1017	{
1018		u_int8_t val;
1019
1020		/* avoid power off hangup */
1021		val = bus_space_read_1(iot, ioh, cr0_cfg1);
1022		bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR);
1023
1024		/* status init */
1025		scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
1026				 "bus reset (power off?)");
1027		return 1;
1028	}
1029
1030	/********************************************
1031	 * Debug section
1032	 ********************************************/
1033#ifdef	NCV_DEBUG
1034	if (ncv_debug)
1035	{
1036		scsi_low_print(slp, NULL);
1037		printf("%s st %x ist %x\n\n", slp->sl_xname,
1038			status, ireason);
1039#ifdef	DDB
1040		if (ncv_debug > 1)
1041			SCSI_LOW_DEBUGGER("ncv");
1042#endif	/* DDB */
1043	}
1044#endif	/* NCV_DEBUG */
1045
1046	/********************************************
1047	 * Reselect or Disconnect or Nexus check
1048	 ********************************************/
1049	/* (I) reselect */
1050	if (ireason == INTR_RESELECT)
1051	{
1052		if (ncv_reselected(sc) == EJUSTRETURN)
1053			return 1;
1054	}
1055
1056	/* (II) nexus */
1057	if ((ti = slp->sl_Tnexus) == NULL)
1058		return 0;
1059
1060	derror = 0;
1061	if ((status & (STAT_PE | STAT_GE)) != 0)
1062	{
1063		slp->sl_error |= PARITYERR;
1064		if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
1065			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
1066		else
1067			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
1068		derror = SCSI_LOW_DATA_PE;
1069	}
1070
1071	if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
1072	{
1073		if ((ireason & INTR_ILL) == 0)
1074			return ncv_disconnected(sc, ti);
1075
1076		slp->sl_error |= FATALIO;
1077		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd");
1078		return 1;
1079	}
1080
1081	/********************************************
1082	 * Internal scsi phase
1083	 ********************************************/
1084	switch (ti->ti_phase)
1085	{
1086	case PH_SELSTART:
1087		scsi_low_arbit_win(slp);
1088		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
1089
1090		if (sc->sc_selstop == 0)
1091		{
1092			/* XXX:
1093		 	 * Here scsi phases expected are
1094			 * DATA PHASE:
1095		 	 * MSGIN     : target wants to disconnect the host.
1096			 * STATUSIN  : immediate command completed.
1097			 * CMD PHASE : command out failed
1098			 * MSGOUT    : identify command failed.
1099			 */
1100			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1101				break;
1102		}
1103		else
1104		{
1105			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1106				break;
1107			if ((ireason & INTR_FC) != 0)
1108			{
1109				SCSI_LOW_ASSERT_ATN(slp);
1110			}
1111		}
1112		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1113		break;
1114
1115	case PH_RESEL:
1116		ncv_target_nexus_establish(sc);
1117		if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
1118		{
1119			printf("%s: unexpected phase after reselect\n",
1120				slp->sl_xname);
1121			slp->sl_error |= FATALIO;
1122			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1123			return 1;
1124		}
1125		break;
1126
1127	default:
1128		if ((slp->sl_flags & HW_PDMASTART) != 0)
1129		{
1130			ncv_pdma_end(sc, ti);
1131		}
1132		break;
1133	}
1134
1135	/********************************************
1136	 * Scsi phase sequencer
1137	 ********************************************/
1138	switch (status & PHASE_MASK)
1139	{
1140	case DATA_OUT_PHASE: /* data out */
1141		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1142		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
1143		{
1144			scsi_low_attention(slp);
1145		}
1146
1147		pp = physio_proc_enter(bp);
1148		if (slp->sl_scp.scp_datalen <= 0)
1149		{
1150			if ((ireason & INTR_BS) == 0)
1151				break;
1152
1153			if ((slp->sl_error & PDMAERR) == 0)
1154				printf("%s: data underrun\n", slp->sl_xname);
1155			slp->sl_error |= PDMAERR;
1156
1157			if ((slp->sl_flags & HW_WRITE_PADDING) != 0)
1158			{
1159				u_int8_t padding[NCV_PADDING_SIZE];
1160
1161				SCSI_LOW_BZERO(padding, sizeof(padding));
1162				ncv_pio_write(sc, padding, sizeof(padding));
1163			}
1164			else
1165			{
1166				printf("%s: write padding required\n",
1167					slp->sl_xname);
1168			}
1169		}
1170		else
1171		{
1172			len = slp->sl_scp.scp_datalen;
1173			if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0)
1174			{
1175				if (len > ncv_data_write_bytes)
1176					len = ncv_data_write_bytes;
1177			}
1178			ncv_pio_write(sc, slp->sl_scp.scp_data, len);
1179		}
1180		physio_proc_leave(pp);
1181		break;
1182
1183	case DATA_IN_PHASE: /* data in */
1184		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1185		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
1186		{
1187			scsi_low_attention(slp);
1188		}
1189
1190		pp = physio_proc_enter(bp);
1191		if (slp->sl_scp.scp_datalen <= 0)
1192		{
1193			if ((ireason & INTR_BS) == 0)
1194				break;
1195
1196			if ((slp->sl_error & PDMAERR) == 0)
1197				printf("%s: data overrun\n", slp->sl_xname);
1198			slp->sl_error |= PDMAERR;
1199
1200			if ((slp->sl_flags & HW_READ_PADDING) != 0)
1201			{
1202				u_int8_t padding[NCV_PADDING_SIZE];
1203
1204				ncv_pio_read(sc, padding, sizeof(padding));
1205			}
1206			else
1207			{
1208				printf("%s: read padding required\n",
1209					slp->sl_xname);
1210				break;
1211			}
1212		}
1213		else
1214		{
1215			len = slp->sl_scp.scp_datalen;
1216			if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0)
1217			{
1218				if (len > ncv_data_read_bytes)
1219					len = ncv_data_read_bytes;
1220			}
1221			ncv_pio_read(sc, slp->sl_scp.scp_data, len);
1222		}
1223		physio_proc_leave(pp);
1224		break;
1225
1226	case COMMAND_PHASE: /* cmd out */
1227		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
1228		if (scsi_low_cmd(slp, ti) != 0)
1229		{
1230			scsi_low_attention(slp);
1231		}
1232
1233		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1234		ncvhw_fpush(iot, ioh,
1235			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
1236		bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1237		break;
1238
1239	case STATUS_PHASE: /* status in */
1240		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
1241		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1242		bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS);
1243		sc->sc_compseq = 1;
1244		break;
1245
1246	default:
1247		break;
1248
1249	case MESSAGE_OUT_PHASE: /* msg out */
1250		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1251		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1252
1253		flags = SCSI_LOW_MSGOUT_UNIFY;
1254		if (ti->ti_ophase != ti->ti_phase)
1255			flags |= SCSI_LOW_MSGOUT_INIT;
1256		len = scsi_low_msgout(slp, ti, flags);
1257
1258		if (len > 1 && slp->sl_atten == 0)
1259		{
1260			scsi_low_attention(slp);
1261		}
1262
1263		ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
1264		bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1265		SCSI_LOW_DEASSERT_ATN(slp);
1266		break;
1267
1268	case MESSAGE_IN_PHASE: /* msg in */
1269		SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
1270
1271		len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK;
1272		if (sc->sc_compseq != 0)
1273		{
1274			sc->sc_compseq = 0;
1275			if ((ireason & INTR_FC) && len == 2)
1276			{
1277				regv = bus_space_read_1(iot, ioh, cr0_sfifo);
1278				scsi_low_statusin(slp, ti, regv | derror);
1279				len --;
1280			}
1281			else
1282			{
1283				slp->sl_error |= FATALIO;
1284				scsi_low_assert_msg(slp, ti,
1285						    SCSI_LOW_MSG_ABORT, 1);
1286				bus_space_write_1(sc->sc_iot, sc->sc_ioh,
1287						  cr0_cmd, CMD_MSGOK);
1288				break;
1289			}
1290		}
1291		else if (ireason & INTR_BS)
1292		{
1293			bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1294			bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1295			if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1296			{
1297				if (ncv_catch_intr(sc) == 0)
1298					goto again;
1299			}
1300			break;
1301		}
1302
1303		if ((ireason & INTR_FC) && len == 1)
1304		{
1305			regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1306					        cr0_sfifo);
1307			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
1308			{
1309				if (scsi_low_is_msgout_continue(ti, 0) != 0)
1310				{
1311					scsi_low_attention(slp);
1312				}
1313			}
1314			bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1315				CMD_MSGOK);
1316			if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
1317			{
1318				/* XXX:
1319				 * clear a pending interrupt and sync with
1320				 * a next interrupt!
1321				 */
1322				ncv_catch_intr(sc);
1323			}
1324		}
1325		else
1326		{
1327			slp->sl_error |= FATALIO;
1328			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1329			bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1330				CMD_MSGOK);
1331		}
1332		break;
1333	}
1334
1335	return 1;
1336}
1337