nsp.c revision 79697
167468Snon/*	$FreeBSD: head/sys/dev/nsp/nsp.c 79697 2001-07-14 00:38:51Z non $	*/
279697Snon/*	$NecBSD: nsp.c,v 1.21.12.6 2001/06/29 06:27:52 honda Exp $	*/
367468Snon/*	$NetBSD$	*/
467468Snon
567468Snon#define	NSP_DEBUG
667468Snon#define	NSP_STATICS
779697Snon#define	NSP_IO_CONTROL_FLAGS \
879697Snon	(NSP_READ_SUSPEND_IO | NSP_WRITE_SUSPEND_IO | \
979697Snon	 NSP_READ_FIFO_INTERRUPTS | NSP_WRITE_FIFO_INTERRUPTS | \
1079697Snon	 NSP_USE_MEMIO | NSP_WAIT_FOR_SELECT)
1167468Snon
1267468Snon/*
1379697Snon *  Copyright (c) 1998, 1999, 2000, 2001
1467468Snon *	NetBSD/pc98 porting staff. All rights reserved.
1579697Snon *
1679697Snon *  Copyright (c) 1998, 1999, 2000, 2001
1779697Snon *	Naofumi HONDA. All rights reserved.
1867468Snon *
1967468Snon *  Redistribution and use in source and binary forms, with or without
2067468Snon *  modification, are permitted provided that the following conditions
2167468Snon *  are met:
2267468Snon *  1. Redistributions of source code must retain the above copyright
2367468Snon *     notice, this list of conditions and the following disclaimer.
2467468Snon *  2. Redistributions in binary form must reproduce the above copyright
2567468Snon *     notice, this list of conditions and the following disclaimer in the
2667468Snon *     documentation and/or other materials provided with the distribution.
2767468Snon *  3. The name of the author may not be used to endorse or promote products
2867468Snon *     derived from this software without specific prior written permission.
2967468Snon *
3067468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
3167468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3267468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3367468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
3467468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3567468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
3667468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3767468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3867468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3967468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4067468Snon * POSSIBILITY OF SUCH DAMAGE.
4167468Snon */
4267468Snon#include "opt_ddb.h"
4367468Snon
4467468Snon#include <sys/param.h>
4567468Snon#include <sys/systm.h>
4667468Snon#include <sys/kernel.h>
4767468Snon#if defined(__FreeBSD__) && __FreeBSD_version > 500001
4867468Snon#include <sys/bio.h>
4979697Snon#endif	/* __ FreeBSD__ */
5067468Snon#include <sys/buf.h>
5167468Snon#include <sys/queue.h>
5267468Snon#include <sys/malloc.h>
5367468Snon#include <sys/errno.h>
5467468Snon
5567468Snon#ifdef __NetBSD__
5679697Snon#include <sys/device.h>
5767468Snon#include <machine/bus.h>
5867468Snon#include <machine/intr.h>
5967468Snon
6067468Snon#include <dev/scsipi/scsi_all.h>
6167468Snon#include <dev/scsipi/scsipi_all.h>
6267468Snon#include <dev/scsipi/scsiconf.h>
6367468Snon#include <dev/scsipi/scsi_disk.h>
6467468Snon
6567468Snon#include <machine/dvcfg.h>
6667468Snon#include <machine/physio_proc.h>
6767468Snon
6867468Snon#include <i386/Cbus/dev/scsi_low.h>
6967468Snon#include <i386/Cbus/dev/nspreg.h>
7067468Snon#include <i386/Cbus/dev/nspvar.h>
7167468Snon#endif /* __NetBSD__ */
7267468Snon
7367468Snon#ifdef __FreeBSD__
7467468Snon#include <machine/clock.h>
7567468Snon#include <machine/cpu.h>
7667468Snon#include <machine/bus_pio.h>
7767468Snon#include <machine/bus_memio.h>
7867468Snon#include <machine/bus.h>
7967468Snon
8067468Snon#include <machine/dvcfg.h>
8167468Snon#include <machine/physio_proc.h>
8267468Snon
8367468Snon#include <cam/scsi/scsi_low.h>
8467468Snon#include <dev/nsp/nspreg.h>
8567468Snon#include <dev/nsp/nspvar.h>
8667468Snon
8767468Snon#if __FreeBSD_version < 400001
8867468Snon#include "nsp.h"
8967468Snonstruct nsp_softc *nspdata[NNSP];
9067468Snon#endif
9167468Snon#endif /* __FreeBSD__ */
9267468Snon
9367468Snon/***************************************************
9467468Snon * USER SETTINGS
9567468Snon ***************************************************/
9667468Snon/* DEVICE CONFIGURATION FLAGS (MINOR)
9767468Snon *
9867468Snon * 0x01   DISCONECT OFF
9967468Snon * 0x02   PARITY LINE OFF
10067468Snon * 0x04   IDENTIFY MSG OFF ( = single lun)
10167468Snon * 0x08   SYNC TRANSFER OFF
10267468Snon */
10367468Snon
10467468Snon/***************************************************
10567468Snon * PARAMS
10667468Snon ***************************************************/
10767468Snon#define	NSP_NTARGETS	8
10867468Snon#define	NSP_NLUNS	8
10967468Snon
11079697Snon#define	NSP_MAX_DATA_SIZE	(64 * 1024)
11179697Snon#define	NSP_SELTIMEOUT		(200)
11279697Snon#define	NSP_DELAY_MAX		(2 * 1000 * 1000)
11379697Snon#define	NSP_DELAY_INTERVAL	(1)
11479697Snon#define	NSP_TIMER_1MS		(1000 / 51)
11567468Snon
11667468Snon/***************************************************
11767468Snon * DEBUG
11867468Snon ***************************************************/
11967468Snon#ifdef	NSP_DEBUG
12067468Snonint nsp_debug;
12167468Snon#endif	/* NSP_DEBUG */
12267468Snon
12367468Snon#ifdef	NSP_STATICS
12467468Snonstruct nsp_statics {
12579697Snon	int arbit_conflict_1;
12679697Snon	int arbit_conflict_2;
12779697Snon	int device_data_write;
12879697Snon	int device_busy;
12967468Snon	int disconnect;
13067468Snon	int reselect;
13167468Snon	int data_phase_bypass;
13279697Snon} nsp_statics;
13367468Snon#endif	/* NSP_STATICS */
13467468Snon
13567468Snon/***************************************************
13679697Snon * IO control
13767468Snon ***************************************************/
13879697Snon#define	NSP_READ_SUSPEND_IO		0x0001
13979697Snon#define	NSP_WRITE_SUSPEND_IO		0x0002
14079697Snon#define	NSP_USE_MEMIO			0x0004
14179697Snon#define	NSP_READ_FIFO_INTERRUPTS	0x0010
14279697Snon#define	NSP_WRITE_FIFO_INTERRUPTS	0x0020
14379697Snon#define	NSP_WAIT_FOR_SELECT		0x0100
14479697Snon
14579697Snonu_int nsp_io_control = NSP_IO_CONTROL_FLAGS;
14679697Snonint nsp_read_suspend_bytes = DEV_BSIZE;
14779697Snonint nsp_write_suspend_bytes = DEV_BSIZE;
14879697Snonint nsp_read_interrupt_bytes = 4096;
14979697Snonint nsp_write_interrupt_bytes = 4096;
15079697Snon
15179697Snon/***************************************************
15279697Snon * DEVICE STRUCTURE
15379697Snon ***************************************************/
15467468Snonextern struct cfdriver nsp_cd;
15567468Snon
15667468Snon/**************************************************************
15767468Snon * DECLARE
15867468Snon **************************************************************/
15979697Snon#define	NSP_FIFO_ON	1
16079697Snon#define	NSP_FIFO_OFF	0
16179697Snonstatic void nsp_pio_read __P((struct nsp_softc *, int));
16279697Snonstatic void nsp_pio_write __P((struct nsp_softc *, int));
16379697Snonstatic int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int, int));
16467468Snonstatic int nsp_msg __P((struct nsp_softc *, struct targ_info *, u_int));
16567468Snonstatic int nsp_reselected __P((struct nsp_softc *));
16679697Snonstatic int nsp_disconnected __P((struct nsp_softc *, struct targ_info *));
16779697Snonstatic void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *));
16867468Snonstatic void nsphw_init __P((struct nsp_softc *));
16979697Snonstatic int nsp_target_nexus_establish __P((struct nsp_softc *));
17079697Snonstatic int nsp_lun_nexus_establish __P((struct nsp_softc *));
17179697Snonstatic int nsp_ccb_nexus_establish __P((struct nsp_softc *));
17267468Snonstatic int nsp_world_start __P((struct nsp_softc *, int));
17367468Snonstatic int nsphw_start_selection __P((struct nsp_softc *sc, struct slccb *));
17467468Snonstatic void nsphw_bus_reset __P((struct nsp_softc *));
17567468Snonstatic void nsphw_attention __P((struct nsp_softc *));
17667468Snonstatic u_int nsp_fifo_count __P((struct nsp_softc *));
17779697Snonstatic u_int nsp_request_count __P((struct nsp_softc *));
17867468Snonstatic int nsp_negate_signal __P((struct nsp_softc *, u_int8_t, u_char *));
17967468Snonstatic int nsp_expect_signal __P((struct nsp_softc *, u_int8_t, u_int8_t));
18079697Snonstatic void nsp_start_timer __P((struct nsp_softc *, int));
18179697Snonstatic void nsp_setup_fifo __P((struct nsp_softc *, int, int, int));
18279697Snonstatic int nsp_targ_init __P((struct nsp_softc *, struct targ_info *, int));
18379697Snonstatic void nsphw_selection_done_and_expect_msgout __P((struct nsp_softc *));
18479697Snonstatic void nsp_data_padding __P((struct nsp_softc *, int, u_int));
18579697Snonstatic int nsp_timeout __P((struct nsp_softc *));
18679697Snonstatic int nsp_read_fifo __P((struct nsp_softc *, int));
18779697Snonstatic int nsp_write_fifo __P((struct nsp_softc *, int));
18879697Snonstatic int nsp_phase_match __P((struct nsp_softc *, u_int8_t, u_int8_t));
18979697Snonstatic int nsp_wait_interrupt __P((struct nsp_softc *));
19067468Snon
19167468Snonstruct scsi_low_funcs nspfuncs = {
19267468Snon	SC_LOW_INIT_T nsp_world_start,
19367468Snon	SC_LOW_BUSRST_T nsphw_bus_reset,
19473025Snon	SC_LOW_TARG_INIT_T nsp_targ_init,
19579697Snon	SC_LOW_LUN_INIT_T NULL,
19667468Snon
19767468Snon	SC_LOW_SELECT_T nsphw_start_selection,
19879697Snon	SC_LOW_NEXUS_T nsp_lun_nexus_establish,
19979697Snon	SC_LOW_NEXUS_T nsp_ccb_nexus_establish,
20067468Snon
20167468Snon	SC_LOW_ATTEN_T nsphw_attention,
20267468Snon	SC_LOW_MSG_T nsp_msg,
20367468Snon
20479697Snon	SC_LOW_TIMEOUT_T nsp_timeout,
20567468Snon	SC_LOW_POLL_T nspintr,
20667468Snon
20767468Snon	NULL,
20867468Snon};
20967468Snon
21067468Snon/****************************************************
21167468Snon * hwfuncs
21267468Snon ****************************************************/
21367468Snonstatic __inline u_int8_t nsp_cr_read_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs));
21467468Snonstatic __inline void nsp_cr_write_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs, u_int8_t va));
21567468Snon
21667468Snonstatic __inline u_int8_t
21767468Snonnsp_cr_read_1(bst, bsh, ofs)
21867468Snon	bus_space_tag_t bst;
21967468Snon	bus_space_handle_t bsh;
22067468Snon	bus_addr_t ofs;
22167468Snon{
22267468Snon
22367468Snon	bus_space_write_1(bst, bsh, nsp_idxr, ofs);
22467468Snon	return bus_space_read_1(bst, bsh, nsp_datar);
22567468Snon}
22667468Snon
22767468Snonstatic __inline void
22867468Snonnsp_cr_write_1(bst, bsh, ofs, va)
22967468Snon	bus_space_tag_t bst;
23067468Snon	bus_space_handle_t bsh;
23167468Snon	bus_addr_t ofs;
23267468Snon	u_int8_t va;
23367468Snon{
23467468Snon
23567468Snon	bus_space_write_1(bst, bsh, nsp_idxr, ofs);
23667468Snon	bus_space_write_1(bst, bsh, nsp_datar, va);
23767468Snon}
23867468Snon
23967468Snonstatic int
24067468Snonnsp_expect_signal(sc, curphase, mask)
24167468Snon	struct nsp_softc *sc;
24267468Snon	u_int8_t curphase, mask;
24367468Snon{
24467468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
24567468Snon	bus_space_tag_t bst = sc->sc_iot;
24667468Snon	bus_space_handle_t bsh = sc->sc_ioh;
24779697Snon	int wc;
24873025Snon	u_int8_t ph, isrc;
24967468Snon
25079697Snon	for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++)
25167468Snon	{
25267468Snon		ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
25379697Snon		if (ph == (u_int8_t) -1)
25479697Snon			return -1;
25579697Snon
25667468Snon		isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
25779697Snon		if (isrc & IRQSR_SCSI)
25879697Snon			return 0;
25967468Snon
26079697Snon		if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase)
26179697Snon			return 1;
26279697Snon
26379697Snon		SCSI_LOW_DELAY(NSP_DELAY_INTERVAL);
26467468Snon	}
26567468Snon
26679697Snon	printf("%s: nsp_expect_signal timeout\n", slp->sl_xname);
26779697Snon	return -1;
26867468Snon}
26967468Snon
27067468Snonstatic void
27167468Snonnsphw_init(sc)
27267468Snon	struct nsp_softc *sc;
27367468Snon{
27467468Snon	bus_space_tag_t bst = sc->sc_iot;
27567468Snon	bus_space_handle_t bsh = sc->sc_ioh;
27667468Snon
27767468Snon	/* block all interrupts */
27867468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK);
27967468Snon
28067468Snon	/* setup SCSI interface */
28167468Snon	bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_IFSEL);
28267468Snon
28367468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, 0);
28467468Snon
28567468Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8);
28667468Snon	nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_iclkdiv);
28767468Snon
28867468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
28979697Snon	nsp_cr_write_1(bst, bsh, NSPR_PARITYR, sc->sc_parr);
29067468Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR,
29167468Snon		       PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST | PTCLRR_RSS);
29267468Snon
29367468Snon	/* setup fifo asic */
29467468Snon	bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_REGSEL);
29567468Snon	nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, 0);
29667468Snon	if ((nsp_cr_read_1(bst, bsh, NSPR_OCR) & OCR_TERMPWRS) == 0)
29767468Snon		nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, TERMPWRC_POWON);
29867468Snon
29967468Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8);
30067468Snon	nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_clkdiv);
30167468Snon	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
30267468Snon	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
30367468Snon
30467468Snon	nsp_cr_write_1(bst, bsh, NSPR_SYNCR, 0);
30567468Snon	nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0);
30667468Snon
30767468Snon	/* enable interrupts and ack them */
30879697Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
30967468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
31067468Snon
31179697Snon	nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0);
31267468Snon}
31367468Snon
31467468Snon/****************************************************
31567468Snon * scsi low interface
31667468Snon ****************************************************/
31767468Snonstatic void
31867468Snonnsphw_attention(sc)
31967468Snon	struct nsp_softc *sc;
32067468Snon{
32167468Snon	bus_space_tag_t bst = sc->sc_iot;
32267468Snon	bus_space_handle_t bsh = sc->sc_ioh;
32367468Snon	u_int8_t cr;
32467468Snon
32567468Snon	cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR)/*  & ~SCBUSCR_ACK */;
32667468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ATN);
32779697Snon	SCSI_LOW_DELAY(10);
32867468Snon}
32967468Snon
33067468Snonstatic void
33167468Snonnsphw_bus_reset(sc)
33267468Snon	struct nsp_softc *sc;
33367468Snon{
33467468Snon	bus_space_tag_t bst = sc->sc_iot;
33567468Snon	bus_space_handle_t bsh = sc->sc_ioh;
33667468Snon	int i;
33767468Snon
33867468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK);
33967468Snon
34067468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST);
34179697Snon	SCSI_LOW_DELAY(100 * 1000);	/* 100ms */
34267468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0);
34367468Snon	for (i = 0; i < 5; i ++)
34467468Snon		(void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS);
34567468Snon
34667468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
34767468Snon}
34867468Snon
34979697Snonstatic void
35079697Snonnsphw_selection_done_and_expect_msgout(sc)
35171468Sjhb	struct nsp_softc *sc;
35271468Sjhb{
35379697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
35471468Sjhb	bus_space_tag_t bst = sc->sc_iot;
35571468Sjhb	bus_space_handle_t bsh = sc->sc_ioh;
35671468Sjhb
35779697Snon	/* clear ack counter */
35879697Snon	sc->sc_cnt = 0;
35979697Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
36079697Snon			PTCLRR_REQ | PTCLRR_HOST);
36179697Snon
36279697Snon	/* deassert sel and assert atten */
36379697Snon	sc->sc_seltout = 0;
36479697Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc);
36579697Snon	SCSI_LOW_DELAY(1);
36679697Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
36779697Snon			sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN);
36879697Snon	SCSI_LOW_ASSERT_ATN(slp);
36971468Sjhb}
37071468Sjhb
37167468Snonstatic int
37267468Snonnsphw_start_selection(sc, cb)
37367468Snon	struct nsp_softc *sc;
37467468Snon	struct slccb *cb;
37567468Snon{
37667468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
37767468Snon	bus_space_tag_t bst = sc->sc_iot;
37867468Snon	bus_space_handle_t bsh = sc->sc_ioh;
37967468Snon	struct targ_info *ti = cb->ti;
38067468Snon	register u_int8_t arbs, ph;
38179697Snon	int s, wc;
38267468Snon
38379697Snon	wc = sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
38479697Snon	sc->sc_dataout_timeout = 0;
38579697Snon
38667468Snon	/* check bus free */
38779697Snon	s = splhigh();
38879697Snon	ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
38979697Snon	if (ph != SCBUSMON_FREE)
39067468Snon	{
39167468Snon		splx(s);
39279697Snon#ifdef	NSP_STATICS
39379697Snon		nsp_statics.arbit_conflict_1 ++;
39479697Snon#endif	/* NSP_STATICS */
39579697Snon		return SCSI_LOW_START_FAIL;
39667468Snon	}
39767468Snon
39867468Snon	/* start arbitration */
39979697Snon	nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC);
40079697Snon	splx(s);
40179697Snon
40267468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART);
40367468Snon	do
40467468Snon	{
40567468Snon		/* XXX: what a stupid chip! */
40667468Snon		arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS);
40779697Snon		SCSI_LOW_DELAY(1);
40867468Snon	}
40973025Snon	while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && wc -- > 0);
41067468Snon
41167468Snon	if ((arbs & ARBITS_WIN) == 0)
41267468Snon	{
41367468Snon		nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
41479697Snon#ifdef	NSP_STATICS
41579697Snon		nsp_statics.arbit_conflict_2 ++;
41679697Snon#endif	/* NSP_STATICS */
41767468Snon		return SCSI_LOW_START_FAIL;
41867468Snon	}
41967468Snon
42067468Snon	/* assert select line */
42167468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
42279697Snon	scsi_low_arbit_win(slp);
42379697Snon
42479697Snon	s = splhigh();
42579697Snon	SCSI_LOW_DELAY(3);
42667468Snon	nsp_cr_write_1(bst, bsh, NSPR_DATA,
42767468Snon		       sc->sc_idbit | (1 << ti->ti_id));
42867468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
42967468Snon			SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc);
43079697Snon	SCSI_LOW_DELAY(3);
43167468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL |
43267468Snon			SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc);
43367468Snon	nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
43479697Snon	SCSI_LOW_DELAY(3);
43567468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
43667468Snon		       SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc);
43779697Snon	SCSI_LOW_DELAY(1);
43867468Snon
43979697Snon	if ((nsp_io_control & NSP_WAIT_FOR_SELECT) != 0)
44079697Snon	{
44179697Snon#define	NSP_FIRST_SEL_WAIT	300
44279697Snon#define	NSP_SEL_CHECK_INTERVAL	10
44379697Snon
44479697Snon		/* wait for a selection response */
44579697Snon		for (wc = 0; wc < NSP_FIRST_SEL_WAIT / NSP_SEL_CHECK_INTERVAL;
44679697Snon		     wc ++)
44779697Snon		{
44879697Snon			ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
44979697Snon			if ((ph & SCBUSMON_BSY) == 0)
45079697Snon			{
45179697Snon				SCSI_LOW_DELAY(NSP_SEL_CHECK_INTERVAL);
45279697Snon				continue;
45379697Snon			}
45479697Snon
45579697Snon				SCSI_LOW_DELAY(1);
45679697Snon			ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
45779697Snon			if ((ph & SCBUSMON_BSY) != 0)
45879697Snon			{
45979697Snon				nsphw_selection_done_and_expect_msgout(sc);
46079697Snon				splx(s);
46179697Snon
46279697Snon				SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
46379697Snon				return SCSI_LOW_START_OK;
46479697Snon			}
46579697Snon		}
46679697Snon	}
46779697Snon	splx(s);
46879697Snon
46979697Snon	/* check a selection timeout */
47079697Snon	nsp_start_timer(sc, NSP_TIMER_1MS);
47167468Snon	sc->sc_seltout = 1;
47267468Snon	return SCSI_LOW_START_OK;
47367468Snon}
47467468Snon
47567468Snonstatic int
47667468Snonnsp_world_start(sc, fdone)
47767468Snon	struct nsp_softc *sc;
47867468Snon	int fdone;
47967468Snon{
48067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
48167468Snon
48267468Snon	sc->sc_cnt = 0;
48367468Snon	sc->sc_seltout = 0;
48479697Snon
48567468Snon	if ((slp->sl_cfgflags & CFG_NOATTEN) == 0)
48667468Snon		sc->sc_busc = SCBUSCR_ATN;
48767468Snon	else
48867468Snon		sc->sc_busc = 0;
48979697Snon
49079697Snon	if ((slp->sl_cfgflags & CFG_NOPARITY) == 0)
49179697Snon		sc->sc_parr = PARITYR_ENABLE | PARITYR_CLEAR;
49279697Snon	else
49379697Snon		sc->sc_parr = 0;
49479697Snon
49567468Snon	sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST);
49667468Snon
49767468Snon	nsphw_init(sc);
49867468Snon	scsi_low_bus_reset(slp);
49967468Snon
50067468Snon	SOFT_INTR_REQUIRED(slp);
50167468Snon	return 0;
50267468Snon}
50367468Snon
50467468Snonstruct ncp_synch_data {
50567468Snon	u_int min_period;
50667468Snon	u_int max_period;
50767468Snon	u_int chip_period;
50867468Snon	u_int ack_width;
50967468Snon};
51067468Snon
51167468Snonstatic struct ncp_synch_data ncp_sync_data_40M[] = {
51267468Snon	{0x0c,0x0c,0x1,0},	/* 20MB  50ns*/
51367468Snon	{0x19,0x19,0x3,1}, 	/* 10MB  100ns*/
51467468Snon	{0x1a,0x25,0x5,2},	/* 7.5MB 150ns*/
51567468Snon	{0x26,0x32,0x7,3},	/* 5MB   200ns*/
51667468Snon	{0x0, 0, 0, 0}
51767468Snon};
51867468Snon
51967468Snonstatic struct ncp_synch_data ncp_sync_data_20M[] = {
52067468Snon	{0x19,0x19,0x1,0}, 	/* 10MB  100ns*/
52167468Snon	{0x1a,0x25,0x2,0},	/* 7.5MB 150ns*/
52267468Snon	{0x26,0x32,0x3,1},	/* 5MB   200ns*/
52367468Snon	{0x0, 0, 0, 0}
52467468Snon};
52567468Snon
52667468Snonstatic int
52767468Snonnsp_msg(sc, ti, msg)
52867468Snon	struct nsp_softc *sc;
52967468Snon	struct targ_info *ti;
53067468Snon	u_int msg;
53167468Snon{
53279697Snon	bus_space_tag_t bst = sc->sc_iot;
53379697Snon	bus_space_handle_t bsh = sc->sc_ioh;
53467468Snon	struct ncp_synch_data *sdp;
53573025Snon	struct nsp_targ_info *nti = (void *) ti;
53667468Snon	u_int period, offset;
53779697Snon	int i, error;
53867468Snon
53979697Snon	if ((msg & SCSI_LOW_MSG_WIDE) != 0)
54079697Snon	{
54179697Snon		if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8)
54279697Snon		{
54379697Snon			ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
54479697Snon			return EINVAL;
54579697Snon		}
54679697Snon		return 0;
54779697Snon	}
54879697Snon
54967468Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
55067468Snon		return 0;
55167468Snon
55273025Snon	period = ti->ti_maxsynch.period;
55373025Snon	offset = ti->ti_maxsynch.offset;
55467468Snon	if (sc->sc_iclkdiv == CLKDIVR_20M)
55567468Snon		sdp = &ncp_sync_data_20M[0];
55667468Snon	else
55767468Snon		sdp = &ncp_sync_data_40M[0];
55867468Snon
55967468Snon	for (i = 0; sdp->max_period != 0; i ++, sdp ++)
56067468Snon	{
56167468Snon		if (period >= sdp->min_period && period <= sdp->max_period)
56267468Snon			break;
56367468Snon	}
56467468Snon
56567468Snon	if (period != 0 && sdp->max_period == 0)
56667468Snon	{
56767468Snon		/*
56867468Snon		 * NO proper period/offset found,
56967468Snon		 * Retry neg with the target.
57067468Snon		 */
57173025Snon		ti->ti_maxsynch.period = 0;
57273025Snon		ti->ti_maxsynch.offset = 0;
57373025Snon		nti->nti_reg_syncr = 0;
57473025Snon		nti->nti_reg_ackwidth = 0;
57579697Snon		error = EINVAL;
57667468Snon	}
57779697Snon	else
57879697Snon	{
57979697Snon		nti->nti_reg_syncr = (sdp->chip_period << SYNCR_PERS) |
58079697Snon				      (offset & SYNCR_OFFM);
58179697Snon		nti->nti_reg_ackwidth = sdp->ack_width;
58279697Snon		error = 0;
58379697Snon	}
58467468Snon
58579697Snon	nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr);
58679697Snon	nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth);
58779697Snon	return error;
58867468Snon}
58967468Snon
59067468Snonstatic int
59179697Snonnsp_targ_init(sc, ti, action)
59267468Snon	struct nsp_softc *sc;
59367468Snon	struct targ_info *ti;
59479697Snon	int action;
59567468Snon{
59673025Snon	struct nsp_targ_info *nti = (void *) ti;
59767468Snon
59879697Snon	if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE)
59979697Snon	{
60079697Snon		ti->ti_width = SCSI_LOW_BUS_WIDTH_8;
60179697Snon		ti->ti_maxsynch.period = 100 / 4;
60279697Snon		ti->ti_maxsynch.offset = 15;
60379697Snon		nti->nti_reg_syncr = 0;
60479697Snon		nti->nti_reg_ackwidth = 0;
60579697Snon	}
60667468Snon	return 0;
60767468Snon}
60867468Snon
60979697Snonstatic void
61079697Snonnsp_start_timer(sc, time)
61179697Snon	struct nsp_softc *sc;
61279697Snon	int time;
61379697Snon{
61479697Snon	bus_space_tag_t bst = sc->sc_iot;
61579697Snon	bus_space_handle_t bsh = sc->sc_ioh;
61679697Snon
61779697Snon	sc->sc_timer = time;
61879697Snon	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time);
61979697Snon}
62079697Snon
62167468Snon/**************************************************************
62267468Snon * General probe attach
62367468Snon **************************************************************/
62467468Snonint
62567468Snonnspprobesubr(iot, ioh, dvcfg)
62667468Snon	bus_space_tag_t iot;
62767468Snon	bus_space_handle_t ioh;
62867468Snon	u_int dvcfg;
62967468Snon{
63067468Snon	u_int8_t regv;
63167468Snon
63267468Snon	regv = bus_space_read_1(iot, ioh, nsp_fifosr);
63367468Snon	if (regv < 0x11 || regv >= 0x20)
63467468Snon		return 0;
63567468Snon	return 1;
63667468Snon}
63767468Snon
63867468Snonint
63967468Snonnspprint(aux, name)
64067468Snon	void *aux;
64167468Snon	const char *name;
64267468Snon{
64367468Snon
64467468Snon	if (name != NULL)
64567468Snon		printf("%s: scsibus ", name);
64667468Snon	return UNCONF;
64767468Snon}
64867468Snon
64967468Snonvoid
65067468Snonnspattachsubr(sc)
65167468Snon	struct nsp_softc *sc;
65267468Snon{
65367468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
65467468Snon
65567468Snon	printf("\n");
65667468Snon
65767468Snon	sc->sc_idbit = (1 << slp->sl_hostid);
65879697Snon	slp->sl_flags |= HW_READ_PADDING;
65967468Snon	slp->sl_funcs = &nspfuncs;
66079697Snon	sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */
66167468Snon
66279697Snon	(void) scsi_low_attach(slp, 0, NSP_NTARGETS, NSP_NLUNS,
66379697Snon			       sizeof(struct nsp_targ_info), 0);
66467468Snon}
66567468Snon
66667468Snon/**************************************************************
66767468Snon * PDMA functions
66867468Snon **************************************************************/
66967468Snonstatic u_int
67067468Snonnsp_fifo_count(sc)
67167468Snon	struct nsp_softc *sc;
67267468Snon{
67367468Snon	bus_space_tag_t bst = sc->sc_iot;
67467468Snon	bus_space_handle_t bsh = sc->sc_ioh;
67567468Snon	u_int count;
67667468Snon
67779697Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_ACK | PTCLRR_PT);
67867468Snon	count = bus_space_read_1(bst, bsh, nsp_datar);
67967468Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8);
68067468Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16);
68167468Snon	return count;
68267468Snon}
68367468Snon
68479697Snonstatic u_int
68579697Snonnsp_request_count(sc)
68679697Snon	struct nsp_softc *sc;
68779697Snon{
68879697Snon	bus_space_tag_t bst = sc->sc_iot;
68979697Snon	bus_space_handle_t bsh = sc->sc_ioh;
69079697Snon	u_int count;
69179697Snon
69279697Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_RSS_REQ | PTCLRR_PT);
69379697Snon	count = bus_space_read_1(bst, bsh, nsp_datar);
69479697Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8);
69579697Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16);
69679697Snon	return count;
69779697Snon}
69879697Snon
69967468Snonstatic void
70079697Snonnsp_setup_fifo(sc, on, direction, datalen)
70167468Snon	struct nsp_softc *sc;
70267468Snon	int on;
70379697Snon	int direction;
70479697Snon	int datalen;
70567468Snon{
70667468Snon	u_int8_t xfermode;
70767468Snon
70879697Snon	sc->sc_suspendio = 0;
70979697Snon	if (on == NSP_FIFO_OFF)
71079697Snon	{
71179697Snon		xfermode = XFERMR_IO8;
71279697Snon		goto out;
71379697Snon	}
71467468Snon
71579697Snon	/* check if suspend io OK ? */
71679697Snon	if (datalen > 0)
71767468Snon	{
71879697Snon		if (direction == SCSI_LOW_READ)
71979697Snon		{
72079697Snon			if ((nsp_io_control & NSP_READ_SUSPEND_IO) != 0 &&
72179697Snon			    (datalen % nsp_read_suspend_bytes) == 0)
72279697Snon				sc->sc_suspendio = nsp_read_suspend_bytes;
72379697Snon		}
72479697Snon		else
72579697Snon		{
72679697Snon			if ((nsp_io_control & NSP_WRITE_SUSPEND_IO) != 0 &&
72779697Snon			    (datalen % nsp_write_suspend_bytes) == 0)
72879697Snon				sc->sc_suspendio = nsp_write_suspend_bytes;
72979697Snon		}
73067468Snon	}
73179697Snon
73279697Snon	/* determine a transfer type */
73379697Snon	if (datalen < DEV_BSIZE || (datalen & 3) != 0)
73479697Snon	{
73579697Snon		if (sc->sc_memh != NULL &&
73679697Snon		    (nsp_io_control & NSP_USE_MEMIO) != 0)
73779697Snon			xfermode = XFERMR_XEN | XFERMR_MEM8;
73879697Snon		else
73979697Snon			xfermode = XFERMR_XEN | XFERMR_IO8;
74079697Snon	}
74167468Snon	else
74267468Snon	{
74379697Snon		if (sc->sc_memh != NULL &&
74479697Snon		    (nsp_io_control & NSP_USE_MEMIO) != 0)
74579697Snon			xfermode = XFERMR_XEN | XFERMR_MEM32;
74667468Snon		else
74779697Snon			xfermode = XFERMR_XEN | XFERMR_IO32;
74879697Snon
74979697Snon		if (sc->sc_suspendio > 0)
75079697Snon			xfermode |= XFERMR_FIFOEN;
75167468Snon	}
75267468Snon
75379697Snonout:
75467468Snon	sc->sc_xfermr = xfermode;
75579697Snon	nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_XFERMR, sc->sc_xfermr);
75667468Snon}
75767468Snon
75879697Snonstatic void
75967468Snonnsp_pdma_end(sc, ti)
76067468Snon	struct nsp_softc *sc;
76167468Snon	struct targ_info *ti;
76267468Snon{
76367468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
76479697Snon	struct slccb *cb = slp->sl_Qnexus;
76567468Snon	u_int len = 0, cnt;
76667468Snon
76779697Snon	sc->sc_dataout_timeout = 0;
76867468Snon	slp->sl_flags &= ~HW_PDMASTART;
76979697Snon	nsp_setup_fifo(sc, NSP_FIFO_OFF, SCSI_LOW_READ, 0);
77079697Snon	if ((sc->sc_icr & SCIENR_FIFO) != 0)
77179697Snon	{
77279697Snon		sc->sc_icr &= ~SCIENR_FIFO;
77379697Snon		nsp_cr_write_1(sc->sc_iot, sc->sc_ioh, NSPR_SCIENR, sc->sc_icr);
77479697Snon	}
77567468Snon
77679697Snon	if (cb == NULL)
77779697Snon	{
77879697Snon		slp->sl_error |= PDMAERR;
77979697Snon		return;
78079697Snon	}
78179697Snon
78267468Snon	if (ti->ti_phase == PH_DATA)
78367468Snon	{
78467468Snon		cnt = nsp_fifo_count(sc);
78567468Snon		if (slp->sl_scp.scp_direction  == SCSI_LOW_WRITE)
78667468Snon		{
78767468Snon			len = sc->sc_cnt - cnt;
78879697Snon			if (sc->sc_cnt >= cnt &&
78979697Snon			    slp->sl_scp.scp_datalen + len <=
79067468Snon			    cb->ccb_scp.scp_datalen)
79167468Snon			{
79267468Snon				slp->sl_scp.scp_data -= len;
79367468Snon				slp->sl_scp.scp_datalen += len;
79467468Snon			}
79567468Snon			else
79667468Snon			{
79767468Snon				slp->sl_error |= PDMAERR;
79867468Snon				printf("%s len %x >= datalen %x\n",
79967468Snon					slp->sl_xname,
80067468Snon					len, slp->sl_scp.scp_datalen);
80167468Snon			}
80267468Snon		}
80367468Snon		else if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
80467468Snon		{
80579697Snon			if (sc->sc_cnt != cnt ||
80679697Snon			    sc->sc_cnt > cb->ccb_scp.scp_datalen)
80767468Snon			{
80867468Snon				slp->sl_error |= PDMAERR;
80979697Snon				printf("%s: data read count error %x != %x (%x)\n",
81079697Snon					slp->sl_xname, sc->sc_cnt, cnt,
81179697Snon					cb->ccb_scp.scp_datalen);
81267468Snon			}
81367468Snon		}
81467468Snon		sc->sc_cnt = cnt;
81579697Snon		scsi_low_data_finish(slp);
81667468Snon	}
81767468Snon	else
81867468Snon	{
81967468Snon
82067468Snon		printf("%s data phase miss\n", slp->sl_xname);
82167468Snon		slp->sl_error |= PDMAERR;
82267468Snon	}
82367468Snon}
82467468Snon
82567468Snon#define	RFIFO_CRIT	64
82679697Snon#define	WFIFO_CRIT	32
82767468Snon
82867468Snonstatic void
82979697Snonnsp_data_padding(sc, direction, count)
83067468Snon	struct nsp_softc *sc;
83179697Snon	int direction;
83279697Snon	u_int count;
83367468Snon{
83479697Snon	bus_space_tag_t bst = sc->sc_iot;
83579697Snon	bus_space_handle_t bsh = sc->sc_ioh;
83679697Snon
83779697Snon	if (count > NSP_MAX_DATA_SIZE)
83879697Snon		count = NSP_MAX_DATA_SIZE;
83979697Snon
84079697Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_XEN | XFERMR_IO8);
84179697Snon	if (direction == SCSI_LOW_READ)
84279697Snon	{
84379697Snon		while (count -- > 0)
84479697Snon			(void) bus_space_read_1(bst, bsh, nsp_fifodr);
84579697Snon	}
84679697Snon	else
84779697Snon	{
84879697Snon		while (count -- > 0)
84979697Snon			(void) bus_space_write_1(bst, bsh, nsp_fifodr, 0);
85079697Snon	}
85179697Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr);
85279697Snon}
85379697Snon
85479697Snonstatic int
85579697Snonnsp_read_fifo(sc, suspendio)
85679697Snon	struct nsp_softc *sc;
85779697Snon	int suspendio;
85879697Snon{
85967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
86067468Snon	bus_space_tag_t bst = sc->sc_iot;
86167468Snon	bus_space_handle_t bsh = sc->sc_ioh;
86279697Snon	u_int res;
86367468Snon
86479697Snon	res = nsp_fifo_count(sc);
86579697Snon	if (res == sc->sc_cnt)
86679697Snon		return 0;
86767468Snon
86879697Snon#ifdef	NSP_DEBUG
86979697Snon	if (res < sc->sc_cnt || res == (u_int) -1)
87067468Snon	{
87179697Snon		printf("%s: strange fifo ack count 0x%x < 0x%x\n",
87279697Snon			slp->sl_xname, res, sc->sc_cnt);
87379697Snon		return 0;
87479697Snon	}
87579697Snon#endif	/* NSP_DEBUG */
87679697Snon
87779697Snon	res = res - sc->sc_cnt;
87879697Snon	if (res > slp->sl_scp.scp_datalen)
87979697Snon	{
88079697Snon		if ((slp->sl_error & PDMAERR) == 0)
88179697Snon		{
88279697Snon			printf("%s: data overrun 0x%x > 0x%x\n",
88379697Snon				slp->sl_xname, res, slp->sl_scp.scp_datalen);
88479697Snon		}
88579697Snon
88679697Snon		slp->sl_error |= PDMAERR;
88779697Snon		slp->sl_scp.scp_datalen = 0;
88879697Snon
88979697Snon		if ((slp->sl_flags & HW_READ_PADDING) == 0)
89079697Snon		{
89179697Snon			printf("%s: read padding required\n", slp->sl_xname);
89279697Snon			return 0;
89379697Snon		}
89479697Snon
89579697Snon		nsp_data_padding(sc, SCSI_LOW_READ, res);
89679697Snon		sc->sc_cnt += res;
89779697Snon		return 1;	/* padding start */
89879697Snon	}
89979697Snon
90079697Snon	if (suspendio > 0 && slp->sl_scp.scp_datalen >= suspendio)
90179697Snon		res = suspendio;
90279697Snon
90379697Snon	if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0)
90479697Snon	{
90579697Snon		if ((sc->sc_xfermr & XFERMR_MEM32) != 0)
90679697Snon		{
90779697Snon			res &= ~3;
90879697Snon			bus_space_read_region_4(sc->sc_memt, sc->sc_memh, 0,
90979697Snon				(u_int32_t *) slp->sl_scp.scp_data, res >> 2);
91079697Snon		}
91179697Snon		else
91279697Snon		{
91379697Snon			bus_space_read_region_1(sc->sc_memt, sc->sc_memh, 0,
91479697Snon				(u_int8_t *) slp->sl_scp.scp_data, res);
91579697Snon		}
91679697Snon	}
91779697Snon	else
91879697Snon	{
91979697Snon		if ((sc->sc_xfermr & XFERMR_IO32) != 0)
92079697Snon		{
92179697Snon			res &= ~3;
92279697Snon			bus_space_read_multi_4(bst, bsh, nsp_fifodr,
92379697Snon				(u_int32_t *) slp->sl_scp.scp_data, res >> 2);
92479697Snon		}
92579697Snon		else
92679697Snon		{
92779697Snon			bus_space_read_multi_1(bst, bsh, nsp_fifodr,
92879697Snon				(u_int8_t *) slp->sl_scp.scp_data, res);
92979697Snon		}
93079697Snon	}
93179697Snon
93279697Snon	if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
93379697Snon	{
93479697Snon		nsp_cr_write_1(bst, bsh, NSPR_PARITYR,
93579697Snon			       PARITYR_ENABLE | PARITYR_CLEAR);
93679697Snon		scsi_low_assert_msg(slp, slp->sl_Tnexus, SCSI_LOW_MSG_ERROR, 1);
93779697Snon	}
93879697Snon
93979697Snon	slp->sl_scp.scp_data += res;
94079697Snon	slp->sl_scp.scp_datalen -= res;
94179697Snon	sc->sc_cnt += res;
94279697Snon	return 0;
94379697Snon}
94479697Snon
94579697Snonstatic int
94679697Snonnsp_write_fifo(sc, suspendio)
94779697Snon	struct nsp_softc *sc;
94879697Snon	int suspendio;
94979697Snon{
95079697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
95179697Snon	bus_space_tag_t bst = sc->sc_iot;
95279697Snon	bus_space_handle_t bsh = sc->sc_ioh;
95379697Snon	u_int res;
95479697Snon	register u_int8_t stat;
95579697Snon
95679697Snon	if (suspendio > 0)
95779697Snon	{
95879697Snon#ifdef	NSP_DEBUG
95979697Snon		if ((slp->sl_scp.scp_datalen % WFIFO_CRIT) != 0)
96079697Snon		{
96179697Snon			printf("%s: strange write length 0x%x\n",
96279697Snon				slp->sl_xname, slp->sl_scp.scp_datalen);
96379697Snon		}
96479697Snon#endif	/* NSP_DEBUG */
96579697Snon		res = slp->sl_scp.scp_datalen % suspendio;
96667468Snon		if (res == 0)
96767468Snon		{
96879697Snon			res = suspendio;
96967468Snon		}
97079697Snon	}
97179697Snon	else
97279697Snon	{
97379697Snon		res = WFIFO_CRIT;
97479697Snon	}
97567468Snon
97679697Snon	if (res > slp->sl_scp.scp_datalen)
97779697Snon		res = slp->sl_scp.scp_datalen;
97867468Snon
97979697Snon	/* XXX: reconfirm! */
98079697Snon	stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK;
98179697Snon	if (stat != PHASE_DATAOUT)
98279697Snon		return 0;
98367468Snon
98479697Snon	if ((sc->sc_xfermr & (XFERMR_MEM32 | XFERMR_MEM8)) != 0)
98579697Snon	{
98679697Snon		if ((sc->sc_xfermr & XFERMR_MEM32) != 0)
98779697Snon		{
98879697Snon			bus_space_write_region_4(sc->sc_memt, sc->sc_memh, 0,
98979697Snon				(u_int32_t *) slp->sl_scp.scp_data, res >> 2);
99079697Snon		}
99167468Snon		else
99279697Snon		{
99379697Snon			bus_space_write_region_1(sc->sc_memt, sc->sc_memh, 0,
99479697Snon				(u_int8_t *) slp->sl_scp.scp_data, res);
99579697Snon		}
99679697Snon	}
99779697Snon	else
99879697Snon	{
99979697Snon		if ((sc->sc_xfermr & XFERMR_IO32) != 0)
100079697Snon		{
100179697Snon			bus_space_write_multi_4(bst, bsh, nsp_fifodr,
100279697Snon				(u_int32_t *) slp->sl_scp.scp_data, res >> 2);
100379697Snon		}
100479697Snon		else
100579697Snon		{
100679697Snon			bus_space_write_multi_1(bst, bsh, nsp_fifodr,
100779697Snon				(u_int8_t *) slp->sl_scp.scp_data, res);
100879697Snon		}
100979697Snon	}
101067468Snon
101179697Snon	slp->sl_scp.scp_datalen -= res;
101279697Snon	slp->sl_scp.scp_data += res;
101379697Snon	sc->sc_cnt += res;
101479697Snon	return 0;
101579697Snon}
101679697Snon
101779697Snonstatic int
101879697Snonnsp_wait_interrupt(sc)
101979697Snon	struct nsp_softc *sc;
102079697Snon{
102179697Snon	bus_space_tag_t bst = sc->sc_iot;
102279697Snon	bus_space_handle_t bsh = sc->sc_ioh;
102379697Snon	int tout;
102479697Snon	register u_int8_t isrc;
102579697Snon
102679697Snon	for (tout = 0; tout < DEV_BSIZE / 10; tout ++)
102779697Snon	{
102879697Snon		isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
102979697Snon		if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) != 0)
103067468Snon		{
103179697Snon			if ((isrc & IRQSR_FIFO) != 0)
103279697Snon			{
103379697Snon				bus_space_write_1(bst, bsh,
103479697Snon					nsp_irqcr, IRQCR_FIFOCL);
103579697Snon			}
103679697Snon			return 1;
103767468Snon		}
103879697Snon		SCSI_LOW_DELAY(1);
103979697Snon	}
104079697Snon	return 0;
104179697Snon}
104279697Snon
104379697Snonstatic void
104479697Snonnsp_pio_read(sc, suspendio)
104579697Snon	struct nsp_softc *sc;
104679697Snon	int suspendio;
104779697Snon{
104879697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
104979697Snon	bus_space_tag_t bst = sc->sc_iot;
105079697Snon	bus_space_handle_t bsh = sc->sc_ioh;
105179697Snon	int tout, padding, datalen;
105279697Snon	register u_int8_t stat, fstat;
105379697Snon
105479697Snon	padding = 0;
105579697Snon	tout = sc->sc_tmaxcnt;
105679697Snon	slp->sl_flags |= HW_PDMASTART;
105779697Snon	datalen = slp->sl_scp.scp_datalen;
105879697Snon
105979697SnonReadLoop:
106079697Snon	while (1)
106179697Snon	{
106279697Snon		stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
106379697Snon		if (stat == (u_int8_t) -1)
106479697Snon			return;
106579697Snon
106679697Snon		/* out of data phase */
106779697Snon		if ((stat & SCBUSMON_PHMASK) != PHASE_DATAIN)
106879697Snon		{
106979697Snon			nsp_read_fifo(sc, 0);
107079697Snon			return;
107179697Snon		}
107279697Snon
107379697Snon		/* data phase */
107479697Snon		fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
107579697Snon		if ((fstat & FIFOSR_FULLEMP) != 0)
107679697Snon		{
107779697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
107879697Snon			{
107979697Snon				bus_space_write_1(bst, bsh, nsp_irqcr,
108079697Snon						  IRQCR_FIFOCL);
108179697Snon			}
108279697Snon
108379697Snon			if (suspendio > 0)
108479697Snon			{
108579697Snon				padding |= nsp_read_fifo(sc, suspendio);
108679697Snon			}
108779697Snon			else
108879697Snon			{
108979697Snon				padding |= nsp_read_fifo(sc, 0);
109079697Snon			}
109179697Snon
109279697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
109379697Snon				break;
109479697Snon		}
109567468Snon		else
109667468Snon		{
109779697Snon			if (padding == 0 && slp->sl_scp.scp_datalen <= 0)
109879697Snon				return;
109979697Snon
110079697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
110179697Snon				break;
110279697Snon
110379697Snon			SCSI_LOW_DELAY(1);
110467468Snon		}
110567468Snon
110679697Snon		if ((-- tout) <= 0)
110779697Snon		{
110879697Snon			printf("%s: nsp_pio_read: timeout\n", slp->sl_xname);
110979697Snon			return;
111079697Snon		}
111167468Snon	}
111267468Snon
111379697Snon
111479697Snon	if (slp->sl_scp.scp_datalen > 0 &&
111579697Snon	    slp->sl_scp.scp_datalen > datalen - nsp_read_interrupt_bytes)
111679697Snon	{
111779697Snon		if (nsp_wait_interrupt(sc) != 0)
111879697Snon			goto ReadLoop;
111979697Snon	}
112067468Snon}
112167468Snon
112267468Snonstatic void
112379697Snonnsp_pio_write(sc, suspendio)
112467468Snon	struct nsp_softc *sc;
112579697Snon	int suspendio;
112667468Snon{
112767468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
112867468Snon	bus_space_tag_t bst = sc->sc_iot;
112967468Snon	bus_space_handle_t bsh = sc->sc_ioh;
113079697Snon	u_int rcount, acount;
113179697Snon	int tout, datalen;
113279697Snon	register u_int8_t stat, fstat;
113367468Snon
113479697Snon	tout = sc->sc_tmaxcnt;
113567468Snon	slp->sl_flags |= HW_PDMASTART;
113679697Snon	datalen = slp->sl_scp.scp_datalen;
113779697Snon
113879697SnonWriteLoop:
113979697Snon	while (1)
114067468Snon	{
114179697Snon		stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON) & SCBUSMON_PHMASK;
114267468Snon		if (stat != PHASE_DATAOUT)
114379697Snon			return;
114467468Snon
114579697Snon		if (slp->sl_scp.scp_datalen <= 0)
114679697Snon		{
114779697Snon			if (sc->sc_dataout_timeout == 0)
114879697Snon				sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
114979697Snon			return;
115079697Snon		}
115167468Snon
115279697Snon		fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
115379697Snon		if ((fstat & FIFOSR_FULLEMP) != 0)
115479697Snon		{
115579697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
115679697Snon			{
115779697Snon				bus_space_write_1(bst, bsh, nsp_irqcr,
115879697Snon						  IRQCR_FIFOCL);
115979697Snon			}
116067468Snon
116179697Snon			if (suspendio > 0)
116279697Snon			{
116379697Snon				/* XXX:IMPORTANT:
116479697Snon				 * To avoid timeout of pcmcia bus
116579697Snon				 * (not scsi bus!), we should check
116679697Snon				 * the scsi device sends us request
116779697Snon				 * signals, which means the scsi device
116879697Snon				 * is ready to recieve data without
116979697Snon				 * heavy delays.
117079697Snon				 */
117179697Snon				acount = nsp_fifo_count(sc);
117279697Snon				rcount = nsp_request_count(sc);
117379697Snon				if (rcount <= acount)
117479697Snon				{
117579697Snon					nsp_write_fifo(sc, 0);
117679697Snon#ifdef	NSP_STATICS
117779697Snon					nsp_statics.device_busy ++;
117879697Snon#endif	/* NSP_STATICS */
117979697Snon				}
118079697Snon				else
118179697Snon				{
118279697Snon					nsp_write_fifo(sc, suspendio);
118379697Snon#ifdef	NSP_STATICS
118479697Snon					nsp_statics.device_data_write ++;
118579697Snon#endif	/* NSP_STATICS */
118679697Snon				}
118779697Snon			}
118879697Snon			else
118979697Snon			{
119079697Snon				nsp_write_fifo(sc, 0);
119179697Snon			}
119279697Snon
119379697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
119479697Snon				break;
119567468Snon		}
119667468Snon		else
119767468Snon		{
119879697Snon			if ((sc->sc_icr & SCIENR_FIFO) != 0)
119979697Snon				break;
120079697Snon
120179697Snon			SCSI_LOW_DELAY(1);
120267468Snon		}
120367468Snon
120479697Snon		if ((-- tout) <= 0)
120579697Snon		{
120679697Snon			printf("%s: nsp_pio_write: timeout\n", slp->sl_xname);
120779697Snon			return;
120879697Snon		}
120967468Snon	}
121067468Snon
121179697Snon	if (slp->sl_scp.scp_datalen > 0 &&
121279697Snon	    slp->sl_scp.scp_datalen > datalen - nsp_write_interrupt_bytes)
121379697Snon	{
121479697Snon		if (nsp_wait_interrupt(sc) != 0)
121579697Snon			goto WriteLoop;
121679697Snon	}
121767468Snon}
121867468Snon
121967468Snonstatic int
122067468Snonnsp_negate_signal(sc, mask, s)
122167468Snon	struct nsp_softc *sc;
122267468Snon	u_int8_t mask;
122367468Snon	u_char *s;
122467468Snon{
122567468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
122667468Snon	bus_space_tag_t bst = sc->sc_iot;
122767468Snon	bus_space_handle_t bsh = sc->sc_ioh;
122879697Snon	int wc;
122967468Snon	u_int8_t regv;
123067468Snon
123179697Snon	for (wc = 0; wc < NSP_DELAY_MAX / NSP_DELAY_INTERVAL; wc ++)
123267468Snon	{
123367468Snon		regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
123479697Snon		if (regv == (u_int8_t) -1)
123579697Snon			return -1;
123679697Snon		if ((regv & mask) == 0)
123779697Snon			return 1;
123879697Snon		SCSI_LOW_DELAY(NSP_DELAY_INTERVAL);
123967468Snon	}
124067468Snon
124179697Snon	printf("%s: %s nsp_negate_signal timeout\n", slp->sl_xname, s);
124279697Snon	return -1;
124367468Snon}
124467468Snon
124567468Snonstatic int
124679697Snonnsp_xfer(sc, buf, len, phase, clear_atn)
124767468Snon	struct nsp_softc *sc;
124867468Snon	u_int8_t *buf;
124967468Snon	int len;
125067468Snon	int phase;
125179697Snon	int clear_atn;
125267468Snon{
125367468Snon	bus_space_tag_t bst = sc->sc_iot;
125467468Snon	bus_space_handle_t bsh = sc->sc_ioh;
125579697Snon	int ptr, rv;
125667468Snon
125767468Snon	for (ptr = 0; len > 0; len --, ptr ++)
125867468Snon	{
125967468Snon		rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ);
126067468Snon		if (rv <= 0)
126167468Snon			goto out;
126267468Snon
126379697Snon		if (len == 1 && clear_atn != 0)
126467468Snon		{
126567468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
126667468Snon				       SCBUSCR_ADIR | SCBUSCR_ACKEN);
126779697Snon			SCSI_LOW_DEASSERT_ATN(&sc->sc_sclow);
126867468Snon		}
126967468Snon
127067468Snon		if (phase & SCBUSMON_IO)
127167468Snon		{
127267468Snon			buf[ptr] = nsp_cr_read_1(bst, bsh, NSPR_DATAACK);
127367468Snon		}
127467468Snon		else
127567468Snon		{
127667468Snon			nsp_cr_write_1(bst, bsh, NSPR_DATAACK, buf[ptr]);
127767468Snon		}
127867468Snon		nsp_negate_signal(sc, SCBUSMON_ACK, "xfer<ACK>");
127967468Snon	}
128067468Snon
128167468Snonout:
128267468Snon	return len;
128367468Snon}
128467468Snon
128567468Snon/**************************************************************
128667468Snon * disconnect & reselect (HW low)
128767468Snon **************************************************************/
128867468Snonstatic int
128967468Snonnsp_reselected(sc)
129067468Snon	struct nsp_softc *sc;
129167468Snon{
129267468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
129367468Snon	bus_space_tag_t bst = sc->sc_iot;
129467468Snon	bus_space_handle_t bsh = sc->sc_ioh;
129567468Snon	struct targ_info *ti;
129667468Snon	u_int sid;
129767468Snon	u_int8_t cr;
129867468Snon
129967468Snon	sid = (u_int) nsp_cr_read_1(bst, bsh, NSPR_RESELR);
130067468Snon	sid &= ~sc->sc_idbit;
130167468Snon	sid = ffs(sid) - 1;
130267468Snon	if ((ti = scsi_low_reselected(slp, sid)) == NULL)
130367468Snon		return EJUSTRETURN;
130467468Snon
130567468Snon	nsp_negate_signal(sc, SCBUSMON_SEL, "reselect<SEL>");
130667468Snon
130779697Snon	cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
130879697Snon	cr &= ~(SCBUSCR_BSY | SCBUSCR_ATN);
130967468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
131079697Snon	cr |= SCBUSCR_ADIR | SCBUSCR_ACKEN;
131179697Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
131267468Snon
131367468Snon#ifdef	NSP_STATICS
131479697Snon	nsp_statics.reselect ++;
131567468Snon#endif	/* NSP_STATCIS */
131667468Snon	return EJUSTRETURN;
131767468Snon}
131867468Snon
131979697Snonstatic int
132067468Snonnsp_disconnected(sc, ti)
132167468Snon	struct nsp_softc *sc;
132267468Snon	struct targ_info *ti;
132367468Snon{
132467468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
132579697Snon	bus_space_tag_t bst = sc->sc_iot;
132679697Snon	bus_space_handle_t bsh = sc->sc_ioh;
132767468Snon
132879697Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
132979697Snon			PTCLRR_REQ | PTCLRR_HOST);
133079697Snon	if ((sc->sc_icr & SCIENR_FIFO) != 0)
133179697Snon	{
133279697Snon		sc->sc_icr &= ~SCIENR_FIFO;
133379697Snon		nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
133479697Snon	}
133579697Snon	sc->sc_cnt = 0;
133679697Snon	sc->sc_dataout_timeout = 0;
133767468Snon#ifdef	NSP_STATICS
133879697Snon	nsp_statics.disconnect ++;
133967468Snon#endif	/* NSP_STATICS */
134067468Snon	scsi_low_disconnected(slp, ti);
134167468Snon	return 1;
134267468Snon}
134367468Snon
134467468Snon/**************************************************************
134567468Snon * SEQUENCER
134667468Snon **************************************************************/
134779697Snonstatic void nsp_error __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t));
134867468Snon
134967468Snonstatic void
135079697Snonnsp_error(sc, s, isrc, ph, irqphs)
135167468Snon	struct nsp_softc *sc;
135267468Snon	u_char *s;
135367468Snon	u_int8_t isrc, ph, irqphs;
135467468Snon{
135567468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
135667468Snon
135767468Snon	printf("%s: %s\n", slp->sl_xname, s);
135867468Snon	printf("%s: isrc 0x%x scmon 0x%x irqphs 0x%x\n",
135967468Snon	       slp->sl_xname, (u_int) isrc, (u_int) ph, (u_int) irqphs);
136067468Snon}
136167468Snon
136267468Snonstatic int
136379697Snonnsp_target_nexus_establish(sc)
136467468Snon	struct nsp_softc *sc;
136567468Snon{
136679697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
136767468Snon	bus_space_tag_t bst = sc->sc_iot;
136867468Snon	bus_space_handle_t bsh = sc->sc_ioh;
136979697Snon	struct targ_info *ti = slp->sl_Tnexus;
137073025Snon	struct nsp_targ_info *nti = (void *) ti;
137167468Snon
137267468Snon	/* setup synch transfer registers */
137373025Snon	nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nti->nti_reg_syncr);
137473025Snon	nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nti->nti_reg_ackwidth);
137567468Snon
137679697Snon	/* setup pdma fifo (minimum) */
137779697Snon	nsp_setup_fifo(sc, NSP_FIFO_ON, SCSI_LOW_READ, 0);
137879697Snon	return 0;
137979697Snon}
138079697Snon
138179697Snonstatic int
138279697Snonnsp_lun_nexus_establish(sc)
138379697Snon	struct nsp_softc *sc;
138479697Snon{
138579697Snon
138679697Snon	return 0;
138779697Snon}
138879697Snon
138979697Snonstatic int
139079697Snonnsp_ccb_nexus_establish(sc)
139179697Snon	struct nsp_softc *sc;
139279697Snon{
139379697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
139479697Snon	struct slccb *cb = slp->sl_Qnexus;
139579697Snon
139679697Snon	sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000;
139779697Snon
139867468Snon	/* setup pdma fifo */
139979697Snon	nsp_setup_fifo(sc, NSP_FIFO_ON,
140079697Snon		       slp->sl_scp.scp_direction, slp->sl_scp.scp_datalen);
140167468Snon
140279697Snon	if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
140379697Snon	{
140479697Snon		if (sc->sc_suspendio > 0 &&
140579697Snon		    (nsp_io_control & NSP_READ_FIFO_INTERRUPTS) != 0)
140679697Snon		{
140779697Snon			sc->sc_icr |= SCIENR_FIFO;
140879697Snon			nsp_cr_write_1(sc->sc_iot, sc->sc_ioh,
140979697Snon				       NSPR_SCIENR, sc->sc_icr);
141079697Snon		}
141179697Snon	}
141279697Snon	else
141379697Snon	{
141479697Snon		if (sc->sc_suspendio > 0 &&
141579697Snon		    (nsp_io_control & NSP_WRITE_FIFO_INTERRUPTS) != 0)
141679697Snon		{
141779697Snon			sc->sc_icr |= SCIENR_FIFO;
141879697Snon			nsp_cr_write_1(sc->sc_iot, sc->sc_ioh,
141979697Snon				       NSPR_SCIENR, sc->sc_icr);
142079697Snon		}
142179697Snon	}
142267468Snon	return 0;
142367468Snon}
142467468Snon
142579697Snonstatic int
142679697Snonnsp_phase_match(sc, phase, stat)
142779697Snon	struct nsp_softc *sc;
142879697Snon	u_int8_t phase;
142979697Snon	u_int8_t stat;
143079697Snon{
143179697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
143279697Snon
143379697Snon	if ((stat & SCBUSMON_PHMASK) != phase)
143479697Snon	{
143579697Snon		printf("%s: phase mismatch 0x%x != 0x%x\n",
143679697Snon			slp->sl_xname, (u_int) phase, (u_int) stat);
143779697Snon		return EINVAL;
143879697Snon	}
143979697Snon
144079697Snon	if ((stat & SCBUSMON_REQ) == 0)
144179697Snon		return EINVAL;
144279697Snon
144379697Snon	return 0;
144479697Snon}
144579697Snon
144667468Snonint
144767468Snonnspintr(arg)
144867468Snon	void *arg;
144967468Snon{
145067468Snon	struct nsp_softc *sc = arg;
145167468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
145267468Snon	bus_space_tag_t bst = sc->sc_iot;
145367468Snon	bus_space_handle_t bsh = sc->sc_ioh;
145467468Snon	struct targ_info *ti;
145567468Snon	struct physio_proc *pp;
145667468Snon	struct buf *bp;
145779697Snon	u_int derror, flags;
145867468Snon	int len, rv;
145967468Snon	u_int8_t isrc, ph, irqphs, cr, regv;
146067468Snon
146167468Snon	/*******************************************
146267468Snon	 * interrupt check
146367468Snon	 *******************************************/
146467468Snon	if (slp->sl_flags & HW_INACTIVE)
146567468Snon		return 0;
146667468Snon
146767468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_IRQDIS);
146867468Snon	isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
146979697Snon	if (isrc == (u_int8_t) -1 || (isrc & IRQSR_MASK) == 0)
147067468Snon	{
147167468Snon		bus_space_write_1(bst, bsh, nsp_irqcr, 0);
147267468Snon		return 0;
147367468Snon	}
147467468Snon
147567468Snon	/* XXX: IMPORTANT
147667468Snon 	 * Do not read an irqphs register if no scsi phase interrupt.
147767468Snon	 * Unless, you should lose a scsi phase interrupt.
147867468Snon	 */
147967468Snon	ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
148067468Snon	if ((isrc & IRQSR_SCSI) != 0)
148167468Snon	{
148267468Snon		irqphs = nsp_cr_read_1(bst, bsh, NSPR_IRQPHS);
148367468Snon	}
148467468Snon	else
148567468Snon		irqphs = 0;
148667468Snon
148767468Snon	/*
148867468Snon 	 * timer interrupt handler (scsi vs timer interrupts)
148967468Snon	 */
149067468Snon	if (sc->sc_timer != 0)
149167468Snon	{
149267468Snon		nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
149367468Snon		nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
149467468Snon		sc->sc_timer = 0;
149567468Snon	}
149667468Snon
149779697Snon	/* check a timer interrupt */
149879697Snon	regv = 0;
149979697Snon	if ((isrc & IRQSR_TIMER) != 0)
150067468Snon	{
150179697Snon		if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0)
150279697Snon		{
150379697Snon			bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL);
150479697Snon			return 1;
150579697Snon		}
150679697Snon		regv |= IRQCR_TIMERCL;
150767468Snon	}
150867468Snon
150979697Snon	/* check a fifo interrupt */
151079697Snon	if ((isrc & IRQSR_FIFO) != 0)
151179697Snon	{
151279697Snon		regv |= IRQCR_FIFOCL;
151379697Snon	}
151467468Snon
151579697Snon	/* OK. enable all interrupts */
151679697Snon	bus_space_write_1(bst, bsh, nsp_irqcr, regv);
151779697Snon
151867468Snon	/*******************************************
151967468Snon	 * debug section
152067468Snon	 *******************************************/
152167468Snon#ifdef	NSP_DEBUG
152267468Snon	if (nsp_debug)
152367468Snon	{
152479697Snon		nsp_error(sc, "current status", isrc, ph, irqphs);
152567468Snon		scsi_low_print(slp, NULL);
152679697Snon#ifdef	DDB
152767468Snon		if (nsp_debug > 1)
152879697Snon			SCSI_LOW_DEBUGGER("nsp");
152979697Snon#endif	/* DDB */
153067468Snon	}
153167468Snon#endif	/* NSP_DEBUG */
153267468Snon
153367468Snon	/*******************************************
153467468Snon	 * Parse hardware SCSI irq reasons register
153567468Snon	 *******************************************/
153667468Snon	if ((isrc & IRQSR_SCSI) != 0)
153767468Snon	{
153867468Snon 		if ((irqphs & IRQPHS_RST) != 0)
153967468Snon		{
154067468Snon			scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
154167468Snon					 "bus reset (power off?)");
154267468Snon			return 1;
154367468Snon		}
154467468Snon
154567468Snon		if ((irqphs & IRQPHS_RSEL) != 0)
154667468Snon		{
154767468Snon			bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_RESCL);
154867468Snon			if (nsp_reselected(sc) == EJUSTRETURN)
154967468Snon				return 1;
155067468Snon		}
155167468Snon
155267468Snon		if ((irqphs & (IRQPHS_PCHG | IRQPHS_LBF)) == 0)
155367468Snon			return 1;
155467468Snon	}
155567468Snon
155667468Snon	/*******************************************
155767468Snon	 * nexus check
155867468Snon	 *******************************************/
155979697Snon	if ((ti = slp->sl_Tnexus) == NULL)
156067468Snon	{
156167468Snon		/* unknown scsi phase changes */
156279697Snon		nsp_error(sc, "unknown scsi phase changes", isrc, ph, irqphs);
156367468Snon		return 0;
156467468Snon	}
156567468Snon
156667468Snon	/*******************************************
156767468Snon	 * aribitration & selection
156867468Snon	 *******************************************/
156967468Snon	switch (ti->ti_phase)
157067468Snon	{
157167468Snon	case PH_SELSTART:
157267468Snon		if ((ph & SCBUSMON_BSY) == 0)
157367468Snon		{
157467468Snon			if (sc->sc_seltout >= NSP_SELTIMEOUT)
157567468Snon			{
157667468Snon				sc->sc_seltout = 0;
157767468Snon				nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0);
157867468Snon				return nsp_disconnected(sc, ti);
157967468Snon			}
158067468Snon			sc->sc_seltout ++;
158179697Snon			nsp_start_timer(sc, NSP_TIMER_1MS);
158267468Snon			return 1;
158367468Snon		}
158467468Snon
158567468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
158679697Snon		nsphw_selection_done_and_expect_msgout(sc);
158767468Snon		return 1;
158867468Snon
158979697Snon	case PH_SELECTED:
159079697Snon		if ((isrc & IRQSR_SCSI) == 0)
159179697Snon			return 1;
159279697Snon
159379697Snon		nsp_target_nexus_establish(sc);
159479697Snon		break;
159579697Snon
159667468Snon	case PH_RESEL:
159779697Snon		if ((isrc & IRQSR_SCSI) == 0)
159879697Snon			return 1;
159979697Snon
160079697Snon		nsp_target_nexus_establish(sc);
160167468Snon		if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN)
160267468Snon		{
160379697Snon			printf("%s: unexpected phase after reselect\n",
160479697Snon			       slp->sl_xname);
160579697Snon			slp->sl_error |= FATALIO;
160667468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
160767468Snon			return 1;
160867468Snon		}
160979697Snon		break;
161067468Snon
161179697Snon	case PH_DATA:
161279697Snon		if ((isrc & IRQSR_SCSI) != 0)
161379697Snon			break;
161479697Snon		if ((isrc & IRQSR_FIFO) != 0)
161579697Snon		{
161679697Snon			if (NSP_IS_PHASE_DATA(ph) == 0)
161779697Snon				return 1;
161879697Snon			irqphs = (ph & IRQPHS_PHMASK);
161979697Snon			break;
162079697Snon		}
162179697Snon		return 1;
162279697Snon
162367468Snon	default:
162479697Snon		if ((isrc & IRQSR_SCSI) == 0)
162567468Snon			return 1;
162667468Snon		break;
162767468Snon	}
162867468Snon
162967468Snon	/*******************************************
163079697Snon	 * data phase control
163167468Snon	 *******************************************/
163267468Snon	if (slp->sl_flags & HW_PDMASTART)
163379697Snon	{
163479697Snon		if ((isrc & IRQSR_SCSI) != 0 &&
163579697Snon		     NSP_IS_IRQPHS_DATA(irqphs) == 0)
163679697Snon		{
163779697Snon			if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
163879697Snon				nsp_pio_read(sc, 0);
163979697Snon			nsp_pdma_end(sc, ti);
164079697Snon		}
164179697Snon	}
164267468Snon
164379697Snon	/*******************************************
164479697Snon	 * scsi seq
164579697Snon	 *******************************************/
164667468Snon	if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0)
164767468Snon		return nsp_disconnected(sc, ti);
164867468Snon
164967468Snon	/* check unexpected bus free state */
165067468Snon	if (ph == 0)
165167468Snon	{
165279697Snon		nsp_error(sc, "unexpected bus free", isrc, ph, irqphs);
165367468Snon		return nsp_disconnected(sc, ti);
165467468Snon	}
165567468Snon
165667468Snon	/* check normal scsi phase */
165779697Snon	switch (irqphs & IRQPHS_PHMASK)
165867468Snon	{
165979697Snon	case IRQPHS_CMD:
166079697Snon		if (nsp_phase_match(sc, PHASE_CMD, ph) != 0)
166167468Snon			return 1;
166267468Snon
166367468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
166467468Snon		if (scsi_low_cmd(slp, ti) != 0)
166579697Snon		{
166679697Snon			scsi_low_attention(slp);
166779697Snon		}
166867468Snon
166967468Snon		nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR);
167067468Snon		for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++)
167167468Snon			nsp_cr_write_1(bst, bsh, NSPR_CMDDR,
167267468Snon				       slp->sl_scp.scp_cmd[len]);
167367468Snon
167467468Snon		nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC);
167567468Snon		break;
167667468Snon
167779697Snon	case IRQPHS_DATAOUT:
167867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
167967468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
168079697Snon		{
168179697Snon			scsi_low_attention(slp);
168279697Snon		}
168367468Snon
168467468Snon		pp = physio_proc_enter(bp);
168579697Snon		nsp_pio_write(sc, sc->sc_suspendio);
168667468Snon		physio_proc_leave(pp);
168767468Snon		break;
168867468Snon
168979697Snon	case IRQPHS_DATAIN:
169067468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
169167468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
169279697Snon		{
169379697Snon			scsi_low_attention(slp);
169479697Snon		}
169567468Snon
169667468Snon		pp = physio_proc_enter(bp);
169779697Snon		nsp_pio_read(sc, sc->sc_suspendio);
169867468Snon		physio_proc_leave(pp);
169967468Snon		break;
170067468Snon
170179697Snon	case IRQPHS_STATUS:
170279697Snon		if (nsp_phase_match(sc, PHASE_STATUS, ph) != 0)
170367468Snon			return 1;
170467468Snon
170567468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
170679697Snon		regv = nsp_cr_read_1(bst, bsh, NSPR_DATA);
170779697Snon		if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
170879697Snon		{
170979697Snon			nsp_cr_write_1(bst, bsh, NSPR_PARITYR,
171079697Snon				       PARITYR_ENABLE | PARITYR_CLEAR);
171179697Snon			derror = SCSI_LOW_DATA_PE;
171279697Snon		}
171379697Snon		else
171479697Snon			derror = 0;
171579697Snon
171679697Snon		/* assert ACK */
171779697Snon		cr = SCBUSCR_ACK | nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
171879697Snon		nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
171979697Snon
172079697Snon		if (scsi_low_statusin(slp, ti, derror | regv) != 0)
172179697Snon		{
172279697Snon			scsi_low_attention(slp);
172379697Snon		}
172479697Snon
172579697Snon		/* check REQ nagated */
172679697Snon		nsp_negate_signal(sc, SCBUSMON_REQ, "statin<REQ>");
172779697Snon
172879697Snon		/* deassert ACK */
172979697Snon		cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK);
173079697Snon		nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
173167468Snon		break;
173267468Snon
173379697Snon	case IRQPHS_MSGOUT:
173479697Snon		if (nsp_phase_match(sc, PHASE_MSGOUT, ph) != 0)
173579697Snon			return 1;
173667468Snon
173779697Snon#ifdef	NSP_MSGOUT_SERIALIZE
173867468Snon		/*
173967468Snon		 * XXX: NSP QUIRK
174067468Snon		 * NSP invoke interrupts only in the case of scsi phase changes,
174167468Snon		 * therefore we should poll the scsi phase here to catch
174267468Snon		 * the next "msg out" if exists (no scsi phase changes).
174367468Snon		 */
174467468Snon		rv = len = 16;
174567468Snon		do {
174667468Snon			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
174779697Snon			flags = (ti->ti_ophase != ti->ti_phase) ?
174879697Snon					SCSI_LOW_MSGOUT_INIT : 0;
174979697Snon			len = scsi_low_msgout(slp, ti, flags);
175067468Snon
175179697Snon			if (len > 1 && slp->sl_atten == 0)
175267468Snon			{
175379697Snon				scsi_low_attention(slp);
175479697Snon			}
175579697Snon
175679697Snon			if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT,
175779697Snon			             slp->sl_clear_atten) != 0)
175879697Snon			{
175979697Snon				slp->sl_error |= FATALIO;
176079697Snon				nsp_error(sc, "MSGOUT: xfer short",
176167468Snon						    isrc, ph, irqphs);
176267468Snon			}
176367468Snon
176467468Snon			/* catch a next signal */
176567468Snon			rv = nsp_expect_signal(sc, PHASE_MSGOUT, SCBUSMON_REQ);
176667468Snon		}
176767468Snon		while (rv > 0 && len -- > 0);
176879697Snon
176979697Snon#else	/* !NSP_MSGOUT_SERIALIZE */
177079697Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
177179697Snon		flags = SCSI_LOW_MSGOUT_UNIFY;
177279697Snon		if (ti->ti_ophase != ti->ti_phase)
177379697Snon			flags |= SCSI_LOW_MSGOUT_INIT;
177479697Snon		len = scsi_low_msgout(slp, ti, flags);
177579697Snon
177679697Snon		if (len > 1 && slp->sl_atten == 0)
177779697Snon		{
177879697Snon			scsi_low_attention(slp);
177979697Snon		}
178079697Snon
178179697Snon		if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT,
178279697Snon			     slp->sl_clear_atten) != 0)
178379697Snon		{
178479697Snon			nsp_error(sc, "MSGOUT: xfer short", isrc, ph, irqphs);
178579697Snon		}
178679697Snon
178779697Snon#endif	/* !NSP_MSGOUT_SERIALIZE */
178867468Snon		break;
178967468Snon
179079697Snon	case IRQPHS_MSGIN:
179179697Snon		if (nsp_phase_match(sc, PHASE_MSGIN, ph) != 0)
179279697Snon			return 1;
179367468Snon
179467468Snon		/*
179567468Snon		 * XXX: NSP QUIRK
179667468Snon		 * NSP invoke interrupts only in the case of scsi phase changes,
179767468Snon		 * therefore we should poll the scsi phase here to catch
179867468Snon		 * the next "msg in" if exists (no scsi phase changes).
179967468Snon		 */
180067468Snon		rv = len = 16;
180167468Snon		do {
180279697Snon			SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
180379697Snon
180467468Snon			/* read a data */
180567468Snon			regv = nsp_cr_read_1(bst, bsh, NSPR_DATA);
180679697Snon			if (nsp_cr_read_1(bst, bsh, NSPR_PARITYR) & PARITYR_PE)
180779697Snon			{
180879697Snon				nsp_cr_write_1(bst, bsh,
180979697Snon					       NSPR_PARITYR,
181079697Snon					       PARITYR_ENABLE | PARITYR_CLEAR);
181179697Snon				derror = SCSI_LOW_DATA_PE;
181279697Snon			}
181379697Snon			else
181479697Snon			{
181579697Snon				derror = 0;
181679697Snon			}
181767468Snon
181867468Snon			/* assert ack */
181979697Snon			cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) | SCBUSCR_ACK;
182067468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
182179697Snon
182279697Snon			if (scsi_low_msgin(slp, ti, regv | derror) == 0)
182379697Snon			{
182479697Snon				if (scsi_low_is_msgout_continue(ti, 0) != 0)
182579697Snon				{
182679697Snon					scsi_low_attention(slp);
182779697Snon				}
182879697Snon			}
182979697Snon
183079697Snon			/* check REQ nagated */
183167468Snon			nsp_negate_signal(sc, SCBUSMON_REQ, "msgin<REQ>");
183267468Snon
183367468Snon			/* deassert ack */
183479697Snon			cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & (~SCBUSCR_ACK);
183567468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
183667468Snon
183767468Snon			/* catch a next signal */
183867468Snon			rv = nsp_expect_signal(sc, PHASE_MSGIN, SCBUSMON_REQ);
183967468Snon		}
184067468Snon		while (rv > 0 && len -- > 0);
184167468Snon		break;
184267468Snon
184367468Snon	default:
184479697Snon		slp->sl_error |= FATALIO;
184579697Snon		nsp_error(sc, "unknown scsi phase", isrc, ph, irqphs);
184667468Snon		break;
184767468Snon	}
184867468Snon
184967468Snon	return 1;
185067468Snon
185179697Snon#if	0
185267468Snontimerout:
185379697Snon	nsp_start_timer(sc, NSP_TIMER_1MS);
185467468Snon	return 0;
185579697Snon#endif
185667468Snon}
185779697Snon
185879697Snonstatic int
185979697Snonnsp_timeout(sc)
186079697Snon	struct nsp_softc *sc;
186179697Snon{
186279697Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
186379697Snon	bus_space_tag_t iot = sc->sc_iot;
186479697Snon	bus_space_handle_t ioh = sc->sc_ioh;
186579697Snon	int tout;
186679697Snon	u_int8_t ph, regv;
186779697Snon
186879697Snon	if (slp->sl_Tnexus == NULL)
186979697Snon		return 0;
187079697Snon
187179697Snon	ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
187279697Snon	switch (ph & SCBUSMON_PHMASK)
187379697Snon	{
187479697Snon	case PHASE_DATAOUT:
187579697Snon		if (sc->sc_dataout_timeout == 0)
187679697Snon			break;
187779697Snon
187879697Snon		/* check a fifo empty */
187979697Snon		regv = bus_space_read_1(iot, ioh, nsp_fifosr);
188079697Snon		if ((regv & FIFOSR_FULLEMP) == 0)
188179697Snon			break;
188279697Snon		bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL);
188379697Snon
188479697Snon		/* check still requested */
188579697Snon		ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
188679697Snon		if ((ph & SCBUSMON_REQ) == 0)
188779697Snon			break;
188879697Snon		/* check timeout */
188979697Snon		if ((-- sc->sc_dataout_timeout) > 0)
189079697Snon			break;
189179697Snon
189279697Snon	        slp->sl_error |= PDMAERR;
189379697Snon		if ((slp->sl_flags & HW_WRITE_PADDING) == 0)
189479697Snon		{
189579697Snon			printf("%s: write padding required\n", slp->sl_xname);
189679697Snon			break;
189779697Snon		}
189879697Snon
189979697Snon		tout = NSP_DELAY_MAX;
190079697Snon		while (tout -- > 0)
190179697Snon		{
190279697Snon			ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
190379697Snon			if ((ph & SCBUSMON_PHMASK) != PHASE_DATAOUT)
190479697Snon				break;
190579697Snon			regv = bus_space_read_1(iot, ioh, nsp_fifosr);
190679697Snon			if ((regv & FIFOSR_FULLEMP) == 0)
190779697Snon			{
190879697Snon				SCSI_LOW_DELAY(1);
190979697Snon				continue;
191079697Snon			}
191179697Snon
191279697Snon			bus_space_write_1(iot, ioh, nsp_irqcr, IRQCR_FIFOCL);
191379697Snon			nsp_data_padding(sc, SCSI_LOW_WRITE, 32);
191479697Snon		}
191579697Snon		ph = nsp_cr_read_1(iot, ioh, NSPR_SCBUSMON);
191679697Snon		if ((ph & SCBUSMON_PHMASK) == PHASE_DATAOUT)
191779697Snon			sc->sc_dataout_timeout = SCSI_LOW_TIMEOUT_HZ;
191879697Snon		break;
191979697Snon
192079697Snon	default:
192179697Snon		break;
192279697Snon	}
192379697Snon	return 0;
192479697Snon}
1925