ncr53c500.c revision 73025
1/*	$FreeBSD: head/sys/dev/ncv/ncr53c500.c 73025 2001-02-25 12:40:30Z non $	*/
2/*	$NecBSD: ncr53c500.c,v 1.30 1999/07/23 21:00:04 honda Exp $	*/
3/*	$NetBSD$	*/
4
5#define	NCV_DEBUG
6#define	NCV_STATICS
7
8/*
9 * [NetBSD for NEC PC-98 series]
10 *  Copyright (c) 1995, 1996, 1997, 1998, 1999
11 *	NetBSD/pc98 porting staff. All rights reserved.
12 *  Copyright (c) 1995, 1996, 1997, 1998, 1999
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#include "opt_ddb.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/disklabel.h>
44#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
45#include <sys/bio.h>
46#endif
47#include <sys/buf.h>
48#include <sys/queue.h>
49#include <sys/malloc.h>
50#include <sys/device_port.h>
51#include <sys/errno.h>
52
53#include <vm/vm.h>
54
55#ifdef __NetBSD__
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#define delay(time) DELAY(time)
79
80#include <machine/cpu.h>
81#include <machine/bus_pio.h>
82#include <machine/bus.h>
83
84#include <machine/dvcfg.h>
85#include <machine/physio_proc.h>
86
87#include <cam/scsi/scsi_low.h>
88
89#include <dev/ncv/ncr53c500reg.h>
90#include <dev/ncv/ncr53c500hw.h>
91#include <dev/ncv/ncr53c500var.h>
92
93#include <dev/ncv/ncr53c500hwtab.h>
94
95#if __FreeBSD_version < 400001
96#include "ncv.h"
97struct ncv_softc *ncvdata[NNCV];
98#endif
99#endif /* __FreeBSD__ */
100
101/***************************************************
102 * DEBUG
103 ***************************************************/
104#ifndef DDB
105#define Debugger() panic("should call debugger here (ncr53c500.c)")
106#else /* ! DDB */
107#ifdef __FreeBSD__
108#define Debugger() Debugger("ncv")
109#endif /* __FreeBSD__ */
110#endif
111
112#ifdef	NCV_DEBUG
113int ncv_debug;
114#endif	/* NCV_DEBUG */
115
116#ifdef	NCV_STATICS
117struct ncv_statics {
118	int disconnect;
119	int reselect;
120} ncv_statics[NCV_NTARGETS];
121#endif	/* NCV_STATICS */
122
123/***************************************************
124 * ISA DEVICE STRUCTURE
125 ***************************************************/
126extern struct cfdriver ncv_cd;
127
128/**************************************************************
129 * DECLARE
130 **************************************************************/
131#ifdef __NetBSD__
132extern int delaycount;
133#endif
134
135/* static */
136static void ncv_pio_read __P((struct ncv_softc *, u_int8_t *, u_int));
137static void ncv_pio_write __P((struct ncv_softc *, u_int8_t *, u_int));
138static int ncv_msg __P((struct ncv_softc *, struct targ_info *, u_int));
139static __inline int ncv_reselected __P((struct ncv_softc *));
140static __inline int ncv_disconnected __P((struct ncv_softc *, struct targ_info *));
141static __inline void ncv_pdma_end __P((struct ncv_softc *sc, struct targ_info *));
142
143static __inline void ncvhw_set_count __P((bus_space_tag_t, bus_space_handle_t, int));
144static __inline u_int ncvhw_get_count __P((bus_space_tag_t, bus_space_handle_t));
145static __inline void ncvhw_select_register_0 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
146static __inline void ncvhw_select_register_1 __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
147static __inline void ncvhw_fpush __P((bus_space_tag_t, bus_space_handle_t, u_int8_t *, int));
148
149static int ncv_world_start __P((struct ncv_softc *, int));
150static void ncvhw_bus_reset __P((struct ncv_softc *));
151static void ncvhw_reset __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
152static int ncvhw_check __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
153static void ncvhw_init __P((bus_space_tag_t, bus_space_handle_t, struct ncv_hw *));
154static int ncvhw_start_selection __P((struct ncv_softc *sc, struct slccb *));
155static void ncvhw_attention __P((struct ncv_softc *));
156static int ncv_nexus __P((struct ncv_softc *, struct targ_info *));
157#ifdef	NCV_POWER_CONTROL
158static int ncvhw_power __P((struct ncv_softc *, u_int));
159#endif
160static int ncv_targ_init __P((struct ncv_softc *, struct targ_info *));
161
162struct scsi_low_funcs ncv_funcs = {
163	SC_LOW_INIT_T ncv_world_start,
164	SC_LOW_BUSRST_T ncvhw_bus_reset,
165	SC_LOW_TARG_INIT_T ncv_targ_init,
166
167	SC_LOW_SELECT_T ncvhw_start_selection,
168	SC_LOW_NEXUS_T ncv_nexus,
169
170	SC_LOW_ATTEN_T ncvhw_attention,
171	SC_LOW_MSG_T ncv_msg,
172
173	SC_LOW_POLL_T ncvintr,
174
175	NULL,	/* SC_LOW_POWER_T ncvhw_power, */
176};
177
178/**************************************************************
179 * hwfuncs
180 **************************************************************/
181static __inline void
182ncvhw_select_register_0(iot, ioh, hw)
183	bus_space_tag_t iot;
184	bus_space_handle_t ioh;
185	struct ncv_hw *hw;
186{
187
188	bus_space_write_1(iot, ioh, cr0_cfg4, hw->cfg4);
189}
190
191static __inline void
192ncvhw_select_register_1(iot, ioh, hw)
193	bus_space_tag_t iot;
194	bus_space_handle_t ioh;
195	struct ncv_hw *hw;
196{
197
198	bus_space_write_1(iot, ioh, cr1_cfg5, hw->cfg5);
199}
200
201static __inline void
202ncvhw_fpush(iot, ioh, buf, len)
203	bus_space_tag_t iot;
204	bus_space_handle_t ioh;
205	u_int8_t *buf;
206	int len;
207{
208	int ptr;
209
210	for (ptr = 0; ptr < len; ptr ++)
211		bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]);
212}
213
214static int
215ncvhw_check(iot, ioh, hw)
216	bus_space_tag_t iot;
217	bus_space_handle_t ioh;
218	struct ncv_hw *hw;
219{
220	u_int8_t stat;
221
222	ncvhw_select_register_0(iot, ioh, hw);
223	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
224	if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA))
225	{
226#ifdef	NCV_DEBUG
227		printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n");
228#endif	/* NCV_DEBUG */
229		return ENODEV;
230	}
231
232	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
233	if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP)
234	{
235#ifdef	NCV_DEBUG
236		printf("ncv: cr0_cmd CMD_NOP failed\n");
237#endif	/* NCV_DEBUG */
238		return ENODEV;
239	}
240
241	/* hardware reset */
242	ncvhw_reset(iot, ioh, hw);
243	ncvhw_init(iot, ioh, hw);
244
245	/* bus reset */
246	ncvhw_select_register_0(iot, ioh, hw);
247	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
248	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
249	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
250	delay(100 * 1000);
251
252	/* check response */
253	bus_space_read_1(iot, ioh, cr0_stat);
254	stat = bus_space_read_1(iot, ioh, cr0_istat);
255	delay(1000);
256
257	if (((stat & INTR_SBR) == 0) ||
258	    (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR))
259	{
260#ifdef	NCV_DEBUG
261		printf("ncv: cr0_istat SCSI BUS RESET failed\n");
262#endif	/* NCV_DEBUG */
263		return ENODEV;
264	}
265
266	return 0;
267}
268
269static void
270ncvhw_reset(iot, ioh, hw)
271	bus_space_tag_t iot;
272	bus_space_handle_t ioh;
273	struct ncv_hw *hw;
274{
275
276	ncvhw_select_register_0(iot, ioh, hw);
277
278	/* dummy cmd twice */
279	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
280	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
281
282	/* chip reset */
283	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP);
284
285	/* again dummy cmd twice */
286	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
287	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP);
288}
289
290static void
291ncvhw_init(iot, ioh, hw)
292	bus_space_tag_t iot;
293	bus_space_handle_t ioh;
294	struct ncv_hw *hw;
295{
296
297	ncvhw_select_register_0(iot, ioh, hw);
298	bus_space_write_1(iot, ioh, cr0_clk, hw->clk);
299	bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT);
300	bus_space_write_1(iot, ioh, cr0_period, 0);
301	bus_space_write_1(iot, ioh, cr0_offs, 0);
302
303	bus_space_write_1(iot, ioh, cr0_cfg1, hw->cfg1);
304	bus_space_write_1(iot, ioh, cr0_cfg2, hw->cfg2);
305	bus_space_write_1(iot, ioh, cr0_cfg3, hw->cfg3);
306	bus_space_write_1(iot, ioh, cr0_tchsb, 0);
307
308	ncvhw_select_register_1(iot, ioh, hw);
309	bus_space_write_1(iot, ioh, cr1_fstat, 0x0);
310	bus_space_write_1(iot, ioh, cr1_pflag, 0x0);
311	bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
312
313	ncvhw_select_register_0(iot, ioh, hw);
314}
315
316#ifdef	NCV_POWER_CONTROL
317static int
318ncvhw_power(sc, flags)
319	struct ncv_softc *sc;
320	u_int flags;
321{
322	struct scsi_low_softc *slp = &sc->sc_sclow;
323	bus_space_tag_t iot = sc->sc_iot;
324	bus_space_handle_t ioh = sc->sc_ioh;
325
326	if (flags == SCSI_LOW_POWDOWN)
327	{
328		printf("%s power down\n", slp->sl_xname);
329		ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
330		bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN);
331	}
332	else
333	{
334		switch (sc->sc_rstep)
335		{
336		case 0:
337			printf("%s resume step O\n", slp->sl_xname);
338			ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
339			bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE);
340			break;
341
342		case 1:
343			printf("%s resume step I\n", slp->sl_xname);
344			ncvhw_reset(iot, ioh, &sc->sc_hw);
345			ncvhw_init(iot, ioh, &sc->sc_hw);
346			break;
347		}
348	}
349
350	return 0;
351}
352#endif	/* NCV_POWER_CONTROL */
353
354/**************************************************************
355 * scsi low interface
356 **************************************************************/
357static void
358ncvhw_attention(sc)
359	struct ncv_softc *sc;
360{
361
362	bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN);
363	delay(10);
364}
365
366static void
367ncvhw_bus_reset(sc)
368	struct ncv_softc *sc;
369{
370	bus_space_tag_t iot = sc->sc_iot;
371	bus_space_handle_t ioh = sc->sc_ioh;
372
373	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
374	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
375	bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI);
376	bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA);
377}
378
379static int
380ncvhw_start_selection(sc, cb)
381	struct ncv_softc *sc;
382	struct slccb *cb;
383{
384	struct scsi_low_softc *slp = &sc->sc_sclow;
385	bus_space_tag_t iot = sc->sc_iot;
386	bus_space_handle_t ioh = sc->sc_ioh;
387	struct targ_info *ti = cb->ti;
388	int s;
389	u_int8_t msg;
390
391	msg = ID_MSG_SETUP(ti);
392	sc->sc_compseq = 0;
393	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
394
395	s = splhigh();
396
397	if (slp->sl_disc > 0 &&
398	    (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat) & STAT_INT))
399	{
400		splx(s);
401		return SCSI_LOW_START_FAIL;
402	}
403
404	bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id);
405	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
406	bus_space_write_1(iot, ioh, cr0_sfifo, msg);
407
408	if (scsi_low_is_msgout_continue(ti) != 0)
409	{
410		bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATNS);
411		sc->sc_selstop = 1;
412	}
413	else
414	{
415		/* XXX:
416		 * emulate nexus call because ncv bypasses CMD phase.
417		 */
418		scsi_low_cmd(slp, ti);
419		ncvhw_fpush(iot, ioh,
420			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
421		bus_space_write_1(iot, ioh, cr0_cmd, CMD_SELATN);
422		sc->sc_selstop = 0;
423	}
424	splx(s);
425
426	SCSI_LOW_TARGET_ASSERT_ATN(ti);
427	SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
428	return SCSI_LOW_START_OK;
429}
430
431static int
432ncv_world_start(sc, fdone)
433	struct ncv_softc *sc;
434	int fdone;
435{
436	struct scsi_low_softc *slp = &sc->sc_sclow;
437	bus_space_tag_t iot = sc->sc_iot;
438	bus_space_handle_t ioh = sc->sc_ioh;
439	u_int8_t stat;
440#ifdef __FreeBSD__
441	intrmask_t s;
442#endif
443
444	ncvhw_reset(iot, ioh, &sc->sc_hw);
445	ncvhw_init(iot, ioh, &sc->sc_hw);
446
447#ifdef __FreeBSD__
448	s = splcam();
449#endif
450	scsi_low_bus_reset(slp);
451
452	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
453	bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat);
454	stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat);
455#ifdef __FreeBSD__
456	splx(s);
457#endif
458	delay(1000);
459
460	if (((stat & INTR_SBR) == 0) ||
461	    (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR))
462		return ENODEV;
463
464	SOFT_INTR_REQUIRED(slp);
465	return 0;
466}
467
468static int
469ncv_msg(sc, ti, msg)
470	struct ncv_softc *sc;
471	struct targ_info *ti;
472	u_int msg;
473{
474	struct ncv_targ_info *nti = (void *) ti;
475	u_int hwcycle, period;
476
477	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
478		return 0;
479
480	period = ti->ti_maxsynch.period;
481	hwcycle = 1000 / ((sc->sc_hw.clk == 0) ? 40 : (5 * sc->sc_hw.clk));
482
483	if (period < 200 / 4 && period >= 100 / 4)
484		nti->nti_reg_cfg3 |= C3_FSCSI;
485	else
486		nti->nti_reg_cfg3 &= ~C3_FSCSI;
487
488	period = ((period * 40 / hwcycle) + 5) / 10;
489	nti->nti_reg_period = period & 0x1f;
490	nti->nti_reg_offset = ti->ti_maxsynch.offset;
491	return 0;
492}
493
494static int
495ncv_targ_init(sc, ti)
496	struct ncv_softc *sc;
497	struct targ_info *ti;
498{
499	struct ncv_targ_info *nti = (void *) ti;
500
501	ti->ti_maxsynch.period = sc->sc_hw.mperiod;
502	ti->ti_maxsynch.offset = sc->sc_hw.moffset;
503
504	nti->nti_reg_cfg3 = sc->sc_hw.cfg3;
505	nti->nti_reg_period = 0;
506	nti->nti_reg_offset = 0;
507	return 0;
508}
509
510/**************************************************************
511 * General probe attach
512 **************************************************************/
513static int ncv_setup_img __P((struct ncv_hw *, u_int, int));
514
515static int
516ncv_setup_img(hw, dvcfg, hsid)
517	struct ncv_hw *hw;
518	u_int dvcfg;
519	int hsid;
520{
521
522	if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
523	{
524		printf("ncv: invalid dvcfg flags\n");
525		return EINVAL;
526	}
527
528	if (NCV_C5IMG(dvcfg) != 0)
529	{
530		hw->cfg5 = NCV_C5IMG(dvcfg);
531		hw->clk = NCV_CLKFACTOR(dvcfg);
532
533		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M)
534			hw->mperiod = 100 / 4;
535
536		/* XXX:
537		 * RATOC scsi cards have fatal fifo asic bug.
538		 * To avoid it, currently make sync offset 0 (async)!
539		 */
540		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
541		{
542			hw->mperiod = 0;
543			hw->moffset = 0;
544		}
545
546		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
547			hw->cfg2 &= ~C2_SCSI2;
548
549		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
550			hw->cfg1 |= C1_SLOW;
551	}
552
553	/* setup configuration image 3 */
554	if (hw->clk != CLK_40M_F && hw->clk <= CLK_25M_F)
555		hw->cfg3 &= ~C3_FCLK;
556
557	/* setup configuration image 1 */
558	hw->cfg1 = (hw->cfg1 & 0xf0) | hsid;
559	return 0;
560}
561
562int
563ncvprobesubr(iot, ioh, dvcfg, hsid)
564	bus_space_tag_t iot;
565	bus_space_handle_t ioh;
566	u_int dvcfg;
567	int hsid;
568{
569	struct ncv_hw hwtab;
570
571	hwtab = ncv_template;
572	if (ncv_setup_img(&hwtab, dvcfg, hsid))
573		return 0;
574	if (ncvhw_check(iot, ioh, &hwtab) != 0)
575		return 0;
576
577	return 1;
578}
579
580int
581ncvprint(aux, name)
582	void *aux;
583	const char *name;
584{
585
586	if (name != NULL)
587		printf("%s: scsibus ", name);
588	return UNCONF;
589}
590
591void
592ncvattachsubr(sc)
593	struct ncv_softc *sc;
594{
595	struct scsi_low_softc *slp = &sc->sc_sclow;
596
597	printf("\n");
598	sc->sc_hw = ncv_template;
599	ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
600#ifdef __FreeBSD__
601	sc->sc_wc = 0x2000 * 2000;	/* XXX need calibration */
602#else /* NetBSD */
603	sc->sc_wc = delaycount * 2000;	/* 2 sec */
604#endif
605	slp->sl_funcs = &ncv_funcs;
606	(void) scsi_low_attach(slp, 2, NCV_NTARGETS, NCV_NLUNS,
607			       sizeof(struct ncv_targ_info));
608}
609
610/**************************************************************
611 * PDMA
612 **************************************************************/
613static __inline void
614ncvhw_set_count(iot, ioh, count)
615	bus_space_tag_t iot;
616	bus_space_handle_t ioh;
617	int count;
618{
619
620	bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count);
621	bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY));
622	bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
623}
624
625static __inline u_int
626ncvhw_get_count(iot, ioh)
627	bus_space_tag_t iot;
628	bus_space_handle_t ioh;
629{
630	u_int count;
631
632	count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb);
633	count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY;
634	count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2);
635	return count;
636}
637
638static __inline void
639ncv_pdma_end(sc, ti)
640	struct ncv_softc *sc;
641	struct targ_info *ti;
642{
643	struct scsi_low_softc *slp = &sc->sc_sclow;
644	bus_space_tag_t iot = sc->sc_iot;
645	bus_space_handle_t ioh = sc->sc_ioh;
646	int len;
647
648	slp->sl_flags &= ~HW_PDMASTART;
649	if (ti->ti_phase == PH_DATA)
650	{
651		len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh);
652		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
653			len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
654				cr0_sffl) & CR0_SFFLR_BMASK);
655
656		if ((u_int) len <= (u_int) slp->sl_scp.scp_datalen)
657		{
658			slp->sl_scp.scp_data += (slp->sl_scp.scp_datalen - len);
659			slp->sl_scp.scp_datalen = len;
660			if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
661			    sc->sc_tdatalen != len)
662				goto bad;
663		}
664		else
665		{
666bad:
667			slp->sl_error |= PDMAERR;
668			printf("%s stragne count hw 0x%x soft 0x%x tlen 0x%x\n",
669				slp->sl_xname, len, slp->sl_scp.scp_datalen,
670				sc->sc_tdatalen);
671		}
672	}
673	else
674	{
675		printf("%s data phase miss\n", slp->sl_xname);
676		slp->sl_error |= PDMAERR;
677	}
678
679	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
680	bus_space_write_1(iot, ioh, cr1_fstat, 0);
681	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
682}
683
684static void
685ncv_pio_read(sc, buf, reqlen)
686	struct ncv_softc *sc;
687	u_int8_t *buf;
688	u_int reqlen;
689{
690	struct scsi_low_softc *slp = &sc->sc_sclow;
691	bus_space_tag_t iot = sc->sc_iot;
692	bus_space_handle_t ioh = sc->sc_ioh;
693	int tout = sc->sc_wc;
694	register u_int8_t fstat;
695
696	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
697	bus_space_write_1(iot, ioh, cr1_pflag, 0);
698
699	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
700	ncvhw_set_count(iot, ioh, reqlen);
701	bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
702
703	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
704	bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
705	slp->sl_flags |= HW_PDMASTART;
706
707	while (reqlen >= FIFO_F_SZ && tout > 0)
708	{
709		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
710		if (fstat & FIFO_F)
711		{
712#define	NCV_FAST32_ACCESS
713#ifdef	NCV_FAST32_ACCESS
714			bus_space_read_multi_4(iot, ioh, cr1_fdata,
715				(u_int32_t *) buf, FIFO_F_SZ / 4);
716#else	/* !NCV_FAST32_ACCESS */
717			bus_space_read_multi_2(iot, ioh, cr1_fdata,
718				(u_int16_t *) buf, FIFO_F_SZ / 2);
719#endif	/* !NCV_FAST32_ACCESS */
720			buf += FIFO_F_SZ;
721			reqlen -= FIFO_F_SZ;
722			continue;
723		}
724		else if (fstat & FIFO_BRK)
725			break;
726
727		tout --;
728	}
729
730	if (reqlen >= FIFO_2_SZ)
731	{
732		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
733		if (fstat & FIFO_2)
734		{
735#ifdef	NCV_FAST32_ACCESS
736			bus_space_read_multi_4(iot, ioh, cr1_fdata,
737				(u_int32_t *) buf, FIFO_2_SZ / 4);
738#else	/* !NCV_FAST32_ACCESS */
739			bus_space_read_multi_2(iot, ioh, cr1_fdata,
740				(u_int16_t *) buf, FIFO_2_SZ / 2);
741#endif	/* !NCV_FAST32_ACCESS */
742			buf += FIFO_2_SZ;
743			reqlen -= FIFO_2_SZ;
744		}
745	}
746
747	while (reqlen > 0 && tout > 0)
748	{
749		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
750		if ((fstat & FIFO_E) == 0)
751		{
752			*buf++ = bus_space_read_1(iot, ioh, cr1_fdata);
753			reqlen --;
754			continue;
755		}
756		else if (fstat & FIFO_BRK)
757			break;
758
759		tout --;
760	}
761
762	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
763	sc->sc_tdatalen = reqlen;
764
765	if (tout <= 0)
766		printf("%s pio read timeout\n", slp->sl_xname);
767}
768
769static void
770ncv_pio_write(sc, buf, reqlen)
771	struct ncv_softc *sc;
772	u_int8_t *buf;
773	u_int reqlen;
774{
775	struct scsi_low_softc *slp = &sc->sc_sclow;
776	bus_space_tag_t iot = sc->sc_iot;
777	bus_space_handle_t ioh = sc->sc_ioh;
778	int tout = sc->sc_wc;
779	register u_int8_t fstat;
780
781	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
782	bus_space_write_1(iot, ioh, cr1_pflag, 0);
783
784	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
785	ncvhw_set_count(iot, ioh, reqlen);
786	bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA);
787
788	ncvhw_select_register_1(iot, ioh, &sc->sc_hw);
789	bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN);
790	slp->sl_flags |= HW_PDMASTART;
791
792	while (reqlen >= FIFO_F_SZ && tout > 0)
793	{
794		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
795		if (fstat & FIFO_BRK)
796			goto done;
797
798		if (fstat & FIFO_E)
799		{
800#ifdef	NCV_FAST32_ACCESS
801			bus_space_write_multi_4(iot, ioh, cr1_fdata,
802				(u_int32_t *) buf, FIFO_F_SZ / 4);
803#else	/* !NCV_FAST32_ACCESS */
804			bus_space_write_multi_2(iot, ioh, cr1_fdata,
805				(u_int16_t *) buf, FIFO_F_SZ / 2);
806#endif	/* !NCV_FAST32_ACCESS */
807			buf += FIFO_F_SZ;
808			reqlen -= FIFO_F_SZ;
809		}
810		else
811			tout --;
812	}
813
814	while (reqlen > 0 && tout > 0)
815	{
816		fstat = bus_space_read_1(iot, ioh, cr1_fstat);
817		if (fstat & FIFO_BRK)
818			break;
819
820		if ((fstat & FIFO_F) == 0) /* fifo not full */
821		{
822			bus_space_write_1(iot, ioh, cr1_fdata, *buf++);
823			reqlen --;
824		}
825		else
826			tout --;
827	}
828
829done:
830	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
831
832	if (tout <= 0)
833		printf("%s pio write timeout\n", slp->sl_xname);
834}
835
836/**************************************************************
837 * disconnect & reselect (HW low)
838 **************************************************************/
839static __inline int
840ncv_reselected(sc)
841	struct ncv_softc *sc;
842{
843	struct scsi_low_softc *slp = &sc->sc_sclow;
844	bus_space_tag_t iot = sc->sc_iot;
845	bus_space_handle_t ioh = sc->sc_ioh;
846	struct targ_info *ti;
847	u_int sid;
848
849	if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2)
850	{
851		printf("%s illegal fifo bytes\n", slp->sl_xname);
852		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused");
853		return EJUSTRETURN;
854	}
855
856	sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo);
857	sid = ffs(sid) - 1;
858	ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
859	if (ti == NULL)
860		return EJUSTRETURN;
861
862#ifdef	NCV_STATICS
863	ncv_statics[sid].reselect ++;
864#endif	/* NCV_STATICS */
865	bus_space_write_1(iot, ioh, cr0_dstid, sid);
866	return 0;
867}
868
869static __inline int
870ncv_disconnected(sc, ti)
871	struct ncv_softc *sc;
872	struct targ_info *ti;
873{
874	struct scsi_low_softc *slp = &sc->sc_sclow;
875	bus_space_tag_t iot = sc->sc_iot;
876	bus_space_handle_t ioh = sc->sc_ioh;
877
878	bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
879	bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1);
880	bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL);
881
882#ifdef	NCV_STATICS
883	if (slp->sl_msgphase == MSGPH_DISC)
884		ncv_statics[ti->ti_id].disconnect ++;
885#endif	/* NCV_STATICS */
886
887	scsi_low_disconnected(slp, ti);
888	return 1;
889}
890
891/**************************************************************
892 * SEQUENCER
893 **************************************************************/
894static int
895ncv_nexus(sc, ti)
896	struct ncv_softc *sc;
897	struct targ_info *ti;
898{
899	bus_space_tag_t iot = sc->sc_iot;
900	bus_space_handle_t ioh = sc->sc_ioh;
901	struct lun_info *li = ti->ti_li;
902	struct ncv_targ_info *nti = (void *) ti;
903
904	if (li->li_flags & SCSI_LOW_NOPARITY)
905		bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1);
906	else
907		bus_space_write_1(iot, ioh, cr0_cfg1, sc->sc_hw.cfg1 | C1_PARENB);
908	bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period);
909	bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset);
910	bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3);
911	return 0;
912}
913
914int
915ncvintr(arg)
916	void *arg;
917{
918	struct ncv_softc *sc = arg;
919	struct scsi_low_softc *slp = &sc->sc_sclow;
920	bus_space_tag_t iot = sc->sc_iot;
921	bus_space_handle_t ioh = sc->sc_ioh;
922	struct targ_info *ti;
923	struct physio_proc *pp;
924	struct buf *bp;
925	int len, identify;
926	u_int8_t regv, status, ireason;
927
928	if (slp->sl_flags & HW_INACTIVE)
929		return 0;
930
931	/********************************************
932	 * Status
933	 ********************************************/
934	ncvhw_select_register_0(iot, ioh, &sc->sc_hw);
935	status = bus_space_read_1(iot, ioh, cr0_stat);
936	if ((status & STAT_INT) == 0)
937		return 0;
938
939	ireason = bus_space_read_1(iot, ioh, cr0_istat);
940	if (ireason & INTR_SBR)
941	{
942		u_int8_t val;
943
944		/* avoid power off hangup */
945		val = bus_space_read_1(iot, ioh, cr0_cfg1);
946		bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR);
947
948		/* status init */
949		scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
950				 "bus reset (power off?)");
951		return 1;
952	}
953
954	/********************************************
955	 * Debug section
956	 ********************************************/
957#ifdef	NCV_DEBUG
958	if (ncv_debug)
959	{
960		scsi_low_print(slp, NULL);
961		printf("%s st %x ist %x\n\n", slp->sl_xname,
962			status, ireason);
963		if (ncv_debug > 1)
964			Debugger();
965	}
966#endif	/* NCV_DEBUG */
967
968	/********************************************
969	 * Reselect or Disconnect or Nexus check
970	 ********************************************/
971	/* (I) reselect */
972	if (ireason == INTR_RESELECT)
973	{
974		if (ncv_reselected(sc) == EJUSTRETURN)
975			return 1;
976	}
977
978	/* (II) nexus */
979	if ((ti = slp->sl_nexus) == NULL)
980		return 0;
981
982	if ((status & (STAT_PE | STAT_GE)) != 0)
983	{
984		slp->sl_error |= PARITYERR;
985		if (ti->ti_phase == PH_MSGIN)
986			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 1);
987		else
988			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
989	}
990
991	if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
992	{
993		if ((ireason & INTR_ILL) == 0)
994			return ncv_disconnected(sc, ti);
995
996		slp->sl_error |= FATALIO;
997		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd");
998		return 1;
999	}
1000
1001	/********************************************
1002	 * Internal scsi phase
1003	 ********************************************/
1004	switch (ti->ti_phase)
1005	{
1006	case PH_SELSTART:
1007		scsi_low_arbit_win(slp, ti);
1008		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
1009		identify = 0;
1010
1011		if (sc->sc_selstop == 0)
1012		{
1013			/* XXX:
1014		 	 * Here scsi phases expected are
1015			 * DATA PHASE:
1016		 	 * MSGIN     : target wants to disconnect the host.
1017			 * STATUSIN  : immediate command completed.
1018			 * MSGOUT    : identify command failed.
1019			 */
1020			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1021				break;
1022			identify = 1;
1023		}
1024		else
1025		{
1026		 	 /* XXX:
1027			  * Here scsi phase should be MSGOUT.
1028			  * The driver NEVER supports devices
1029			  * which neglect ATN singal.
1030			  */
1031			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
1032			{
1033				slp->sl_error |= FATALIO;
1034				scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
1035						 "msgout error");
1036				return 1;
1037			}
1038
1039			if ((ireason & INTR_FC) == 0)
1040				identify = 1;
1041		}
1042
1043		if (identify != 0)
1044		{
1045			printf("%s msg identify failed\n", slp->sl_xname);
1046			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
1047		}
1048		break;
1049
1050	case PH_RESEL:
1051		if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
1052		{
1053			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1054			return 1;
1055		}
1056		break;
1057
1058	default:
1059		if (slp->sl_flags & HW_PDMASTART)
1060			ncv_pdma_end(sc, ti);
1061		break;
1062	}
1063
1064	/********************************************
1065	 * Scsi phase sequencer
1066	 ********************************************/
1067	switch (status & PHASE_MASK)
1068	{
1069	case DATA_OUT_PHASE: /* data out */
1070		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1071		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
1072			break;
1073
1074		pp = physio_proc_enter(bp);
1075		ncv_pio_write(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen);
1076		physio_proc_leave(pp);
1077		break;
1078
1079	case DATA_IN_PHASE: /* data in */
1080		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
1081		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
1082			break;
1083
1084		pp = physio_proc_enter(bp);
1085		ncv_pio_read(sc, slp->sl_scp.scp_data, slp->sl_scp.scp_datalen);
1086		physio_proc_leave(pp);
1087		break;
1088
1089	case COMMAND_PHASE: /* cmd out */
1090		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
1091		if (scsi_low_cmd(slp, ti) != 0)
1092			break;
1093
1094		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1095		ncvhw_fpush(iot, ioh,
1096			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
1097		bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1098		break;
1099
1100	case STATUS_PHASE: /* status in */
1101		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
1102		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1103		bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS);
1104		sc->sc_compseq = 1;
1105		break;
1106
1107	default:
1108		break;
1109
1110	case MESSAGE_OUT_PHASE: /* msg out */
1111		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1112		bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1113
1114		len = scsi_low_msgout(slp, ti);
1115		ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len);
1116		bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1117		if (scsi_low_is_msgout_continue(ti) == 0)
1118			bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTATN);
1119		break;
1120
1121	case MESSAGE_IN_PHASE: /* msg in */
1122		SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
1123
1124		len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK;
1125		if (sc->sc_compseq != 0)
1126		{
1127			sc->sc_compseq = 0;
1128			if ((ireason & INTR_FC) && len == 2)
1129			{
1130				ti->ti_status =
1131					bus_space_read_1(iot, ioh, cr0_sfifo);
1132				len --;
1133			}
1134			else
1135			{
1136				scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
1137						 "compseq error");
1138				break;
1139			}
1140		}
1141		else if (ireason & INTR_BS)
1142		{
1143			bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH);
1144			bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS);
1145			break;
1146		}
1147
1148		if ((ireason & INTR_FC) && len == 1)
1149		{
1150			regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
1151					        cr0_sfifo);
1152			scsi_low_msgin(slp, ti, regv);
1153			bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd,
1154				CMD_MSGOK);
1155		}
1156		else
1157		{
1158			slp->sl_error |= MSGERR;
1159			printf("%s st %x ist %x\n\n", slp->sl_xname,
1160				status, ireason);
1161			scsi_low_restart(slp, SCSI_LOW_RESTART_HARD,
1162					 "hw msgin error");
1163		}
1164		break;
1165	}
1166
1167	return 1;
1168}
1169