179697Snon/*	$NecBSD: ncr53c500.c,v 1.30.12.3 2001/06/26 07:31:41 honda Exp $	*/
267468Snon/*	$NetBSD$	*/
367468Snon
467468Snon#define	NCV_DEBUG
567468Snon#define	NCV_STATICS
679697Snon#define	NCV_IO_CONTROL_FLAGS	(0)
767468Snon
8139749Simp/*-
967468Snon * [NetBSD for NEC PC-98 series]
1079697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
1167468Snon *	NetBSD/pc98 porting staff. All rights reserved.
1279697Snon *  Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001
1367468Snon *	Naofumi HONDA. All rights reserved.
1467468Snon *
1567468Snon *  Redistribution and use in source and binary forms, with or without
1667468Snon *  modification, are permitted provided that the following conditions
1767468Snon *  are met:
1867468Snon *  1. Redistributions of source code must retain the above copyright
1967468Snon *     notice, this list of conditions and the following disclaimer.
2067468Snon *  2. Redistributions in binary form must reproduce the above copyright
2167468Snon *     notice, this list of conditions and the following disclaimer in the
2267468Snon *     documentation and/or other materials provided with the distribution.
2367468Snon *  3. The name of the author may not be used to endorse or promote products
2467468Snon *     derived from this software without specific prior written permission.
2567468Snon *
2667468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2767468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2867468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2967468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3067468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3167468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3267468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3367468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3467468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3567468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3667468Snon * POSSIBILITY OF SUCH DAMAGE.
3767468Snon */
38119418Sobrien
39119418Sobrien#include <sys/cdefs.h>
40119418Sobrien__FBSDID("$FreeBSD: releng/11.0/sys/dev/ncv/ncr53c500.c 274760 2014-11-20 20:50:05Z jhb $");
4167468Snon
4267468Snon#include <sys/param.h>
4367468Snon#include <sys/systm.h>
4467468Snon#include <sys/kernel.h>
4567468Snon#include <sys/bio.h>
4667468Snon#include <sys/buf.h>
4767468Snon#include <sys/queue.h>
4867468Snon#include <sys/malloc.h>
4967468Snon#include <sys/errno.h>
50274760Sjhb#include <sys/rman.h>
5167468Snon
5267468Snon#include <machine/cpu.h>
5367468Snon#include <machine/bus.h>
5467468Snon
55126928Speter#include <compat/netbsd/dvcfg.h>
5667468Snon
5767468Snon#include <cam/scsi/scsi_low.h>
5867468Snon
5967468Snon#include <dev/ncv/ncr53c500reg.h>
6067468Snon#include <dev/ncv/ncr53c500hw.h>
6167468Snon#include <dev/ncv/ncr53c500var.h>
6267468Snon
6367468Snon#include <dev/ncv/ncr53c500hwtab.h>
6467468Snon
6579697Snon#define	NCV_MAX_DATA_SIZE	(64 * 1024)
6679697Snon#define	NCV_DELAY_MAX		(2 * 1000 * 1000)
6779697Snon#define	NCV_DELAY_INTERVAL	(1)
6879697Snon#define	NCV_PADDING_SIZE	(32)
6979697Snon
7067468Snon/***************************************************
7179697Snon * IO control
7279697Snon ***************************************************/
7379697Snon#define	NCV_READ_INTERRUPTS_DRIVEN	0x0001
7479697Snon#define	NCV_WRITE_INTERRUPTS_DRIVEN	0x0002
7579697Snon#define	NCV_ENABLE_FAST_SCSI		0x0010
7679697Snon#define	NCV_FAST_INTERRUPTS		0x0100
7779697Snon
7879697Snonu_int ncv_io_control = NCV_IO_CONTROL_FLAGS;
7979697Snonint ncv_data_read_bytes = 4096;
8079697Snonint ncv_data_write_bytes = 4096;
8179697Snon
8279697Snon/***************************************************
8367468Snon * DEBUG
8467468Snon ***************************************************/
8567468Snon#ifdef	NCV_DEBUG
8689093Smsmithstatic int ncv_debug;
8767468Snon#endif	/* NCV_DEBUG */
8867468Snon
8967468Snon#ifdef	NCV_STATICS
9089093Smsmithstatic struct ncv_statics {
9167468Snon	int disconnect;
9267468Snon	int reselect;
9379697Snon} ncv_statics;
9467468Snon#endif	/* NCV_STATICS */
9567468Snon
9667468Snon/***************************************************
9779697Snon * DEVICE STRUCTURE
9867468Snon ***************************************************/
9967468Snonextern struct cfdriver ncv_cd;
10067468Snon
10167468Snon/**************************************************************
10267468Snon * DECLARE
10367468Snon **************************************************************/
10467468Snon/* static */
10592739Salfredstatic void ncv_pio_read(struct ncv_softc *, u_int8_t *, u_int);
10692739Salfredstatic void ncv_pio_write(struct ncv_softc *, u_int8_t *, u_int);
10792739Salfredstatic int ncv_msg(struct ncv_softc *, struct targ_info *, u_int);
10892739Salfredstatic int ncv_reselected(struct ncv_softc *);
10992739Salfredstatic int ncv_disconnected(struct ncv_softc *, struct targ_info *);
11067468Snon
111274760Sjhbstatic __inline void ncvhw_set_count(struct resource *, int);
112274760Sjhbstatic __inline u_int ncvhw_get_count(struct resource *);
113274760Sjhbstatic __inline void ncvhw_select_register_0(struct resource *, struct ncv_hw *);
114274760Sjhbstatic __inline void ncvhw_select_register_1(struct resource *, struct ncv_hw *);
115274760Sjhbstatic __inline void ncvhw_fpush(struct resource *, u_int8_t *, int);
11667468Snon
11792739Salfredstatic void ncv_pdma_end(struct ncv_softc *sc, struct targ_info *);
11892739Salfredstatic int ncv_world_start(struct ncv_softc *, int);
11992739Salfredstatic void ncvhw_bus_reset(struct ncv_softc *);
120274760Sjhbstatic void ncvhw_reset(struct resource *, struct ncv_hw *);
121274760Sjhbstatic int ncvhw_check(struct resource *, struct ncv_hw *);
122274760Sjhbstatic void ncvhw_init(struct resource *, struct ncv_hw *);
12392739Salfredstatic int ncvhw_start_selection(struct ncv_softc *sc, struct slccb *);
12492739Salfredstatic void ncvhw_attention(struct ncv_softc *);
12592739Salfredstatic int ncv_ccb_nexus_establish(struct ncv_softc *);
12692739Salfredstatic int ncv_lun_nexus_establish(struct ncv_softc *);
12792739Salfredstatic int ncv_target_nexus_establish(struct ncv_softc *);
12892739Salfredstatic int ncv_targ_init(struct ncv_softc *, struct targ_info *, int);
12992739Salfredstatic int ncv_catch_intr(struct ncv_softc *);
13067468Snon#ifdef	NCV_POWER_CONTROL
13192739Salfredstatic int ncvhw_power(struct ncv_softc *, u_int);
13279697Snon#endif	/* NCV_POWER_CONTROL */
13392739Salfredstatic __inline void ncv_setup_and_start_pio(struct ncv_softc *, u_int);
13467468Snon
13567468Snonstruct scsi_low_funcs ncv_funcs = {
13667468Snon	SC_LOW_INIT_T ncv_world_start,
13767468Snon	SC_LOW_BUSRST_T ncvhw_bus_reset,
13873025Snon	SC_LOW_TARG_INIT_T ncv_targ_init,
13979697Snon	SC_LOW_LUN_INIT_T NULL,
14067468Snon
14167468Snon	SC_LOW_SELECT_T ncvhw_start_selection,
14279697Snon	SC_LOW_NEXUS_T ncv_lun_nexus_establish,
14379697Snon	SC_LOW_NEXUS_T ncv_ccb_nexus_establish,
14467468Snon
14567468Snon	SC_LOW_ATTEN_T ncvhw_attention,
14667468Snon	SC_LOW_MSG_T ncv_msg,
14767468Snon
14879697Snon	SC_LOW_TIMEOUT_T NULL,
14967468Snon	SC_LOW_POLL_T ncvintr,
15067468Snon
15167468Snon	NULL,	/* SC_LOW_POWER_T ncvhw_power, */
15267468Snon};
15367468Snon
15467468Snon/**************************************************************
15567468Snon * hwfuncs
15667468Snon **************************************************************/
15767468Snonstatic __inline void
158274760Sjhbncvhw_select_register_0(struct resource *res, struct ncv_hw *hw)
15967468Snon{
16067468Snon
161274760Sjhb	bus_write_1(res, cr0_cfg4, hw->hw_cfg4);
16267468Snon}
16367468Snon
16467468Snonstatic __inline void
165274760Sjhbncvhw_select_register_1(struct resource *res, struct ncv_hw *hw)
16667468Snon{
16767468Snon
168274760Sjhb	bus_write_1(res, cr1_cfg5, hw->hw_cfg5);
16967468Snon}
17067468Snon
17167468Snonstatic __inline void
172274760Sjhbncvhw_fpush(struct resource *res, u_int8_t *buf, int len)
17367468Snon{
17467468Snon	int ptr;
17567468Snon
17667468Snon	for (ptr = 0; ptr < len; ptr ++)
177274760Sjhb		bus_write_1(res, cr0_sfifo, buf[ptr]);
17867468Snon}
17967468Snon
18079697Snonstatic __inline void
181274760Sjhbncvhw_set_count(struct resource *res, int count)
18279697Snon{
18379697Snon
184274760Sjhb	bus_write_1(res, cr0_tclsb, (u_int8_t) count);
185274760Sjhb	bus_write_1(res, cr0_tcmsb, (u_int8_t) (count >> NBBY));
186274760Sjhb	bus_write_1(res, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2)));
18779697Snon}
18879697Snon
18979697Snonstatic __inline u_int
190274760Sjhbncvhw_get_count(struct resource *res)
19179697Snon{
19279697Snon	u_int count;
19379697Snon
194274760Sjhb	count = (u_int) bus_read_1(res, cr0_tclsb);
195274760Sjhb	count |= ((u_int) bus_read_1(res, cr0_tcmsb)) << NBBY;
196274760Sjhb	count |= ((u_int) bus_read_1(res, cr0_tchsb)) << (NBBY * 2);
19779697Snon	return count;
19879697Snon}
19979697Snon
20067468Snonstatic int
201274760Sjhbncvhw_check(struct resource *res, struct ncv_hw *hw)
20267468Snon{
20367468Snon	u_int8_t stat;
20467468Snon
205274760Sjhb	ncvhw_select_register_0(res, hw);
206274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP | CMD_DMA);
207274760Sjhb	if (bus_read_1(res, cr0_cmd) != (CMD_NOP | CMD_DMA))
20867468Snon	{
20967468Snon#ifdef	NCV_DEBUG
21067468Snon		printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n");
21167468Snon#endif	/* NCV_DEBUG */
21267468Snon		return ENODEV;
21367468Snon	}
21467468Snon
215274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP);
216274760Sjhb	if (bus_read_1(res, cr0_cmd) != CMD_NOP)
21767468Snon	{
21867468Snon#ifdef	NCV_DEBUG
21967468Snon		printf("ncv: cr0_cmd CMD_NOP failed\n");
22067468Snon#endif	/* NCV_DEBUG */
22167468Snon		return ENODEV;
22267468Snon	}
22367468Snon
22467468Snon	/* hardware reset */
225274760Sjhb	ncvhw_reset(res, hw);
226274760Sjhb	ncvhw_init(res, hw);
22767468Snon
22867468Snon	/* bus reset */
229274760Sjhb	ncvhw_select_register_0(res, hw);
230274760Sjhb	bus_write_1(res, cr0_cmd, CMD_FLUSH);
231274760Sjhb	bus_write_1(res, cr0_cmd, CMD_RSTSCSI);
232274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP | CMD_DMA);
233240172Sjhb	DELAY(100 * 1000);
23467468Snon
23567468Snon	/* check response */
236274760Sjhb	bus_read_1(res, cr0_stat);
237274760Sjhb	stat = bus_read_1(res, cr0_istat);
238240172Sjhb	DELAY(1000);
23967468Snon
24067468Snon	if (((stat & INTR_SBR) == 0) ||
241274760Sjhb	    (bus_read_1(res, cr0_istat) & INTR_SBR))
24267468Snon	{
24367468Snon#ifdef	NCV_DEBUG
24467468Snon		printf("ncv: cr0_istat SCSI BUS RESET failed\n");
24567468Snon#endif	/* NCV_DEBUG */
24667468Snon		return ENODEV;
24767468Snon	}
24867468Snon
24967468Snon	return 0;
25067468Snon}
25167468Snon
25267468Snonstatic void
253274760Sjhbncvhw_reset(struct resource *res, struct ncv_hw *hw)
25467468Snon{
25567468Snon
256274760Sjhb	ncvhw_select_register_0(res, hw);
25767468Snon
25867468Snon	/* dummy cmd twice */
259274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP);
260274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP);
26167468Snon
26267468Snon	/* chip reset */
263274760Sjhb	bus_write_1(res, cr0_cmd, CMD_RSTCHIP);
26467468Snon
26567468Snon	/* again dummy cmd twice */
266274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP);
267274760Sjhb	bus_write_1(res, cr0_cmd, CMD_NOP);
26867468Snon}
26967468Snon
27067468Snonstatic void
271274760Sjhbncvhw_init(struct resource *res, struct ncv_hw *hw)
27267468Snon{
27367468Snon
274274760Sjhb	ncvhw_select_register_0(res, hw);
275274760Sjhb	bus_write_1(res, cr0_clk, hw->hw_clk);
276274760Sjhb	bus_write_1(res, cr0_srtout, SEL_TOUT);
277274760Sjhb	bus_write_1(res, cr0_period, 0);
278274760Sjhb	bus_write_1(res, cr0_offs, 0);
27967468Snon
280274760Sjhb	bus_write_1(res, cr0_cfg1, hw->hw_cfg1);
281274760Sjhb	bus_write_1(res, cr0_cfg2, hw->hw_cfg2);
282274760Sjhb	bus_write_1(res, cr0_cfg3, hw->hw_cfg3);
283274760Sjhb	bus_write_1(res, cr0_tchsb, 0);
28467468Snon
285274760Sjhb	ncvhw_select_register_1(res, hw);
286274760Sjhb	bus_write_1(res, cr1_fstat, 0x0);
287274760Sjhb	bus_write_1(res, cr1_pflag, 0x0);
288274760Sjhb	bus_write_1(res, cr1_atacmd, ATACMD_ENGAGE);
28967468Snon
290274760Sjhb	ncvhw_select_register_0(res, hw);
29167468Snon}
29267468Snon
29367468Snon#ifdef	NCV_POWER_CONTROL
29467468Snonstatic int
29567468Snonncvhw_power(sc, flags)
29667468Snon	struct ncv_softc *sc;
29767468Snon	u_int flags;
29867468Snon{
29967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
300274760Sjhb	struct resource *res = sc->port_res;
30167468Snon
30267468Snon	if (flags == SCSI_LOW_POWDOWN)
30367468Snon	{
304240325Sjhb		device_printf(slp->sl_dev, "power down\n");
305274760Sjhb		ncvhw_select_register_1(res, &sc->sc_hw);
306274760Sjhb		bus_write_1(res, cr1_atacmd, ATACMD_POWDOWN);
30767468Snon	}
30867468Snon	else
30967468Snon	{
31067468Snon		switch (sc->sc_rstep)
31167468Snon		{
31267468Snon		case 0:
313240325Sjhb			device_printf(slp->sl_dev, "resume step O\n");
314274760Sjhb			ncvhw_select_register_1(res, &sc->sc_hw);
315274760Sjhb			bus_write_1(res, cr1_atacmd, ATACMD_ENGAGE);
31667468Snon			break;
31767468Snon
31867468Snon		case 1:
319240325Sjhb			device_printf(slp->sl_dev, "resume step I\n");
320274760Sjhb			ncvhw_reset(res, &sc->sc_hw);
321274760Sjhb			ncvhw_init(res, &sc->sc_hw);
32267468Snon			break;
32367468Snon		}
32467468Snon	}
32567468Snon
32667468Snon	return 0;
32767468Snon}
32867468Snon#endif	/* NCV_POWER_CONTROL */
32967468Snon
33067468Snon/**************************************************************
33167468Snon * scsi low interface
33267468Snon **************************************************************/
33367468Snonstatic void
33467468Snonncvhw_attention(sc)
33567468Snon	struct ncv_softc *sc;
33667468Snon{
33767468Snon
338274760Sjhb	bus_write_1(sc->port_res, cr0_cmd, CMD_SETATN);
339240172Sjhb	DELAY(10);
34067468Snon}
34167468Snon
34267468Snonstatic void
34367468Snonncvhw_bus_reset(sc)
34467468Snon	struct ncv_softc *sc;
34567468Snon{
34667468Snon
347274760Sjhb	ncvhw_select_register_0(sc->port_res, &sc->sc_hw);
348274760Sjhb	bus_write_1(sc->port_res, cr0_cmd, CMD_FLUSH);
349274760Sjhb	bus_write_1(sc->port_res, cr0_cmd, CMD_RSTSCSI);
350274760Sjhb	bus_write_1(sc->port_res, cr0_cmd, CMD_NOP | CMD_DMA);
35167468Snon}
35267468Snon
35367468Snonstatic int
35467468Snonncvhw_start_selection(sc, cb)
35567468Snon	struct ncv_softc *sc;
35667468Snon	struct slccb *cb;
35767468Snon{
35867468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
359274760Sjhb	struct resource *res = sc->port_res;
36067468Snon	struct targ_info *ti = cb->ti;
361274760Sjhb	int len;
36279697Snon	u_int flags;
36379697Snon	u_int8_t cmd;
36467468Snon
36579697Snon	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
36667468Snon	sc->sc_compseq = 0;
36779697Snon	if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0)
36879697Snon	{
36979697Snon		cmd = CMD_SELATN;
37079697Snon		sc->sc_selstop = 0;
37179697Snon		flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
37279697Snon	}
37379697Snon	else if (scsi_low_is_msgout_continue(ti,
37479697Snon			SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0)
37579697Snon	{
37679697Snon		cmd = CMD_SELATN3;
37779697Snon		sc->sc_selstop = 0;
37879697Snon		flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT;
37979697Snon	}
38079697Snon	else
38179697Snon	{
38279697Snon		cmd = CMD_SELATNS;
38379697Snon		sc->sc_selstop = 1;
38479697Snon		flags = SCSI_LOW_MSGOUT_INIT;
38579697Snon	}
38679697Snon
387274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
388274760Sjhb	if ((bus_read_1(res, cr0_stat) & STAT_INT) != 0)
38979697Snon		return SCSI_LOW_START_FAIL;
39067468Snon
39179697Snon	ncv_target_nexus_establish(sc);
39279697Snon
39379697Snon	len = scsi_low_msgout(slp, ti, flags);
39479697Snon	if (sc->sc_selstop == 0)
39579697Snon		scsi_low_cmd(slp, ti);
39679697Snon
397274760Sjhb	if ((bus_read_1(res, cr0_stat) & STAT_INT) != 0)
39867468Snon		return SCSI_LOW_START_FAIL;
39967468Snon
400274760Sjhb	bus_write_1(res, cr0_dstid, ti->ti_id);
401274760Sjhb	bus_write_1(res, cr0_cmd, CMD_FLUSH);
402274760Sjhb	ncvhw_fpush(res, ti->ti_msgoutstr, len);
40379697Snon	if (sc->sc_selstop == 0)
40467468Snon	{
405274760Sjhb		ncvhw_fpush(res,
40667468Snon			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
40767468Snon	}
408274760Sjhb	bus_write_1(res, cr0_cmd, cmd);
40967468Snon
41067468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
41167468Snon	return SCSI_LOW_START_OK;
41267468Snon}
41367468Snon
41467468Snonstatic int
41567468Snonncv_world_start(sc, fdone)
41667468Snon	struct ncv_softc *sc;
41767468Snon	int fdone;
41867468Snon{
41967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
420274760Sjhb	struct resource *res = sc->port_res;
42167468Snon	u_int8_t stat;
42267468Snon
42379697Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
42479697Snon		sc->sc_hw.hw_cfg1 |= C1_PARENB;
42579697Snon	else
42679697Snon		sc->sc_hw.hw_cfg1 &= ~C1_PARENB;
42779697Snon
428274760Sjhb	ncvhw_reset(res, &sc->sc_hw);
429274760Sjhb	ncvhw_init(res, &sc->sc_hw);
43067468Snon
43171466Sjhb	scsi_low_bus_reset(slp);
43267468Snon
433274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
434274760Sjhb	bus_read_1(res, cr0_stat);
435274760Sjhb	stat = bus_read_1(res, cr0_istat);
436240172Sjhb	DELAY(1000);
43767468Snon
43867468Snon	if (((stat & INTR_SBR) == 0) ||
439274760Sjhb	    (bus_read_1(res, cr0_istat) & INTR_SBR))
44067468Snon		return ENODEV;
44167468Snon
44267468Snon	return 0;
44367468Snon}
44467468Snon
44567468Snonstatic int
44667468Snonncv_msg(sc, ti, msg)
44767468Snon	struct ncv_softc *sc;
44867468Snon	struct targ_info *ti;
44967468Snon	u_int msg;
45067468Snon{
451274760Sjhb	struct resource *res = sc->port_res;
45273025Snon	struct ncv_targ_info *nti = (void *) ti;
45367468Snon	u_int hwcycle, period;
45467468Snon
45579697Snon	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
45679697Snon	{
45779697Snon		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
45879697Snon		{
45979697Snon			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
46079697Snon			return EINVAL;
46179697Snon		}
46279697Snon		return 0;
46379697Snon	}
46479697Snon
46567468Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
46667468Snon		return 0;
46767468Snon
46873025Snon	period = ti->ti_maxsynch.period;
46979697Snon	hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk);
47079697Snon	hwcycle = 1000 / hwcycle;
47167468Snon
47267468Snon	if (period < 200 / 4 && period >= 100 / 4)
47379697Snon		nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi;
47467468Snon	else
47579697Snon		nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi;
47667468Snon
47767468Snon	period = ((period * 40 / hwcycle) + 5) / 10;
47873025Snon	nti->nti_reg_period = period & 0x1f;
47973025Snon	nti->nti_reg_offset = ti->ti_maxsynch.offset;
48079697Snon
481274760Sjhb	bus_write_1(res, cr0_period, nti->nti_reg_period);
482274760Sjhb	bus_write_1(res, cr0_offs, nti->nti_reg_offset);
483274760Sjhb	bus_write_1(res, cr0_cfg3, nti->nti_reg_cfg3);
48467468Snon	return 0;
48567468Snon}
48667468Snon
48767468Snonstatic int
48879697Snonncv_targ_init(sc, ti, action)
48967468Snon	struct ncv_softc *sc;
49067468Snon	struct targ_info *ti;
49179697Snon	int action;
49267468Snon{
49373025Snon	struct ncv_targ_info *nti = (void *) ti;
49467468Snon
49579697Snon	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
49679697Snon	{
49779697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
49879697Snon		ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod;
49979697Snon		ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset;
50067468Snon
50179697Snon		nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3;
50279697Snon		nti->nti_reg_period = 0;
50379697Snon		nti->nti_reg_offset = 0;
50479697Snon	}
50567468Snon	return 0;
50667468Snon}
50767468Snon
50867468Snon/**************************************************************
50967468Snon * General probe attach
51067468Snon **************************************************************/
51192739Salfredstatic int ncv_setup_img(struct ncv_hw *, u_int, int);
51267468Snon
51367468Snonstatic int
51479697Snonncv_setup_img(hw, dvcfg, hostid)
51567468Snon	struct ncv_hw *hw;
51667468Snon	u_int dvcfg;
51779697Snon	int hostid;
51867468Snon{
51967468Snon
52067468Snon	if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F)
52167468Snon	{
52267468Snon		printf("ncv: invalid dvcfg flags\n");
52367468Snon		return EINVAL;
52467468Snon	}
52567468Snon
52667468Snon	if (NCV_C5IMG(dvcfg) != 0)
52767468Snon	{
52879697Snon		hw->hw_cfg5 = NCV_C5IMG(dvcfg);
52979697Snon		hw->hw_clk = NCV_CLKFACTOR(dvcfg);
53067468Snon
53179697Snon		if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 &&
53279697Snon		    (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0)
53379697Snon			hw->hw_mperiod = 100 / 4;
53467468Snon
53567468Snon		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG)
53679697Snon			hw->hw_cfg3_fclk = 0x04;
53767468Snon
53867468Snon		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1)
53979697Snon			hw->hw_cfg2 &= ~C2_SCSI2;
54067468Snon
54167468Snon		if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW)
54279697Snon			hw->hw_cfg1 |= C1_SLOW;
54367468Snon	}
54467468Snon
54567468Snon	/* setup configuration image 3 */
54679697Snon	if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F)
54779697Snon		hw->hw_cfg3 &= ~hw->hw_cfg3_fclk;
54879697Snon	else
54979697Snon		hw->hw_cfg3 |= hw->hw_cfg3_fclk;
55067468Snon
55167468Snon	/* setup configuration image 1 */
55279697Snon	hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid;
55367468Snon	return 0;
55467468Snon}
55567468Snon
55667468Snonint
557274760Sjhbncvprobesubr(struct resource *res, u_int dvcfg, int hsid)
55867468Snon{
55967468Snon	struct ncv_hw hwtab;
56067468Snon
56167468Snon	hwtab = ncv_template;
56267468Snon	if (ncv_setup_img(&hwtab, dvcfg, hsid))
56367468Snon		return 0;
564274760Sjhb	if (ncvhw_check(res, &hwtab) != 0)
56567468Snon		return 0;
56667468Snon
56767468Snon	return 1;
56867468Snon}
56967468Snon
57067468Snonvoid
57167468Snonncvattachsubr(sc)
57267468Snon	struct ncv_softc *sc;
57367468Snon{
57467468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
57567468Snon
57667468Snon	printf("\n");
57767468Snon	sc->sc_hw = ncv_template;
57867468Snon	ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid);
57967468Snon	slp->sl_funcs = &ncv_funcs;
58079697Snon	slp->sl_flags |= HW_READ_PADDING;
58179697Snon	sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
58279697Snon
58379697Snon	(void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS,
58479697Snon			       sizeof(struct ncv_targ_info), 0);
58567468Snon}
58667468Snon
58767468Snon/**************************************************************
58867468Snon * PDMA
58967468Snon **************************************************************/
59067468Snonstatic __inline void
59179697Snonncv_setup_and_start_pio(sc, reqlen)
59279697Snon	struct ncv_softc *sc;
59379697Snon	u_int reqlen;
59467468Snon{
595274760Sjhb	struct resource *res = sc->port_res;
59667468Snon
597274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
598274760Sjhb	ncvhw_set_count(res, reqlen);
599274760Sjhb	bus_write_1(res, cr0_cmd, CMD_TRANS | CMD_DMA);
60067468Snon
601274760Sjhb	ncvhw_select_register_1(res, &sc->sc_hw);
602274760Sjhb	bus_write_1(res, cr1_fstat, FIFO_EN);
60367468Snon}
60467468Snon
60579697Snonstatic void
60667468Snonncv_pdma_end(sc, ti)
60767468Snon	struct ncv_softc *sc;
60867468Snon	struct targ_info *ti;
60967468Snon{
61067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
611274760Sjhb	struct resource *res = sc->port_res;
61267468Snon	int len;
61367468Snon
61467468Snon	slp->sl_flags &= ~HW_PDMASTART;
61579697Snon	if (slp->sl_Qnexus == NULL)
61679697Snon	{
61779697Snon		slp->sl_error |= PDMAERR;
61879697Snon		goto out;
61979697Snon	}
62079697Snon
62167468Snon	if (ti->ti_phase == PH_DATA)
62267468Snon	{
623274760Sjhb		len = ncvhw_get_count(res);
62467468Snon		if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE)
625274760Sjhb			len += (bus_read_1(res,
62667468Snon				cr0_sffl) & CR0_SFFLR_BMASK);
62767468Snon
62879697Snon		if ((u_int) len <= (u_int) sc->sc_sdatalen)
62967468Snon		{
63067468Snon			if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) &&
63167468Snon			    sc->sc_tdatalen != len)
63267468Snon				goto bad;
63379697Snon
63479697Snon			len = sc->sc_sdatalen - len;
63579697Snon			if ((u_int) len > (u_int) slp->sl_scp.scp_datalen)
63679697Snon				goto bad;
63779697Snon
63879697Snon			slp->sl_scp.scp_data += len;
63979697Snon			slp->sl_scp.scp_datalen -= len;
64067468Snon		}
64167468Snon		else
64267468Snon		{
64367468Snonbad:
64479697Snon			if ((slp->sl_error & PDMAERR) == 0)
64579697Snon			{
646240325Sjhb				device_printf(slp->sl_dev,
647240325Sjhb				    "strange cnt hw 0x%x soft 0x%x\n", len,
648240325Sjhb				    slp->sl_scp.scp_datalen);
64979697Snon			}
65067468Snon			slp->sl_error |= PDMAERR;
65167468Snon		}
65279697Snon		scsi_low_data_finish(slp);
65367468Snon	}
65467468Snon	else
65567468Snon	{
656240325Sjhb		device_printf(slp->sl_dev, "data phase miss\n");
65767468Snon		slp->sl_error |= PDMAERR;
65867468Snon	}
65967468Snon
66079697Snonout:
661274760Sjhb	ncvhw_select_register_1(res, &sc->sc_hw);
662274760Sjhb	bus_write_1(res, cr1_fstat, 0);
663274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
66467468Snon}
66567468Snon
66667468Snonstatic void
66767468Snonncv_pio_read(sc, buf, reqlen)
66867468Snon	struct ncv_softc *sc;
66967468Snon	u_int8_t *buf;
67067468Snon	u_int reqlen;
67167468Snon{
67267468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
673274760Sjhb	struct resource *res = sc->port_res;
67479697Snon	int tout;
67567468Snon	register u_int8_t fstat;
67667468Snon
67779697Snon	ncv_setup_and_start_pio(sc, reqlen);
67867468Snon	slp->sl_flags |= HW_PDMASTART;
67979697Snon	sc->sc_sdatalen = reqlen;
68079697Snon	tout = sc->sc_tmaxcnt;
68167468Snon
68279697Snon	while (reqlen >= FIFO_F_SZ && tout -- > 0)
68367468Snon	{
684274760Sjhb		fstat = bus_read_1(res, cr1_fstat);
68579697Snon		if (fstat == (u_int8_t) -1)
68679697Snon			goto out;
68767468Snon		if (fstat & FIFO_F)
68867468Snon		{
68967468Snon#define	NCV_FAST32_ACCESS
69067468Snon#ifdef	NCV_FAST32_ACCESS
691274760Sjhb			bus_read_multi_4(res, cr1_fdata,
69267468Snon				(u_int32_t *) buf, FIFO_F_SZ / 4);
69367468Snon#else	/* !NCV_FAST32_ACCESS */
694274760Sjhb			bus_read_multi_2(res, cr1_fdata,
69567468Snon				(u_int16_t *) buf, FIFO_F_SZ / 2);
69667468Snon#endif	/* !NCV_FAST32_ACCESS */
69767468Snon			buf += FIFO_F_SZ;
69867468Snon			reqlen -= FIFO_F_SZ;
69967468Snon		}
70079697Snon		else
70179697Snon		{
70279697Snon			if (fstat & FIFO_BRK)
70379697Snon				break;
70467468Snon
705240172Sjhb			DELAY(1);
70667468Snon		}
70767468Snon	}
70867468Snon
70979697Snon	while (reqlen > 0 && tout -- > 0)
71067468Snon	{
711274760Sjhb		fstat = bus_read_1(res, cr1_fstat);
71267468Snon		if ((fstat & FIFO_E) == 0)
71367468Snon		{
714274760Sjhb			*buf++ = bus_read_1(res, cr1_fdata);
71567468Snon			reqlen --;
71667468Snon		}
71779697Snon		else
71879697Snon		{
71979697Snon			 if (fstat & FIFO_BRK)
72079697Snon				break;
72167468Snon
722240172Sjhb			DELAY(1);
72379697Snon		}
72467468Snon	}
72567468Snon
72679697Snonout:
727274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
72867468Snon	sc->sc_tdatalen = reqlen;
72967468Snon}
73067468Snon
73167468Snonstatic void
73267468Snonncv_pio_write(sc, buf, reqlen)
73367468Snon	struct ncv_softc *sc;
73467468Snon	u_int8_t *buf;
73567468Snon	u_int reqlen;
73667468Snon{
73767468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
738274760Sjhb	struct resource *res = sc->port_res;
73979697Snon	int tout;
74067468Snon	register u_int8_t fstat;
74167468Snon
74279697Snon	ncv_setup_and_start_pio(sc, reqlen);
74379697Snon	sc->sc_sdatalen = reqlen;
74479697Snon	tout = sc->sc_tmaxcnt;
74567468Snon	slp->sl_flags |= HW_PDMASTART;
74667468Snon
74779697Snon	while (reqlen >= FIFO_F_SZ && tout -- > 0)
74867468Snon	{
749274760Sjhb		fstat = bus_read_1(res, cr1_fstat);
75067468Snon		if (fstat & FIFO_BRK)
75167468Snon			goto done;
75267468Snon
75379697Snon		if ((fstat & FIFO_E) != 0)
75467468Snon		{
75567468Snon#ifdef	NCV_FAST32_ACCESS
756274760Sjhb			bus_write_multi_4(res, cr1_fdata,
75767468Snon				(u_int32_t *) buf, FIFO_F_SZ / 4);
75867468Snon#else	/* !NCV_FAST32_ACCESS */
759274760Sjhb			bus_write_multi_2(res, cr1_fdata,
76067468Snon				(u_int16_t *) buf, FIFO_F_SZ / 2);
76167468Snon#endif	/* !NCV_FAST32_ACCESS */
76267468Snon			buf += FIFO_F_SZ;
76367468Snon			reqlen -= FIFO_F_SZ;
76467468Snon		}
76573025Snon		else
76679697Snon		{
767240172Sjhb			DELAY(1);
76879697Snon		}
76967468Snon	}
77067468Snon
77179697Snon	while (reqlen > 0 && tout -- > 0)
77267468Snon	{
773274760Sjhb		fstat = bus_read_1(res, cr1_fstat);
77467468Snon		if (fstat & FIFO_BRK)
77567468Snon			break;
77667468Snon
77767468Snon		if ((fstat & FIFO_F) == 0) /* fifo not full */
77867468Snon		{
779274760Sjhb			bus_write_1(res, cr1_fdata, *buf++);
78067468Snon			reqlen --;
78167468Snon		}
78273025Snon		else
78379697Snon		{
784240172Sjhb			DELAY(1);
78579697Snon		}
78667468Snon	}
78767468Snon
78867468Snondone:
789274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
79067468Snon}
79167468Snon
79267468Snon/**************************************************************
79367468Snon * disconnect & reselect (HW low)
79467468Snon **************************************************************/
79579697Snonstatic int
79667468Snonncv_reselected(sc)
79767468Snon	struct ncv_softc *sc;
79867468Snon{
79967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
800274760Sjhb	struct resource *res = sc->port_res;
80167468Snon	struct targ_info *ti;
80267468Snon	u_int sid;
80367468Snon
804274760Sjhb	if ((bus_read_1(res, cr0_sffl) & CR0_SFFLR_BMASK) != 2)
80567468Snon	{
806240325Sjhb		device_printf(slp->sl_dev, "illegal fifo bytes\n");
80767468Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused");
80867468Snon		return EJUSTRETURN;
80967468Snon	}
81067468Snon
811274760Sjhb	sid = (u_int) bus_read_1(res, cr0_sfifo);
81279697Snon	sid &= ~(1 << slp->sl_hostid);
81367468Snon	sid = ffs(sid) - 1;
81467468Snon	ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid);
81567468Snon	if (ti == NULL)
81667468Snon		return EJUSTRETURN;
81767468Snon
81867468Snon#ifdef	NCV_STATICS
81979697Snon	ncv_statics.reselect ++;
82067468Snon#endif	/* NCV_STATICS */
821274760Sjhb	bus_write_1(res, cr0_dstid, sid);
82267468Snon	return 0;
82367468Snon}
82467468Snon
82579697Snonstatic int
82667468Snonncv_disconnected(sc, ti)
82767468Snon	struct ncv_softc *sc;
82867468Snon	struct targ_info *ti;
82967468Snon{
83067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
831274760Sjhb	struct resource *res = sc->port_res;
83267468Snon
833274760Sjhb	bus_write_1(res, cr0_cmd, CMD_FLUSH);
834274760Sjhb	bus_write_1(res, cr0_cmd, CMD_ENSEL);
83567468Snon
83667468Snon#ifdef	NCV_STATICS
83779697Snon	ncv_statics.disconnect ++;
83867468Snon#endif	/* NCV_STATICS */
83967468Snon
84067468Snon	scsi_low_disconnected(slp, ti);
84167468Snon	return 1;
84267468Snon}
84367468Snon
84467468Snon/**************************************************************
84567468Snon * SEQUENCER
84667468Snon **************************************************************/
84767468Snonstatic int
84879697Snonncv_target_nexus_establish(sc)
84967468Snon	struct ncv_softc *sc;
85067468Snon{
85179697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
85279697Snon	struct targ_info *ti = slp->sl_Tnexus;
85379697Snon	struct ncv_targ_info *nti = (void *) ti;
854274760Sjhb	struct resource *res = sc->port_res;
85567468Snon
856274760Sjhb	bus_write_1(res, cr0_period, nti->nti_reg_period);
857274760Sjhb	bus_write_1(res, cr0_offs, nti->nti_reg_offset);
858274760Sjhb	bus_write_1(res, cr0_cfg3, nti->nti_reg_cfg3);
85967468Snon	return 0;
86067468Snon}
86167468Snon
86279697Snonstatic int
86379697Snonncv_lun_nexus_establish(sc)
86479697Snon	struct ncv_softc *sc;
86579697Snon{
86679697Snon
86779697Snon	return 0;
86879697Snon}
86979697Snon
87079697Snonstatic int
87179697Snonncv_ccb_nexus_establish(sc)
87279697Snon	struct ncv_softc *sc;
87379697Snon{
87479697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
87579697Snon	struct slccb *cb = slp->sl_Qnexus;
87679697Snon
87779697Snon	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
87879697Snon	return 0;
87979697Snon}
88079697Snon
88179697Snonstatic int
88279697Snonncv_catch_intr(sc)
88379697Snon	struct ncv_softc *sc;
88479697Snon{
885274760Sjhb	struct resource *res = sc->port_res;
88679697Snon	int wc;
88779697Snon	register u_int8_t status;
88879697Snon
88979697Snon	for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++)
89079697Snon	{
891274760Sjhb		status = bus_read_1(res, cr0_stat);
89279697Snon		if ((status & STAT_INT) != 0)
89379697Snon			return 0;
89479697Snon
895240172Sjhb		DELAY(NCV_DELAY_INTERVAL);
89679697Snon	}
89779697Snon	return EJUSTRETURN;
89879697Snon}
89979697Snon
90067468Snonint
90167468Snonncvintr(arg)
90267468Snon	void *arg;
90367468Snon{
90467468Snon	struct ncv_softc *sc = arg;
90567468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
906274760Sjhb	struct resource *res = sc->port_res;
90767468Snon	struct targ_info *ti;
90867468Snon	struct buf *bp;
90979697Snon	u_int derror, flags;
91079697Snon	int len;
91167468Snon	u_int8_t regv, status, ireason;
91267468Snon
91379697Snonagain:
91467468Snon	if (slp->sl_flags & HW_INACTIVE)
91567468Snon		return 0;
91667468Snon
91767468Snon	/********************************************
91867468Snon	 * Status
91967468Snon	 ********************************************/
920274760Sjhb	ncvhw_select_register_0(res, &sc->sc_hw);
921274760Sjhb	status = bus_read_1(res, cr0_stat);
92279697Snon	if ((status & STAT_INT) == 0 || status == (u_int8_t) -1)
92367468Snon		return 0;
92467468Snon
925274760Sjhb	ireason = bus_read_1(res, cr0_istat);
92679697Snon	if ((ireason & INTR_SBR) != 0)
92767468Snon	{
92867468Snon		u_int8_t val;
92967468Snon
93067468Snon		/* avoid power off hangup */
931274760Sjhb		val = bus_read_1(res, cr0_cfg1);
932274760Sjhb		bus_write_1(res, cr0_cfg1, val | C1_SRR);
93367468Snon
93467468Snon		/* status init */
93567468Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
93667468Snon				 "bus reset (power off?)");
93767468Snon		return 1;
93867468Snon	}
93967468Snon
94067468Snon	/********************************************
94167468Snon	 * Debug section
94267468Snon	 ********************************************/
94367468Snon#ifdef	NCV_DEBUG
94467468Snon	if (ncv_debug)
94567468Snon	{
94667468Snon		scsi_low_print(slp, NULL);
947240325Sjhb		device_printf(slp->sl_dev, "st %x ist %x\n\n",
94867468Snon			status, ireason);
949131914Smarcel#ifdef	KDB
95067468Snon		if (ncv_debug > 1)
951240172Sjhb			kdb_enter(KDB_WHY_CAM, "ncv");
952131914Smarcel#endif	/* KDB */
95367468Snon	}
95467468Snon#endif	/* NCV_DEBUG */
95567468Snon
95667468Snon	/********************************************
95767468Snon	 * Reselect or Disconnect or Nexus check
95867468Snon	 ********************************************/
95967468Snon	/* (I) reselect */
96067468Snon	if (ireason == INTR_RESELECT)
96167468Snon	{
96267468Snon		if (ncv_reselected(sc) == EJUSTRETURN)
96367468Snon			return 1;
96467468Snon	}
96567468Snon
96667468Snon	/* (II) nexus */
96779697Snon	if ((ti = slp->sl_Tnexus) == NULL)
96867468Snon		return 0;
96967468Snon
97079697Snon	derror = 0;
97167468Snon	if ((status & (STAT_PE | STAT_GE)) != 0)
97267468Snon	{
97367468Snon		slp->sl_error |= PARITYERR;
97479697Snon		if ((status & PHASE_MASK) == MESSAGE_IN_PHASE)
97579697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0);
97667468Snon		else
97767468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1);
97879697Snon		derror = SCSI_LOW_DATA_PE;
97967468Snon	}
98067468Snon
98167468Snon	if ((ireason & (INTR_DIS | INTR_ILL)) != 0)
98267468Snon	{
98367468Snon		if ((ireason & INTR_ILL) == 0)
98467468Snon			return ncv_disconnected(sc, ti);
98567468Snon
98667468Snon		slp->sl_error |= FATALIO;
98767468Snon		scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd");
98867468Snon		return 1;
98967468Snon	}
99067468Snon
99167468Snon	/********************************************
99267468Snon	 * Internal scsi phase
99367468Snon	 ********************************************/
99467468Snon	switch (ti->ti_phase)
99567468Snon	{
99667468Snon	case PH_SELSTART:
99779697Snon		scsi_low_arbit_win(slp);
99867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
99967468Snon
100067468Snon		if (sc->sc_selstop == 0)
100167468Snon		{
100267468Snon			/* XXX:
100367468Snon		 	 * Here scsi phases expected are
100467468Snon			 * DATA PHASE:
100567468Snon		 	 * MSGIN     : target wants to disconnect the host.
100667468Snon			 * STATUSIN  : immediate command completed.
100779697Snon			 * CMD PHASE : command out failed
100867468Snon			 * MSGOUT    : identify command failed.
100967468Snon			 */
101067468Snon			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
101167468Snon				break;
101267468Snon		}
101367468Snon		else
101467468Snon		{
101567468Snon			if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE)
101679697Snon				break;
101779697Snon			if ((ireason & INTR_FC) != 0)
101867468Snon			{
101979697Snon				SCSI_LOW_ASSERT_ATN(slp);
102067468Snon			}
102167468Snon		}
102279697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
102367468Snon		break;
102467468Snon
102567468Snon	case PH_RESEL:
102679697Snon		ncv_target_nexus_establish(sc);
102767468Snon		if ((status & PHASE_MASK) != MESSAGE_IN_PHASE)
102867468Snon		{
1029240325Sjhb			device_printf(slp->sl_dev,
1030240325Sjhb			    "unexpected phase after reselect\n");
103179697Snon			slp->sl_error |= FATALIO;
103267468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
103367468Snon			return 1;
103467468Snon		}
103567468Snon		break;
103667468Snon
103767468Snon	default:
103879697Snon		if ((slp->sl_flags & HW_PDMASTART) != 0)
103979697Snon		{
104067468Snon			ncv_pdma_end(sc, ti);
104179697Snon		}
104267468Snon		break;
104367468Snon	}
104467468Snon
104567468Snon	/********************************************
104667468Snon	 * Scsi phase sequencer
104767468Snon	 ********************************************/
104867468Snon	switch (status & PHASE_MASK)
104967468Snon	{
105067468Snon	case DATA_OUT_PHASE: /* data out */
105167468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
105267468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
105379697Snon		{
105479697Snon			scsi_low_attention(slp);
105579697Snon		}
105667468Snon
105779697Snon		if (slp->sl_scp.scp_datalen <= 0)
105879697Snon		{
105979697Snon			if ((ireason & INTR_BS) == 0)
106079697Snon				break;
106179697Snon
106279697Snon			if ((slp->sl_error & PDMAERR) == 0)
1063240325Sjhb				device_printf(slp->sl_dev, "data underrun\n");
106479697Snon			slp->sl_error |= PDMAERR;
106579697Snon
106679697Snon			if ((slp->sl_flags & HW_WRITE_PADDING) != 0)
106779697Snon			{
106879697Snon				u_int8_t padding[NCV_PADDING_SIZE];
106979697Snon
1070240172Sjhb				bzero(padding, sizeof(padding));
107179697Snon				ncv_pio_write(sc, padding, sizeof(padding));
107279697Snon			}
107379697Snon			else
107479697Snon			{
1075240325Sjhb				device_printf(slp->sl_dev,
1076240325Sjhb				    "write padding required\n");
107779697Snon			}
107879697Snon		}
107979697Snon		else
108079697Snon		{
108179697Snon			len = slp->sl_scp.scp_datalen;
108279697Snon			if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0)
108379697Snon			{
108479697Snon				if (len > ncv_data_write_bytes)
108579697Snon					len = ncv_data_write_bytes;
108679697Snon			}
108779697Snon			ncv_pio_write(sc, slp->sl_scp.scp_data, len);
108879697Snon		}
108967468Snon		break;
109067468Snon
109167468Snon	case DATA_IN_PHASE: /* data in */
109267468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
109367468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
109479697Snon		{
109579697Snon			scsi_low_attention(slp);
109679697Snon		}
109767468Snon
109879697Snon		if (slp->sl_scp.scp_datalen <= 0)
109979697Snon		{
110079697Snon			if ((ireason & INTR_BS) == 0)
110179697Snon				break;
110279697Snon
110379697Snon			if ((slp->sl_error & PDMAERR) == 0)
1104240325Sjhb				device_printf(slp->sl_dev, "data overrun\n");
110579697Snon			slp->sl_error |= PDMAERR;
110679697Snon
110779697Snon			if ((slp->sl_flags & HW_READ_PADDING) != 0)
110879697Snon			{
110979697Snon				u_int8_t padding[NCV_PADDING_SIZE];
111079697Snon
111179697Snon				ncv_pio_read(sc, padding, sizeof(padding));
111279697Snon			}
111379697Snon			else
111479697Snon			{
1115240325Sjhb				device_printf(slp->sl_dev,
1116240325Sjhb				    "read padding required\n");
111779697Snon				break;
111879697Snon			}
111979697Snon		}
112079697Snon		else
112179697Snon		{
112279697Snon			len = slp->sl_scp.scp_datalen;
112379697Snon			if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0)
112479697Snon			{
112579697Snon				if (len > ncv_data_read_bytes)
112679697Snon					len = ncv_data_read_bytes;
112779697Snon			}
112879697Snon			ncv_pio_read(sc, slp->sl_scp.scp_data, len);
112979697Snon		}
113067468Snon		break;
113167468Snon
113267468Snon	case COMMAND_PHASE: /* cmd out */
113367468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
113467468Snon		if (scsi_low_cmd(slp, ti) != 0)
113579697Snon		{
113679697Snon			scsi_low_attention(slp);
113779697Snon		}
113867468Snon
1139274760Sjhb		bus_write_1(res, cr0_cmd, CMD_FLUSH);
1140274760Sjhb		ncvhw_fpush(res,
114167468Snon			    slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen);
1142274760Sjhb		bus_write_1(res, cr0_cmd, CMD_TRANS);
114367468Snon		break;
114467468Snon
114567468Snon	case STATUS_PHASE: /* status in */
114667468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
1147274760Sjhb		bus_write_1(res, cr0_cmd, CMD_FLUSH);
1148274760Sjhb		bus_write_1(res, cr0_cmd, CMD_ICCS);
114967468Snon		sc->sc_compseq = 1;
115067468Snon		break;
115167468Snon
115267468Snon	default:
115367468Snon		break;
115467468Snon
115567468Snon	case MESSAGE_OUT_PHASE: /* msg out */
115667468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
1157274760Sjhb		bus_write_1(res, cr0_cmd, CMD_FLUSH);
115867468Snon
115979697Snon		flags = SCSI_LOW_MSGOUT_UNIFY;
116079697Snon		if (ti->ti_ophase != ti->ti_phase)
116179697Snon			flags |= SCSI_LOW_MSGOUT_INIT;
116279697Snon		len = scsi_low_msgout(slp, ti, flags);
116379697Snon
116479697Snon		if (len > 1 && slp->sl_atten == 0)
116579697Snon		{
116679697Snon			scsi_low_attention(slp);
116779697Snon		}
116879697Snon
1169274760Sjhb		ncvhw_fpush(res, ti->ti_msgoutstr, len);
1170274760Sjhb		bus_write_1(res, cr0_cmd, CMD_TRANS);
117179697Snon		SCSI_LOW_DEASSERT_ATN(slp);
117267468Snon		break;
117367468Snon
117467468Snon	case MESSAGE_IN_PHASE: /* msg in */
117567468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
117667468Snon
1177274760Sjhb		len = bus_read_1(res, cr0_sffl) & CR0_SFFLR_BMASK;
117867468Snon		if (sc->sc_compseq != 0)
117967468Snon		{
118067468Snon			sc->sc_compseq = 0;
118167468Snon			if ((ireason & INTR_FC) && len == 2)
118267468Snon			{
1183274760Sjhb				regv = bus_read_1(res, cr0_sfifo);
118479697Snon				scsi_low_statusin(slp, ti, regv | derror);
118567468Snon				len --;
118667468Snon			}
118767468Snon			else
118867468Snon			{
118979697Snon				slp->sl_error |= FATALIO;
119079697Snon				scsi_low_assert_msg(slp, ti,
119179697Snon						    SCSI_LOW_MSG_ABORT, 1);
1192274760Sjhb				bus_write_1(res, cr0_cmd, CMD_MSGOK);
119367468Snon				break;
119467468Snon			}
119567468Snon		}
119667468Snon		else if (ireason & INTR_BS)
119767468Snon		{
1198274760Sjhb			bus_write_1(res, cr0_cmd, CMD_FLUSH);
1199274760Sjhb			bus_write_1(res, cr0_cmd, CMD_TRANS);
120079697Snon			if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
120179697Snon			{
120279697Snon				if (ncv_catch_intr(sc) == 0)
120379697Snon					goto again;
120479697Snon			}
120567468Snon			break;
120667468Snon		}
120767468Snon
120867468Snon		if ((ireason & INTR_FC) && len == 1)
120967468Snon		{
1210274760Sjhb			regv = bus_read_1(res, cr0_sfifo);
121179697Snon			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
121279697Snon			{
121379697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0)
121479697Snon				{
121579697Snon					scsi_low_attention(slp);
121679697Snon				}
121779697Snon			}
1218274760Sjhb			bus_write_1(res, cr0_cmd, CMD_MSGOK);
121979697Snon			if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0)
122079697Snon			{
122179697Snon				/* XXX:
122279697Snon				 * clear a pending interrupt and sync with
122379697Snon				 * a next interrupt!
122479697Snon				 */
122579697Snon				ncv_catch_intr(sc);
122679697Snon			}
122767468Snon		}
122867468Snon		else
122967468Snon		{
123079697Snon			slp->sl_error |= FATALIO;
123179697Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
1232274760Sjhb			bus_write_1(res, cr0_cmd, CMD_MSGOK);
123367468Snon		}
123467468Snon		break;
123567468Snon	}
123667468Snon
123767468Snon	return 1;
123867468Snon}
1239