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