nsp.c revision 71468
167468Snon/*	$FreeBSD: head/sys/dev/nsp/nsp.c 71468 2001-01-23 22:08:21Z jhb $	*/
267468Snon/*	$NecBSD: nsp.c,v 1.21 1999/07/23 21:00:05 honda Exp $	*/
367468Snon/*	$NetBSD$	*/
467468Snon
567468Snon#define	NSP_DEBUG
667468Snon#define	NSP_STATICS
767468Snon
867468Snon/*
967468Snon *  Copyright (c) 1998
1067468Snon *	NetBSD/pc98 porting staff. All rights reserved.
1167468Snon *
1267468Snon *  Redistribution and use in source and binary forms, with or without
1367468Snon *  modification, are permitted provided that the following conditions
1467468Snon *  are met:
1567468Snon *  1. Redistributions of source code must retain the above copyright
1667468Snon *     notice, this list of conditions and the following disclaimer.
1767468Snon *  2. Redistributions in binary form must reproduce the above copyright
1867468Snon *     notice, this list of conditions and the following disclaimer in the
1967468Snon *     documentation and/or other materials provided with the distribution.
2067468Snon *  3. The name of the author may not be used to endorse or promote products
2167468Snon *     derived from this software without specific prior written permission.
2267468Snon *
2367468Snon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2467468Snon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2567468Snon * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2667468Snon * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2767468Snon * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2867468Snon * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2967468Snon * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3067468Snon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3167468Snon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3267468Snon * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3367468Snon * POSSIBILITY OF SUCH DAMAGE.
3467468Snon */
3567468Snon#include "opt_ddb.h"
3667468Snon
3767468Snon#include <sys/param.h>
3867468Snon#include <sys/systm.h>
3967468Snon#include <sys/kernel.h>
4067468Snon#include <sys/disklabel.h>
4167468Snon#if defined(__FreeBSD__) && __FreeBSD_version > 500001
4267468Snon#include <sys/bio.h>
4367468Snon#endif
4467468Snon#include <sys/buf.h>
4567468Snon#include <sys/queue.h>
4667468Snon#include <sys/malloc.h>
4767468Snon#include <sys/device_port.h>
4867468Snon#include <sys/errno.h>
4967468Snon
5067468Snon#include <vm/vm.h>
5167468Snon
5267468Snon#ifdef __NetBSD__
5367468Snon#include <machine/bus.h>
5467468Snon#include <machine/intr.h>
5567468Snon
5667468Snon#include <dev/scsipi/scsi_all.h>
5767468Snon#include <dev/scsipi/scsipi_all.h>
5867468Snon#include <dev/scsipi/scsiconf.h>
5967468Snon#include <dev/scsipi/scsi_disk.h>
6067468Snon
6167468Snon#include <machine/dvcfg.h>
6267468Snon#include <machine/physio_proc.h>
6367468Snon
6467468Snon#include <i386/Cbus/dev/scsi_low.h>
6567468Snon#include <i386/Cbus/dev/nspreg.h>
6667468Snon#include <i386/Cbus/dev/nspvar.h>
6767468Snon#endif /* __NetBSD__ */
6867468Snon
6967468Snon#ifdef __FreeBSD__
7067468Snon#include <machine/clock.h>
7167468Snon#define delay(time) DELAY(time)
7267468Snon
7367468Snon#include <machine/cpu.h>
7467468Snon#include <machine/bus_pio.h>
7567468Snon#include <machine/bus_memio.h>
7667468Snon#include <machine/bus.h>
7767468Snon
7867468Snon#include <machine/dvcfg.h>
7967468Snon#include <machine/physio_proc.h>
8067468Snon
8167468Snon#include <cam/scsi/scsi_low.h>
8267468Snon#include <dev/nsp/nspreg.h>
8367468Snon#include <dev/nsp/nspvar.h>
8467468Snon
8567468Snon#if __FreeBSD_version < 400001
8667468Snon#include "nsp.h"
8767468Snonstruct nsp_softc *nspdata[NNSP];
8867468Snon#endif
8967468Snon#endif /* __FreeBSD__ */
9067468Snon
9167468Snon/***************************************************
9267468Snon * USER SETTINGS
9367468Snon ***************************************************/
9467468Snon/* DEVICE CONFIGURATION FLAGS (MINOR)
9567468Snon *
9667468Snon * 0x01   DISCONECT OFF
9767468Snon * 0x02   PARITY LINE OFF
9867468Snon * 0x04   IDENTIFY MSG OFF ( = single lun)
9967468Snon * 0x08   SYNC TRANSFER OFF
10067468Snon */
10167468Snon
10267468Snon/***************************************************
10367468Snon * PARAMS
10467468Snon ***************************************************/
10567468Snon#define	NSP_NTARGETS	8
10667468Snon#define	NSP_NLUNS	8
10767468Snon
10867468Snon#define	NSP_SELTIMEOUT	200
10967468Snon
11067468Snon/***************************************************
11167468Snon * DEBUG
11267468Snon ***************************************************/
11367468Snon#ifndef DDB
11467468Snon#define Debugger() panic("should call debugger here (nsp.c)")
11567468Snon#else /* ! DDB */
11667468Snon#ifdef __FreeBSD__
11767468Snon#define Debugger() Debugger("nsp")
11867468Snon#endif /* __FreeBSD__ */
11967468Snon#endif
12067468Snon
12167468Snon#ifdef	NSP_DEBUG
12267468Snonint nsp_debug;
12367468Snon#endif	/* NSP_DEBUG */
12467468Snon
12567468Snon#ifdef	NSP_STATICS
12667468Snonstruct nsp_statics {
12767468Snon	int disconnect;
12867468Snon	int reselect;
12967468Snon	int data_phase_bypass;
13067468Snon} nsp_statics[NSP_NTARGETS];
13167468Snon#endif	/* NSP_STATICS */
13267468Snon
13367468Snon/***************************************************
13467468Snon * ISA DEVICE STRUCTURE
13567468Snon ***************************************************/
13667468Snonextern struct cfdriver nsp_cd;
13767468Snon
13867468Snon/**************************************************************
13967468Snon * DECLARE
14067468Snon **************************************************************/
14167468Snon/* static */
14267468Snonstatic void nsp_pio_read __P((struct nsp_softc *, struct targ_info *));
14367468Snonstatic void nsp_pio_write __P((struct nsp_softc *, struct targ_info *));
14467468Snonstatic int nsp_xfer __P((struct nsp_softc *, u_int8_t *, int, int));
14567468Snonstatic int nsp_msg __P((struct nsp_softc *, struct targ_info *, u_int));
14667468Snonstatic int nsp_reselected __P((struct nsp_softc *));
14767468Snonstatic __inline int nsp_disconnected __P((struct nsp_softc *, struct targ_info *));
14867468Snonstatic __inline void nsp_pdma_end __P((struct nsp_softc *, struct targ_info *));
14967468Snonstatic void nsphw_init __P((struct nsp_softc *));
15067468Snonstatic int nsp_nexus __P((struct nsp_softc *, struct targ_info *));
15167468Snonstatic int nsp_world_start __P((struct nsp_softc *, int));
15267468Snonstatic int nsphw_start_selection __P((struct nsp_softc *sc, struct slccb *));
15367468Snonstatic void nsphw_bus_reset __P((struct nsp_softc *));
15467468Snonstatic void nsphw_attention __P((struct nsp_softc *));
15567468Snonstatic u_int nsp_fifo_count __P((struct nsp_softc *));
15667468Snonstatic int nsp_negate_signal __P((struct nsp_softc *, u_int8_t, u_char *));
15767468Snonstatic int nsp_expect_signal __P((struct nsp_softc *, u_int8_t, u_int8_t));
15867468Snonstatic __inline void nsp_start_timer __P((struct nsp_softc *, int));
15967468Snonstatic int nsp_dataphase_bypass __P((struct nsp_softc *, struct targ_info *));
16067468Snonstatic void nsp_setup_fifo __P((struct nsp_softc *, int));
16167468Snonstatic int nsp_lun_init __P((struct nsp_softc *, struct targ_info *, struct lun_info *));
16267468Snonstatic void settimeout __P((void *));
16367468Snon
16467468Snonstruct scsi_low_funcs nspfuncs = {
16567468Snon	SC_LOW_INIT_T nsp_world_start,
16667468Snon	SC_LOW_BUSRST_T nsphw_bus_reset,
16767468Snon	SC_LOW_LUN_INIT_T nsp_lun_init,
16867468Snon
16967468Snon	SC_LOW_SELECT_T nsphw_start_selection,
17067468Snon	SC_LOW_NEXUS_T nsp_nexus,
17167468Snon
17267468Snon	SC_LOW_ATTEN_T nsphw_attention,
17367468Snon	SC_LOW_MSG_T nsp_msg,
17467468Snon
17567468Snon	SC_LOW_POLL_T nspintr,
17667468Snon
17767468Snon	NULL,
17867468Snon};
17967468Snon
18067468Snon/****************************************************
18167468Snon * hwfuncs
18267468Snon ****************************************************/
18367468Snonstatic __inline u_int8_t nsp_cr_read_1 __P((bus_space_tag_t bst, bus_space_handle_t bsh, bus_addr_t ofs));
18467468Snonstatic __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));
18567468Snon
18667468Snonstatic __inline u_int8_t
18767468Snonnsp_cr_read_1(bst, bsh, ofs)
18867468Snon	bus_space_tag_t bst;
18967468Snon	bus_space_handle_t bsh;
19067468Snon	bus_addr_t ofs;
19167468Snon{
19267468Snon
19367468Snon	bus_space_write_1(bst, bsh, nsp_idxr, ofs);
19467468Snon	return bus_space_read_1(bst, bsh, nsp_datar);
19567468Snon}
19667468Snon
19767468Snonstatic __inline void
19867468Snonnsp_cr_write_1(bst, bsh, ofs, va)
19967468Snon	bus_space_tag_t bst;
20067468Snon	bus_space_handle_t bsh;
20167468Snon	bus_addr_t ofs;
20267468Snon	u_int8_t va;
20367468Snon{
20467468Snon
20567468Snon	bus_space_write_1(bst, bsh, nsp_idxr, ofs);
20667468Snon	bus_space_write_1(bst, bsh, nsp_datar, va);
20767468Snon}
20867468Snon
20967468Snonstatic int
21067468Snonnsp_expect_signal(sc, curphase, mask)
21167468Snon	struct nsp_softc *sc;
21267468Snon	u_int8_t curphase, mask;
21367468Snon{
21467468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
21567468Snon	bus_space_tag_t bst = sc->sc_iot;
21667468Snon	bus_space_handle_t bsh = sc->sc_ioh;
21767468Snon	int rv = -1;
21867468Snon	int s;
21967468Snon	int tout = 0;
22067468Snon#ifdef __FreeBSD__
22167468Snon	struct callout_handle ch;
22267468Snon#endif
22367468Snon	u_int8_t ph, isrc;
22467468Snon
22567468Snon#ifdef __FreeBSD__
22667468Snon	ch = timeout(settimeout, &tout, hz/2);
22767468Snon#else
22867468Snon	timeout(settimeout, &tout, hz/2);
22967468Snon#endif
23067468Snon	do
23167468Snon	{
23267468Snon		ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
23367468Snon		if (ph == 0xff) {
23467468Snon			rv = -1;
23567468Snon			break;
23667468Snon		}
23767468Snon		isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
23867468Snon		if (isrc & IRQSR_SCSI) {
23967468Snon			rv = 0;
24067468Snon			break;
24167468Snon		}
24267468Snon		if ((ph & mask) != 0 && (ph & SCBUSMON_PHMASK) == curphase) {
24367468Snon			rv = 1;
24467468Snon			break;
24567468Snon		}
24667468Snon	}
24767468Snon	while (tout == 0);
24867468Snon
24967468Snon	s = splhigh();
25067468Snon	if (tout == 0) {
25167468Snon#ifdef __FreeBSD__
25267468Snon		untimeout(settimeout, &tout, ch);
25367468Snon#else
25467468Snon		untimeout(settimeout, &tout);
25567468Snon#endif
25667468Snon		splx(s);
25767468Snon	} else {
25867468Snon		splx(s);
25967468Snon		printf("%s: nsp_expect_signal timeout\n", slp->sl_xname);
26067468Snon		rv = -1;
26167468Snon	}
26267468Snon
26367468Snon	return rv;
26467468Snon}
26567468Snon
26667468Snonstatic void
26767468Snonnsphw_init(sc)
26867468Snon	struct nsp_softc *sc;
26967468Snon{
27067468Snon	bus_space_tag_t bst = sc->sc_iot;
27167468Snon	bus_space_handle_t bsh = sc->sc_ioh;
27267468Snon
27367468Snon	/* block all interrupts */
27467468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK);
27567468Snon
27667468Snon	/* setup SCSI interface */
27767468Snon	bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_IFSEL);
27867468Snon
27967468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, 0);
28067468Snon
28167468Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8);
28267468Snon	nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_iclkdiv);
28367468Snon
28467468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, sc->sc_icr);
28567468Snon	nsp_cr_write_1(bst, bsh, NSPR_PARITYR, 0);
28667468Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR,
28767468Snon		       PTCLRR_ACK | PTCLRR_REQ | PTCLRR_HOST | PTCLRR_RSS);
28867468Snon
28967468Snon	/* setup fifo asic */
29067468Snon	bus_space_write_1(bst, bsh, nsp_ifselr, IFSELR_REGSEL);
29167468Snon	nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, 0);
29267468Snon	if ((nsp_cr_read_1(bst, bsh, NSPR_OCR) & OCR_TERMPWRS) == 0)
29367468Snon		nsp_cr_write_1(bst, bsh, NSPR_TERMPWRC, TERMPWRC_POWON);
29467468Snon
29567468Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, XFERMR_IO8);
29667468Snon	nsp_cr_write_1(bst, bsh, NSPR_CLKDIVR, sc->sc_clkdiv);
29767468Snon	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
29867468Snon	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
29967468Snon
30067468Snon	nsp_cr_write_1(bst, bsh, NSPR_SYNCR, 0);
30167468Snon	nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, 0);
30267468Snon
30367468Snon	/* enable interrupts and ack them */
30467468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCIENR, SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST);
30567468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
30667468Snon
30767468Snon	nsp_setup_fifo(sc, 0);
30867468Snon}
30967468Snon
31067468Snon/****************************************************
31167468Snon * scsi low interface
31267468Snon ****************************************************/
31367468Snonstatic void
31467468Snonnsphw_attention(sc)
31567468Snon	struct nsp_softc *sc;
31667468Snon{
31767468Snon	bus_space_tag_t bst = sc->sc_iot;
31867468Snon	bus_space_handle_t bsh = sc->sc_ioh;
31967468Snon	u_int8_t cr;
32067468Snon
32167468Snon	cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR)/*  & ~SCBUSCR_ACK */;
32267468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ATN);
32367468Snon}
32467468Snon
32567468Snonstatic void
32667468Snonnsphw_bus_reset(sc)
32767468Snon	struct nsp_softc *sc;
32867468Snon{
32967468Snon	bus_space_tag_t bst = sc->sc_iot;
33067468Snon	bus_space_handle_t bsh = sc->sc_ioh;
33167468Snon	int i;
33267468Snon
33367468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_ALLMASK);
33467468Snon
33567468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_RST);
33667468Snon	delay(100 * 1000);	/* 100ms */
33767468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0);
33867468Snon	for (i = 0; i < 5; i ++)
33967468Snon		(void) nsp_cr_read_1(bst, bsh, NSPR_IRQPHS);
34067468Snon
34167468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQSR_MASK);
34267468Snon}
34367468Snon
34471468Sjhbstatic __inline void
34571468Sjhbnsp_start_timer(sc, time)
34671468Sjhb	struct nsp_softc *sc;
34771468Sjhb	int time;
34871468Sjhb{
34971468Sjhb	bus_space_tag_t bst = sc->sc_iot;
35071468Sjhb	bus_space_handle_t bsh = sc->sc_ioh;
35171468Sjhb
35271468Sjhb	sc->sc_timer = time;
35371468Sjhb	nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, time);
35471468Sjhb}
35571468Sjhb
35667468Snonstatic int
35767468Snonnsphw_start_selection(sc, cb)
35867468Snon	struct nsp_softc *sc;
35967468Snon	struct slccb *cb;
36067468Snon{
36167468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
36267468Snon	bus_space_tag_t bst = sc->sc_iot;
36367468Snon	bus_space_handle_t bsh = sc->sc_ioh;
36467468Snon	struct targ_info *ti = cb->ti;
36567468Snon	register u_int8_t arbs, ph;
36667468Snon	int s;
36767468Snon	int tout = 0;
36867468Snon#ifdef __FreeBSD__
36967468Snon	struct callout_handle ch;
37067468Snon#endif
37167468Snon
37267468Snon	/* check bus free */
37367468Snon	if (slp->sl_disc > 0)
37467468Snon	{
37567468Snon		s = splhigh();
37667468Snon		ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
37767468Snon		if (ph != SCBUSMON_FREE)
37867468Snon		{
37967468Snon			splx(s);
38067468Snon			return SCSI_LOW_START_FAIL;
38167468Snon		}
38267468Snon		splx(s);
38367468Snon	}
38467468Snon
38567468Snon	/* start arbitration */
38667468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_ARBSTART);
38767468Snon	nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_EXEC);
38867468Snon#ifdef __FreeBSD__
38967468Snon	ch = timeout(settimeout, &tout, 2 * hz);
39067468Snon#else
39167468Snon	timeout(settimeout, &tout, 2 * hz);
39267468Snon#endif
39367468Snon	do
39467468Snon	{
39567468Snon		/* XXX: what a stupid chip! */
39667468Snon		arbs = nsp_cr_read_1(bst, bsh, NSPR_ARBITS);
39767468Snon		delay(1);
39867468Snon	}
39967468Snon	while ((arbs & (ARBITS_WIN | ARBITS_FAIL)) == 0 && tout == 0);
40067468Snon
40167468Snon	s = splhigh();
40267468Snon	if (tout == 0) {
40367468Snon#ifdef __FreeBSD__
40467468Snon		untimeout(settimeout, &tout, ch);
40567468Snon#else
40667468Snon		untimeout(settimeout, &tout);
40767468Snon#endif
40867468Snon	}
40967468Snon	splx(s);
41067468Snon
41167468Snon	if ((arbs & ARBITS_WIN) == 0)
41267468Snon	{
41367468Snon		nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
41467468Snon		return SCSI_LOW_START_FAIL;
41567468Snon	}
41667468Snon
41767468Snon	/* assert select line */
41867468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART);
41967468Snon	scsi_low_arbit_win(slp, ti);
42067468Snon	delay(3);
42167468Snon	nsp_cr_write_1(bst, bsh, NSPR_DATA,
42267468Snon		       sc->sc_idbit | (1 << ti->ti_id));
42367468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
42467468Snon			SCBUSCR_SEL | SCBUSCR_BSY | sc->sc_busc);
42567468Snon	delay(3);
42667468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, SCBUSCR_SEL |
42767468Snon			SCBUSCR_BSY | SCBUSCR_DOUT | sc->sc_busc);
42867468Snon	nsp_cr_write_1(bst, bsh, NSPR_ARBITS, ARBITS_CLR);
42967468Snon	delay(3);
43067468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
43167468Snon		       SCBUSCR_SEL | SCBUSCR_DOUT | sc->sc_busc);
43267468Snon
43367468Snon	/* check selection timeout */
43467468Snon	nsp_start_timer(sc, 1000 / 51);
43567468Snon	sc->sc_seltout = 1;
43667468Snon
43767468Snon	return SCSI_LOW_START_OK;
43867468Snon}
43967468Snon
44067468Snonstatic int
44167468Snonnsp_world_start(sc, fdone)
44267468Snon	struct nsp_softc *sc;
44367468Snon	int fdone;
44467468Snon{
44567468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
44667468Snon	intrmask_t s;
44767468Snon
44867468Snon	s = splcam();
44967468Snon	sc->sc_cnt = 0;
45067468Snon	sc->sc_seltout = 0;
45167468Snon	if ((slp->sl_cfgflags & CFG_NOATTEN) == 0)
45267468Snon		sc->sc_busc = SCBUSCR_ATN;
45367468Snon	else
45467468Snon		sc->sc_busc = 0;
45567468Snon	sc->sc_icr = (SCIENR_SCCHG | SCIENR_RESEL | SCIENR_RST);
45667468Snon
45767468Snon	nsphw_init(sc);
45867468Snon	scsi_low_bus_reset(slp);
45967468Snon	splx(s);
46067468Snon
46167468Snon	SOFT_INTR_REQUIRED(slp);
46267468Snon	return 0;
46367468Snon}
46467468Snon
46567468Snonstruct ncp_synch_data {
46667468Snon	u_int min_period;
46767468Snon	u_int max_period;
46867468Snon	u_int chip_period;
46967468Snon	u_int ack_width;
47067468Snon};
47167468Snon
47267468Snonstatic struct ncp_synch_data ncp_sync_data_40M[] = {
47367468Snon	{0x0c,0x0c,0x1,0},	/* 20MB  50ns*/
47467468Snon	{0x19,0x19,0x3,1}, 	/* 10MB  100ns*/
47567468Snon	{0x1a,0x25,0x5,2},	/* 7.5MB 150ns*/
47667468Snon	{0x26,0x32,0x7,3},	/* 5MB   200ns*/
47767468Snon	{0x0, 0, 0, 0}
47867468Snon};
47967468Snon
48067468Snonstatic struct ncp_synch_data ncp_sync_data_20M[] = {
48167468Snon	{0x19,0x19,0x1,0}, 	/* 10MB  100ns*/
48267468Snon	{0x1a,0x25,0x2,0},	/* 7.5MB 150ns*/
48367468Snon	{0x26,0x32,0x3,1},	/* 5MB   200ns*/
48467468Snon	{0x0, 0, 0, 0}
48567468Snon};
48667468Snon
48767468Snonstatic int
48867468Snonnsp_msg(sc, ti, msg)
48967468Snon	struct nsp_softc *sc;
49067468Snon	struct targ_info *ti;
49167468Snon	u_int msg;
49267468Snon{
49367468Snon	struct ncp_synch_data *sdp;
49467468Snon	struct lun_info *li = ti->ti_li;
49567468Snon	struct nsp_lun_info *nli = (void *) li;
49667468Snon	u_int period, offset;
49767468Snon	int i;
49867468Snon
49967468Snon	if ((msg & SCSI_LOW_MSG_SYNCH) == 0)
50067468Snon		return 0;
50167468Snon
50267468Snon	period = li->li_maxsynch.period;
50367468Snon	offset = li->li_maxsynch.offset;
50467468Snon	if (sc->sc_iclkdiv == CLKDIVR_20M)
50567468Snon		sdp = &ncp_sync_data_20M[0];
50667468Snon	else
50767468Snon		sdp = &ncp_sync_data_40M[0];
50867468Snon
50967468Snon	for (i = 0; sdp->max_period != 0; i ++, sdp ++)
51067468Snon	{
51167468Snon		if (period >= sdp->min_period && period <= sdp->max_period)
51267468Snon			break;
51367468Snon	}
51467468Snon
51567468Snon	if (period != 0 && sdp->max_period == 0)
51667468Snon	{
51767468Snon		/*
51867468Snon		 * NO proper period/offset found,
51967468Snon		 * Retry neg with the target.
52067468Snon		 */
52167468Snon		li->li_maxsynch.period = 0;
52267468Snon		li->li_maxsynch.offset = 0;
52367468Snon		nli->nli_reg_syncr = 0;
52467468Snon		nli->nli_reg_ackwidth = 0;
52567468Snon		return EINVAL;
52667468Snon	}
52767468Snon
52867468Snon	nli->nli_reg_syncr = (sdp->chip_period << SYNCR_PERS) |
52967468Snon			      (offset & SYNCR_OFFM);
53067468Snon	nli->nli_reg_ackwidth = sdp->ack_width;
53167468Snon	return 0;
53267468Snon}
53367468Snon
53467468Snonstatic int
53567468Snonnsp_lun_init(sc, ti, li)
53667468Snon	struct nsp_softc *sc;
53767468Snon	struct targ_info *ti;
53867468Snon	struct lun_info *li;
53967468Snon{
54067468Snon	struct nsp_lun_info *nli = (void *) li;
54167468Snon
54267468Snon	li->li_maxsynch.period = 200 / 4;
54367468Snon	li->li_maxsynch.offset = 15;
54467468Snon	nli->nli_reg_syncr = 0;
54567468Snon	nli->nli_reg_ackwidth = 0;
54667468Snon	return 0;
54767468Snon}
54867468Snon
54967468Snon/**************************************************************
55067468Snon * General probe attach
55167468Snon **************************************************************/
55267468Snonint
55367468Snonnspprobesubr(iot, ioh, dvcfg)
55467468Snon	bus_space_tag_t iot;
55567468Snon	bus_space_handle_t ioh;
55667468Snon	u_int dvcfg;
55767468Snon{
55867468Snon	u_int8_t regv;
55967468Snon
56067468Snon	regv = bus_space_read_1(iot, ioh, nsp_fifosr);
56167468Snon	if (regv < 0x11 || regv >= 0x20)
56267468Snon		return 0;
56367468Snon	return 1;
56467468Snon}
56567468Snon
56667468Snonint
56767468Snonnspprint(aux, name)
56867468Snon	void *aux;
56967468Snon	const char *name;
57067468Snon{
57167468Snon
57267468Snon	if (name != NULL)
57367468Snon		printf("%s: scsibus ", name);
57467468Snon	return UNCONF;
57567468Snon}
57667468Snon
57767468Snonvoid
57867468Snonnspattachsubr(sc)
57967468Snon	struct nsp_softc *sc;
58067468Snon{
58167468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
58267468Snon
58367468Snon	printf("\n");
58467468Snon
58567468Snon	sc->sc_idbit = (1 << slp->sl_hostid);
58667468Snon	slp->sl_funcs = &nspfuncs;
58767468Snon	if (sc->sc_memh != NULL)
58867468Snon		sc->sc_xmode = NSP_MID_SMIT;
58967468Snon	else
59067468Snon		sc->sc_xmode = NSP_PIO;
59167468Snon
59267468Snon	(void) scsi_low_attach(slp, 2, NSP_NTARGETS, NSP_NLUNS,
59367468Snon			       sizeof(struct nsp_lun_info));
59467468Snon}
59567468Snon
59667468Snon/**************************************************************
59767468Snon * PDMA functions
59867468Snon **************************************************************/
59967468Snonstatic u_int
60067468Snonnsp_fifo_count(sc)
60167468Snon	struct nsp_softc *sc;
60267468Snon{
60367468Snon	bus_space_tag_t bst = sc->sc_iot;
60467468Snon	bus_space_handle_t bsh = sc->sc_ioh;
60567468Snon	u_int count;
60667468Snon
60767468Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT);
60867468Snon	count = bus_space_read_1(bst, bsh, nsp_datar);
60967468Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 8);
61067468Snon	count += (((u_int) bus_space_read_1(bst, bsh, nsp_datar)) << 16);
61167468Snon	return count;
61267468Snon}
61367468Snon
61467468Snonstatic void
61567468Snonnsp_setup_fifo(sc, on)
61667468Snon	struct nsp_softc *sc;
61767468Snon	int on;
61867468Snon{
61967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
62067468Snon	bus_space_tag_t bst = sc->sc_iot;
62167468Snon	bus_space_handle_t bsh = sc->sc_ioh;
62267468Snon	u_int8_t xfermode;
62367468Snon
62467468Snon	if (on != 0)
62567468Snon		xfermode = XFERMR_XEN | XFERMR_FIFOEN;
62667468Snon	else
62767468Snon		xfermode = 0;
62867468Snon
62967468Snon	if ((slp->sl_scp.scp_datalen % DEV_BSIZE) != 0)
63067468Snon	{
63167468Snon		sc->sc_mask = 0;
63267468Snon		xfermode |= XFERMR_IO8;
63367468Snon	}
63467468Snon	else
63567468Snon	{
63667468Snon		sc->sc_mask = 3;
63767468Snon		if (sc->sc_xmode == NSP_MID_SMIT)
63867468Snon			xfermode |= XFERMR_MEM32;
63967468Snon		else
64067468Snon			xfermode |= XFERMR_IO32;
64167468Snon	}
64267468Snon
64367468Snon	sc->sc_xfermr = xfermode;
64467468Snon	nsp_cr_write_1(bst, bsh, NSPR_XFERMR, sc->sc_xfermr);
64567468Snon}
64667468Snon
64767468Snonstatic __inline void
64867468Snonnsp_pdma_end(sc, ti)
64967468Snon	struct nsp_softc *sc;
65067468Snon	struct targ_info *ti;
65167468Snon{
65267468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
65367468Snon	struct slccb *cb = ti->ti_nexus;
65467468Snon	u_int len = 0, cnt;
65567468Snon
65667468Snon	slp->sl_flags &= ~HW_PDMASTART;
65767468Snon	nsp_setup_fifo(sc, 0);
65867468Snon
65967468Snon	if (ti->ti_phase == PH_DATA)
66067468Snon	{
66167468Snon		cnt = nsp_fifo_count(sc);
66267468Snon		if (slp->sl_scp.scp_direction  == SCSI_LOW_WRITE)
66367468Snon		{
66467468Snon			len = sc->sc_cnt - cnt;
66567468Snon			if (slp->sl_scp.scp_datalen + len <=
66667468Snon			    cb->ccb_scp.scp_datalen)
66767468Snon			{
66867468Snon				slp->sl_scp.scp_data -= len;
66967468Snon				slp->sl_scp.scp_datalen += len;
67067468Snon			}
67167468Snon			else
67267468Snon			{
67367468Snon				slp->sl_error |= PDMAERR;
67467468Snon				printf("%s len %x >= datalen %x\n",
67567468Snon					slp->sl_xname,
67667468Snon					len, slp->sl_scp.scp_datalen);
67767468Snon			}
67867468Snon		}
67967468Snon		else if (slp->sl_scp.scp_direction == SCSI_LOW_READ)
68067468Snon		{
68167468Snon			if (sc->sc_cnt != cnt)
68267468Snon			{
68367468Snon				slp->sl_error |= PDMAERR;
68467468Snon				printf("%s: data read count error %x != %x\n",
68567468Snon					slp->sl_xname, sc->sc_cnt, cnt);
68667468Snon			}
68767468Snon		}
68867468Snon		sc->sc_cnt = cnt;
68967468Snon	}
69067468Snon	else
69167468Snon	{
69267468Snon
69367468Snon		printf("%s data phase miss\n", slp->sl_xname);
69467468Snon		slp->sl_error |= PDMAERR;
69567468Snon	}
69667468Snon}
69767468Snon
69867468Snon#define	RFIFO_CRIT	64
69967468Snon#define	WFIFO_CRIT	64
70067468Snon
70167468Snonstatic void
70267468Snonnsp_pio_read(sc, ti)
70367468Snon	struct nsp_softc *sc;
70467468Snon	struct targ_info *ti;
70567468Snon{
70667468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
70767468Snon	bus_space_tag_t bst = sc->sc_iot;
70867468Snon	bus_space_handle_t bsh = sc->sc_ioh;
70967468Snon	int s;
71067468Snon	int tout = 0;
71167468Snon#ifdef __FreeBSD__
71267468Snon	struct callout_handle ch;
71367468Snon#endif
71467468Snon	u_int res, ocount, mask = sc->sc_mask;
71567468Snon	u_int8_t stat, fstat;
71667468Snon
71767468Snon	slp->sl_flags |= HW_PDMASTART;
71867468Snon	ocount = sc->sc_cnt;
71967468Snon
72067468Snon#ifdef __FreeBSD__
72167468Snon	ch = timeout(settimeout, &tout, 2 * hz);
72267468Snon#else
72367468Snon	timeout(settimeout, &tout, 2 * hz);
72467468Snon#endif
72567468Snon	while (slp->sl_scp.scp_datalen > 0 && tout == 0)
72667468Snon	{
72767468Snon		stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
72867468Snon		stat &= SCBUSMON_PHMASK;
72967468Snon		res = nsp_fifo_count(sc) - ocount;
73067468Snon		if (res == 0)
73167468Snon		{
73267468Snon			if (stat == PHASE_DATAIN)
73367468Snon				continue;
73467468Snon			break;
73567468Snon		}
73667468Snon
73767468Snon		fstat = bus_space_read_1(bst, bsh, nsp_fifosr);
73867468Snon		if ((fstat & FIFOSR_FULLEMP) == 0 && stat == PHASE_DATAIN)
73967468Snon			continue;
74067468Snon
74167468Snon		if (res > slp->sl_scp.scp_datalen)
74267468Snon			break;
74367468Snon
74467468Snon		if (res >= NSP_BUFFER_SIZE)
74567468Snon			res = NSP_BUFFER_SIZE;
74667468Snon		else
74767468Snon			res &= ~mask;
74867468Snon
74967468Snon		if (sc->sc_xfermr & XFERMR_MEM32)
75067468Snon		{
75167468Snon			bus_space_read_region_4(sc->sc_memt,
75267468Snon						sc->sc_memh,
75367468Snon						0,
75467468Snon					(u_int32_t *) slp->sl_scp.scp_data,
75567468Snon						res >> 2);
75667468Snon		}
75767468Snon		else
75867468Snon		{
75967468Snon			if (mask != 0)
76067468Snon				bus_space_read_multi_4(bst, bsh, nsp_fifodr,
76167468Snon					(u_int32_t *) slp->sl_scp.scp_data,
76267468Snon						       res >> 2);
76367468Snon			else
76467468Snon				bus_space_read_multi_1(bst, bsh, nsp_fifodr,
76567468Snon					(u_int8_t *) slp->sl_scp.scp_data,
76667468Snon						       res);
76767468Snon		}
76867468Snon
76967468Snon		slp->sl_scp.scp_data += res;
77067468Snon		slp->sl_scp.scp_datalen -= res;
77167468Snon		ocount += res;
77267468Snon	}
77367468Snon
77467468Snon	sc->sc_cnt = ocount;
77567468Snon	s = splhigh();
77667468Snon	if (tout == 0) {
77767468Snon#ifdef __FreeBSD__
77867468Snon		untimeout(settimeout, &tout, ch);
77967468Snon#else
78067468Snon		untimeout(settimeout, &tout);
78167468Snon#endif
78267468Snon		splx(s);
78367468Snon	} else {
78467468Snon		splx(s);
78567468Snon		printf("%s pio read timeout\n", slp->sl_xname);
78667468Snon	}
78767468Snon}
78867468Snon
78967468Snonstatic void
79067468Snonnsp_pio_write(sc, ti)
79167468Snon	struct nsp_softc *sc;
79267468Snon	struct targ_info *ti;
79367468Snon{
79467468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
79567468Snon	bus_space_tag_t bst = sc->sc_iot;
79667468Snon	bus_space_handle_t bsh = sc->sc_ioh;
79767468Snon	u_int res, ocount, mask = sc->sc_mask;
79867468Snon	int s;
79967468Snon	int tout = 0;
80067468Snon	register u_int8_t stat;
80167468Snon#ifdef __FreeBSD__
80267468Snon	struct callout_handle ch;
80367468Snon#endif
80467468Snon
80567468Snon	ocount = sc->sc_cnt;
80667468Snon	slp->sl_flags |= HW_PDMASTART;
80767468Snon#ifdef __FreeBSD__
80867468Snon	ch = timeout(settimeout, &tout, 2 * hz);
80967468Snon#else
81067468Snon	timeout(settimeout, &tout, 2 * hz);
81167468Snon#endif
81267468Snon	while (slp->sl_scp.scp_datalen > 0 && tout == 0)
81367468Snon	{
81467468Snon		stat = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
81567468Snon		stat &= SCBUSMON_PHMASK;
81667468Snon		if (stat != PHASE_DATAOUT)
81767468Snon			break;
81867468Snon
81967468Snon		res = ocount - nsp_fifo_count(sc);
82067468Snon		if (res > 0)
82167468Snon			continue;
82267468Snon
82367468Snon		res = (slp->sl_scp.scp_datalen > WFIFO_CRIT) ? WFIFO_CRIT :
82467468Snon						  slp->sl_scp.scp_datalen;
82567468Snon
82667468Snon		if (sc->sc_xfermr & XFERMR_MEM32)
82767468Snon		{
82867468Snon			bus_space_write_region_4(sc->sc_memt,
82967468Snon						 sc->sc_memh,
83067468Snon						 0,
83167468Snon					(u_int32_t *) slp->sl_scp.scp_data,
83267468Snon						 res >> 2);
83367468Snon		}
83467468Snon		else
83567468Snon		{
83667468Snon			if (mask != 0)
83767468Snon				bus_space_write_multi_4(bst, bsh, nsp_fifodr,
83867468Snon				(u_int32_t *) slp->sl_scp.scp_data, res >> 2);
83967468Snon			else
84067468Snon				bus_space_write_multi_1(bst, bsh, nsp_fifodr,
84167468Snon				(u_int8_t *) slp->sl_scp.scp_data, res);
84267468Snon		}
84367468Snon
84467468Snon		slp->sl_scp.scp_datalen -= res;
84567468Snon		slp->sl_scp.scp_data += res;
84667468Snon		ocount += res;
84767468Snon	}
84867468Snon
84967468Snon	sc->sc_cnt = ocount;
85067468Snon	s = splhigh();
85167468Snon	if (tout == 0) {
85267468Snon#ifdef __FreeBSD__
85367468Snon		untimeout(settimeout, &tout, ch);
85467468Snon#else
85567468Snon		untimeout(settimeout, &tout);
85667468Snon#endif
85767468Snon		splx(s);
85867468Snon	} else {
85967468Snon		splx(s);
86067468Snon		printf("%s pio write timeout\n", slp->sl_xname);
86167468Snon	}
86267468Snon}
86367468Snon
86467468Snonstatic void
86567468Snonsettimeout(arg)
86667468Snon	void *arg;
86767468Snon{
86867468Snon	int *tout = arg;
86967468Snon
87067468Snon	*tout = 1;
87167468Snon}
87267468Snon
87367468Snonstatic int
87467468Snonnsp_negate_signal(sc, mask, s)
87567468Snon	struct nsp_softc *sc;
87667468Snon	u_int8_t mask;
87767468Snon	u_char *s;
87867468Snon{
87967468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
88067468Snon	bus_space_tag_t bst = sc->sc_iot;
88167468Snon	bus_space_handle_t bsh = sc->sc_ioh;
88267468Snon	int tout = 0;
88370597Snon	int ss;
88467468Snon#ifdef __FreeBSD__
88567468Snon	struct callout_handle ch;
88667468Snon#endif
88767468Snon	u_int8_t regv;
88867468Snon
88967468Snon#ifdef __FreeBSD__
89067468Snon	ch = timeout(settimeout, &tout, hz/2);
89167468Snon#else
89267468Snon	timeout(settimeout, &tout, hz/2);
89367468Snon#endif
89467468Snon	do
89567468Snon	{
89667468Snon		regv = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
89767468Snon		if (regv == 0xff)
89867468Snon			break;
89967468Snon	}
90067468Snon	while ((regv & mask) != 0 && tout == 0);
90167468Snon
90270597Snon	ss = splhigh();
90367468Snon	if (tout == 0) {
90467468Snon#ifdef __FreeBSD__
90567468Snon		untimeout(settimeout, &tout, ch);
90667468Snon#else
90767468Snon		untimeout(settimeout, &tout);
90867468Snon#endif
90970597Snon		splx(ss);
91067468Snon	} else {
91170597Snon		splx(ss);
91267468Snon		printf("%s: %s singla off timeout \n", slp->sl_xname, s);
91367468Snon	}
91467468Snon
91567468Snon	return 0;
91667468Snon}
91767468Snon
91867468Snonstatic int
91967468Snonnsp_xfer(sc, buf, len, phase)
92067468Snon	struct nsp_softc *sc;
92167468Snon	u_int8_t *buf;
92267468Snon	int len;
92367468Snon	int phase;
92467468Snon{
92567468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
92667468Snon	bus_space_tag_t bst = sc->sc_iot;
92767468Snon	bus_space_handle_t bsh = sc->sc_ioh;
92867468Snon	int ptr, rv, atn;
92967468Snon
93067468Snon	atn = (scsi_low_is_msgout_continue(slp->sl_nexus) != 0);
93167468Snon	for (ptr = 0; len > 0; len --, ptr ++)
93267468Snon	{
93367468Snon		rv = nsp_expect_signal(sc, phase, SCBUSMON_REQ);
93467468Snon		if (rv <= 0)
93567468Snon			goto out;
93667468Snon
93767468Snon		if (len == 1 && atn == 0)
93867468Snon		{
93967468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
94067468Snon				       SCBUSCR_ADIR | SCBUSCR_ACKEN);
94167468Snon		}
94267468Snon
94367468Snon		if (phase & SCBUSMON_IO)
94467468Snon		{
94567468Snon			buf[ptr] = nsp_cr_read_1(bst, bsh, NSPR_DATAACK);
94667468Snon		}
94767468Snon		else
94867468Snon		{
94967468Snon			nsp_cr_write_1(bst, bsh, NSPR_DATAACK, buf[ptr]);
95067468Snon		}
95167468Snon		nsp_negate_signal(sc, SCBUSMON_ACK, "xfer<ACK>");
95267468Snon	}
95367468Snon
95467468Snonout:
95567468Snon	return len;
95667468Snon}
95767468Snon
95867468Snonstatic int
95967468Snonnsp_dataphase_bypass(sc, ti)
96067468Snon	struct nsp_softc *sc;
96167468Snon	struct targ_info *ti;
96267468Snon{
96367468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
96467468Snon	struct slccb *cb = ti->ti_nexus;
96567468Snon	u_int cnt;
96667468Snon
96767468Snon	if (slp->sl_scp.scp_direction != SCSI_LOW_READ ||
96867468Snon	    (slp->sl_scp.scp_datalen % DEV_BSIZE) == 0)
96967468Snon		return 0;
97067468Snon
97167468Snon	cnt = nsp_fifo_count(sc);
97267468Snon	if (sc->sc_cnt == cnt)
97367468Snon		return 0;
97467468Snon	if (cnt >= DEV_BSIZE)
97567468Snon		return EINVAL;
97667468Snon
97767468Snon	if (cb == NULL)
97867468Snon		return 0;
97967468Snon
98067468Snon	/*
98167468Snon	 * XXX: NSP_QUIRK
98267468Snon	 * Data phase skip only occures in case of SCSI_LOW_READ.
98367468Snon	 */
98467468Snon	SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
98567468Snon	nsp_pio_read(sc, ti);
98667468Snon	nsp_pdma_end(sc, ti);
98767468Snon#ifdef	NSP_STATICS
98867468Snon	nsp_statics[ti->ti_id].data_phase_bypass ++;
98967468Snon#endif	/* NSP_STATICS */
99067468Snon	return 0;
99167468Snon}
99267468Snon
99367468Snon/**************************************************************
99467468Snon * disconnect & reselect (HW low)
99567468Snon **************************************************************/
99667468Snonstatic int
99767468Snonnsp_reselected(sc)
99867468Snon	struct nsp_softc *sc;
99967468Snon{
100067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
100167468Snon	bus_space_tag_t bst = sc->sc_iot;
100267468Snon	bus_space_handle_t bsh = sc->sc_ioh;
100367468Snon	struct targ_info *ti;
100467468Snon	u_int sid;
100567468Snon	u_int8_t cr;
100667468Snon
100767468Snon	sid = (u_int) nsp_cr_read_1(bst, bsh, NSPR_RESELR);
100867468Snon	sid &= ~sc->sc_idbit;
100967468Snon	sid = ffs(sid) - 1;
101067468Snon	if ((ti = scsi_low_reselected(slp, sid)) == NULL)
101167468Snon		return EJUSTRETURN;
101267468Snon
101367468Snon	nsp_negate_signal(sc, SCBUSMON_SEL, "reselect<SEL>");
101467468Snon
101567468Snon	cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR) & ~(SCBUSCR_BSY | SCBUSCR_ATN);
101667468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
101767468Snon	nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr | SCBUSCR_ADIR | SCBUSCR_ACKEN);
101867468Snon
101967468Snon#ifdef	NSP_STATICS
102067468Snon	nsp_statics[sid].reselect ++;
102167468Snon#endif	/* NSP_STATCIS */
102267468Snon	return EJUSTRETURN;
102367468Snon}
102467468Snon
102567468Snonstatic __inline int
102667468Snonnsp_disconnected(sc, ti)
102767468Snon	struct nsp_softc *sc;
102867468Snon	struct targ_info *ti;
102967468Snon{
103067468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
103167468Snon
103267468Snon#ifdef	NSP_STATICS
103367468Snon	if (slp->sl_msgphase == MSGPH_DISC)
103467468Snon		nsp_statics[ti->ti_id].disconnect ++;
103567468Snon#endif	/* NSP_STATICS */
103667468Snon
103767468Snon	scsi_low_disconnected(slp, ti);
103867468Snon	return 1;
103967468Snon}
104067468Snon
104167468Snon/**************************************************************
104267468Snon * SEQUENCER
104367468Snon **************************************************************/
104467468Snonstatic void nspmsg __P((struct nsp_softc *, u_char *, u_int8_t, u_int8_t, u_int8_t));
104567468Snon
104667468Snonstatic void
104767468Snonnspmsg(sc, s, isrc, ph, irqphs)
104867468Snon	struct nsp_softc *sc;
104967468Snon	u_char *s;
105067468Snon	u_int8_t isrc, ph, irqphs;
105167468Snon{
105267468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
105367468Snon
105467468Snon	printf("%s: %s\n", slp->sl_xname, s);
105567468Snon	printf("%s: isrc 0x%x scmon 0x%x irqphs 0x%x\n",
105667468Snon	       slp->sl_xname, (u_int) isrc, (u_int) ph, (u_int) irqphs);
105767468Snon}
105867468Snon
105967468Snonstatic int
106067468Snonnsp_nexus(sc, ti)
106167468Snon	struct nsp_softc *sc;
106267468Snon	struct targ_info *ti;
106367468Snon{
106467468Snon	bus_space_tag_t bst = sc->sc_iot;
106567468Snon	bus_space_handle_t bsh = sc->sc_ioh;
106667468Snon	struct nsp_lun_info *nli = (void *) ti->ti_li;
106767468Snon
106867468Snon	/* setup synch transfer registers */
106967468Snon	nsp_cr_write_1(bst, bsh, NSPR_SYNCR, nli->nli_reg_syncr);
107067468Snon	nsp_cr_write_1(bst, bsh, NSPR_ACKWIDTH, nli->nli_reg_ackwidth);
107167468Snon
107267468Snon	/* setup pdma fifo */
107367468Snon	nsp_setup_fifo(sc, 1);
107467468Snon
107567468Snon	/* clear ack counter */
107667468Snon	sc->sc_cnt = 0;
107767468Snon	nsp_cr_write_1(bst, bsh, NSPR_PTCLRR, PTCLRR_PT | PTCLRR_ACK |
107867468Snon			PTCLRR_REQ | PTCLRR_HOST);
107967468Snon	return 0;
108067468Snon}
108167468Snon
108267468Snonint
108367468Snonnspintr(arg)
108467468Snon	void *arg;
108567468Snon{
108667468Snon	struct nsp_softc *sc = arg;
108767468Snon	struct scsi_low_softc *slp = &sc->sc_sclow;
108867468Snon	bus_space_tag_t bst = sc->sc_iot;
108967468Snon	bus_space_handle_t bsh = sc->sc_ioh;
109067468Snon	struct targ_info *ti;
109167468Snon	struct physio_proc *pp;
109267468Snon	struct buf *bp;
109367468Snon	int len, rv;
109467468Snon	u_int8_t isrc, ph, irqphs, cr, regv;
109567468Snon
109667468Snon	/*******************************************
109767468Snon	 * interrupt check
109867468Snon	 *******************************************/
109967468Snon	if (slp->sl_flags & HW_INACTIVE)
110067468Snon		return 0;
110167468Snon
110267468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_IRQDIS);
110367468Snon	isrc = bus_space_read_1(bst, bsh, nsp_irqsr);
110467468Snon	if (isrc == 0xff || (isrc & IRQSR_MASK) == 0)
110567468Snon	{
110667468Snon		bus_space_write_1(bst, bsh, nsp_irqcr, 0);
110767468Snon		return 0;
110867468Snon	}
110967468Snon
111067468Snon	/* XXX: IMPORTANT
111167468Snon 	 * Do not read an irqphs register if no scsi phase interrupt.
111267468Snon	 * Unless, you should lose a scsi phase interrupt.
111367468Snon	 */
111467468Snon	ph = nsp_cr_read_1(bst, bsh, NSPR_SCBUSMON);
111567468Snon	if ((isrc & IRQSR_SCSI) != 0)
111667468Snon	{
111767468Snon		irqphs = nsp_cr_read_1(bst, bsh, NSPR_IRQPHS);
111867468Snon	}
111967468Snon	else
112067468Snon		irqphs = 0;
112167468Snon
112267468Snon	/*
112367468Snon 	 * timer interrupt handler (scsi vs timer interrupts)
112467468Snon	 */
112567468Snon	if (sc->sc_timer != 0)
112667468Snon	{
112767468Snon		nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
112867468Snon		nsp_cr_write_1(bst, bsh, NSPR_TIMERCNT, 0);
112967468Snon		sc->sc_timer = 0;
113067468Snon	}
113167468Snon
113267468Snon	if ((isrc & IRQSR_MASK) == IRQSR_TIMER && sc->sc_seltout == 0)
113367468Snon	{
113467468Snon		bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL);
113567468Snon		return 1;
113667468Snon	}
113767468Snon
113867468Snon	bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_TIMERCL | IRQCR_FIFOCL);
113967468Snon
114067468Snon	/*******************************************
114167468Snon	 * debug section
114267468Snon	 *******************************************/
114367468Snon#ifdef	NSP_DEBUG
114467468Snon	if (nsp_debug)
114567468Snon	{
114667468Snon		nspmsg(sc, "current status", isrc, ph, irqphs);
114767468Snon		scsi_low_print(slp, NULL);
114867468Snon		if (nsp_debug > 1)
114967468Snon			Debugger();
115067468Snon	}
115167468Snon#endif	/* NSP_DEBUG */
115267468Snon
115367468Snon	/*******************************************
115467468Snon	 * Parse hardware SCSI irq reasons register
115567468Snon	 *******************************************/
115667468Snon	if ((isrc & IRQSR_SCSI) != 0)
115767468Snon	{
115867468Snon 		if ((irqphs & IRQPHS_RST) != 0)
115967468Snon		{
116067468Snon			scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT,
116167468Snon					 "bus reset (power off?)");
116267468Snon			return 1;
116367468Snon		}
116467468Snon
116567468Snon		if ((irqphs & IRQPHS_RSEL) != 0)
116667468Snon		{
116767468Snon			bus_space_write_1(bst, bsh, nsp_irqcr, IRQCR_RESCL);
116867468Snon			if (nsp_reselected(sc) == EJUSTRETURN)
116967468Snon				return 1;
117067468Snon		}
117167468Snon
117267468Snon		if ((irqphs & (IRQPHS_PCHG | IRQPHS_LBF)) == 0)
117367468Snon			return 1;
117467468Snon	}
117567468Snon
117667468Snon	/*******************************************
117767468Snon	 * nexus check
117867468Snon	 *******************************************/
117967468Snon	if ((ti = slp->sl_nexus) == NULL)
118067468Snon	{
118167468Snon		/* unknown scsi phase changes */
118267468Snon		nspmsg(sc, "unknown scsi phase changes", isrc, ph, irqphs);
118367468Snon		return 0;
118467468Snon	}
118567468Snon
118667468Snon	/*******************************************
118767468Snon	 * aribitration & selection
118867468Snon	 *******************************************/
118967468Snon	switch (ti->ti_phase)
119067468Snon	{
119167468Snon	case PH_SELSTART:
119267468Snon		if ((ph & SCBUSMON_BSY) == 0)
119367468Snon		{
119467468Snon			if (sc->sc_seltout >= NSP_SELTIMEOUT)
119567468Snon			{
119667468Snon				sc->sc_seltout = 0;
119767468Snon				nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, 0);
119867468Snon				return nsp_disconnected(sc, ti);
119967468Snon			}
120067468Snon			sc->sc_seltout ++;
120167468Snon			nsp_start_timer(sc, 1000 / 51);
120267468Snon			return 1;
120367468Snon		}
120467468Snon
120567468Snon		/* attention assert */
120667468Snon		sc->sc_seltout = 0;
120767468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED);
120867468Snon		nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, sc->sc_busc);
120967468Snon		delay(1);
121067468Snon		nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR,
121167468Snon				sc->sc_busc | SCBUSCR_ADIR | SCBUSCR_ACKEN);
121267468Snon
121367468Snon		SCSI_LOW_TARGET_ASSERT_ATN(ti);
121467468Snon		scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_IDENTIFY, 0);
121567468Snon		return 1;
121667468Snon
121767468Snon	case PH_RESEL:
121867468Snon		if ((ph & SCBUSMON_PHMASK) != PHASE_MSGIN)
121967468Snon		{
122067468Snon			scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1);
122167468Snon			return 1;
122267468Snon		}
122367468Snon		/* fall */
122467468Snon
122567468Snon	default:
122667468Snon		if ((isrc & (IRQSR_SCSI | IRQSR_FIFO)) == 0)
122767468Snon			return 1;
122867468Snon		break;
122967468Snon	}
123067468Snon
123167468Snon	/*******************************************
123267468Snon	 * scsi seq
123367468Snon	 *******************************************/
123467468Snon	if (slp->sl_flags & HW_PDMASTART)
123567468Snon		nsp_pdma_end(sc, ti);
123667468Snon
123767468Snon	/* normal disconnect */
123867468Snon	if (slp->sl_msgphase != 0 && (irqphs & IRQPHS_LBF) != 0)
123967468Snon		return nsp_disconnected(sc, ti);
124067468Snon
124167468Snon	/* check unexpected bus free state */
124267468Snon	if (ph == 0)
124367468Snon	{
124467468Snon		nspmsg(sc, "unexpected bus free", isrc, ph, irqphs);
124567468Snon		return nsp_disconnected(sc, ti);
124667468Snon	}
124767468Snon
124867468Snon	/* check normal scsi phase */
124967468Snon	switch (ph & SCBUSMON_PHMASK)
125067468Snon	{
125167468Snon	case PHASE_CMD:
125267468Snon		if ((ph & SCBUSMON_REQ) == 0)
125367468Snon			return 1;
125467468Snon
125567468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_CMD);
125667468Snon		if (scsi_low_cmd(slp, ti) != 0)
125767468Snon			break;
125867468Snon
125967468Snon		nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR);
126067468Snon		for (len = 0; len < slp->sl_scp.scp_cmdlen; len ++)
126167468Snon			nsp_cr_write_1(bst, bsh, NSPR_CMDDR,
126267468Snon				       slp->sl_scp.scp_cmd[len]);
126367468Snon
126467468Snon		nsp_cr_write_1(bst, bsh, NSPR_CMDCR, CMDCR_PTCLR | CMDCR_EXEC);
126567468Snon		break;
126667468Snon
126767468Snon	case PHASE_DATAOUT:
126867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
126967468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0)
127067468Snon			break;
127167468Snon
127267468Snon		pp = physio_proc_enter(bp);
127367468Snon		nsp_pio_write(sc, ti);
127467468Snon		physio_proc_leave(pp);
127567468Snon		break;
127667468Snon
127767468Snon	case PHASE_DATAIN:
127867468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_DATA);
127967468Snon		if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0)
128067468Snon			break;
128167468Snon
128267468Snon		pp = physio_proc_enter(bp);
128367468Snon		nsp_pio_read(sc, ti);
128467468Snon		physio_proc_leave(pp);
128567468Snon		break;
128667468Snon
128767468Snon	case PHASE_STATUS:
128867468Snon		nsp_dataphase_bypass(sc, ti);
128967468Snon		if ((ph & SCBUSMON_REQ) == 0)
129067468Snon			return 1;
129167468Snon
129267468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_STAT);
129367468Snon		ti->ti_status = nsp_cr_read_1(bst, bsh, NSPR_DATAACK);
129467468Snon		break;
129567468Snon
129667468Snon	case PHASE_MSGOUT:
129767468Snon		if ((ph & SCBUSMON_REQ) == 0)
129867468Snon			goto timerout;
129967468Snon
130067468Snon		/*
130167468Snon		 * XXX: NSP QUIRK
130267468Snon		 * NSP invoke interrupts only in the case of scsi phase changes,
130367468Snon		 * therefore we should poll the scsi phase here to catch
130467468Snon		 * the next "msg out" if exists (no scsi phase changes).
130567468Snon		 */
130667468Snon		rv = len = 16;
130767468Snon		do {
130867468Snon			SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT);
130967468Snon
131067468Snon			len = scsi_low_msgout(slp, ti);
131167468Snon			if (nsp_xfer(sc, ti->ti_msgoutstr, len, PHASE_MSGOUT))
131267468Snon			{
131367468Snon				scsi_low_assert_msg(slp, ti,
131467468Snon						    SCSI_LOW_MSG_RESET, 0);
131567468Snon				nspmsg(sc, "MSGOUT: xfer short",
131667468Snon						    isrc, ph, irqphs);
131767468Snon			}
131867468Snon
131967468Snon			/* catch a next signal */
132067468Snon			rv = nsp_expect_signal(sc, PHASE_MSGOUT, SCBUSMON_REQ);
132167468Snon		}
132267468Snon		while (rv > 0 && len -- > 0);
132367468Snon		break;
132467468Snon
132567468Snon	case PHASE_MSGIN:
132667468Snon		nsp_dataphase_bypass(sc, ti);
132767468Snon		if ((ph & SCBUSMON_REQ) == 0)
132867468Snon			goto timerout;
132967468Snon
133067468Snon		SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN);
133167468Snon
133267468Snon		/*
133367468Snon		 * XXX: NSP QUIRK
133467468Snon		 * NSP invoke interrupts only in the case of scsi phase changes,
133567468Snon		 * therefore we should poll the scsi phase here to catch
133667468Snon		 * the next "msg in" if exists (no scsi phase changes).
133767468Snon		 */
133867468Snon		rv = len = 16;
133967468Snon		do {
134067468Snon			/* read a data */
134167468Snon			regv = nsp_cr_read_1(bst, bsh, NSPR_DATA);
134267468Snon
134367468Snon			/* assert ack */
134467468Snon			cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
134567468Snon			cr |= SCBUSCR_ACK;
134667468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
134767468Snon			nsp_negate_signal(sc, SCBUSMON_REQ, "msgin<REQ>");
134867468Snon
134967468Snon			scsi_low_msgin(slp, ti, regv);
135067468Snon
135167468Snon			/* deassert ack */
135267468Snon			cr = nsp_cr_read_1(bst, bsh, NSPR_SCBUSCR);
135367468Snon			cr &= ~SCBUSCR_ACK;
135467468Snon			nsp_cr_write_1(bst, bsh, NSPR_SCBUSCR, cr);
135567468Snon
135667468Snon			/* catch a next signal */
135767468Snon			rv = nsp_expect_signal(sc, PHASE_MSGIN, SCBUSMON_REQ);
135867468Snon		}
135967468Snon		while (rv > 0 && len -- > 0);
136067468Snon		break;
136167468Snon
136267468Snon	case PHASE_SEL:
136367468Snon	default:
136467468Snon		nspmsg(sc, "unknown scsi phase", isrc, ph, irqphs);
136567468Snon		break;
136667468Snon	}
136767468Snon
136867468Snon	return 1;
136967468Snon
137067468Snontimerout:
137167468Snon	nsp_start_timer(sc, 1000 / 102);
137267468Snon	return 0;
137367468Snon}
1374