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