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$"); 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> 5067468Snon 5167468Snon#include <machine/cpu.h> 5267468Snon#include <machine/bus.h> 5367468Snon 54126928Speter#include <compat/netbsd/dvcfg.h> 5567468Snon 5667468Snon#include <cam/scsi/scsi_low.h> 5767468Snon 5867468Snon#include <dev/ncv/ncr53c500reg.h> 5967468Snon#include <dev/ncv/ncr53c500hw.h> 6067468Snon#include <dev/ncv/ncr53c500var.h> 6167468Snon 6267468Snon#include <dev/ncv/ncr53c500hwtab.h> 6367468Snon 6479697Snon#define NCV_MAX_DATA_SIZE (64 * 1024) 6579697Snon#define NCV_DELAY_MAX (2 * 1000 * 1000) 6679697Snon#define NCV_DELAY_INTERVAL (1) 6779697Snon#define NCV_PADDING_SIZE (32) 6879697Snon 6967468Snon/*************************************************** 7079697Snon * IO control 7179697Snon ***************************************************/ 7279697Snon#define NCV_READ_INTERRUPTS_DRIVEN 0x0001 7379697Snon#define NCV_WRITE_INTERRUPTS_DRIVEN 0x0002 7479697Snon#define NCV_ENABLE_FAST_SCSI 0x0010 7579697Snon#define NCV_FAST_INTERRUPTS 0x0100 7679697Snon 7779697Snonu_int ncv_io_control = NCV_IO_CONTROL_FLAGS; 7879697Snonint ncv_data_read_bytes = 4096; 7979697Snonint ncv_data_write_bytes = 4096; 8079697Snon 8179697Snon/*************************************************** 8267468Snon * DEBUG 8367468Snon ***************************************************/ 8467468Snon#ifdef NCV_DEBUG 8589093Smsmithstatic int ncv_debug; 8667468Snon#endif /* NCV_DEBUG */ 8767468Snon 8867468Snon#ifdef NCV_STATICS 8989093Smsmithstatic struct ncv_statics { 9067468Snon int disconnect; 9167468Snon int reselect; 9279697Snon} ncv_statics; 9367468Snon#endif /* NCV_STATICS */ 9467468Snon 9567468Snon/*************************************************** 9679697Snon * DEVICE STRUCTURE 9767468Snon ***************************************************/ 9867468Snonextern struct cfdriver ncv_cd; 9967468Snon 10067468Snon/************************************************************** 10167468Snon * DECLARE 10267468Snon **************************************************************/ 10367468Snon/* static */ 10492739Salfredstatic void ncv_pio_read(struct ncv_softc *, u_int8_t *, u_int); 10592739Salfredstatic void ncv_pio_write(struct ncv_softc *, u_int8_t *, u_int); 10692739Salfredstatic int ncv_msg(struct ncv_softc *, struct targ_info *, u_int); 10792739Salfredstatic int ncv_reselected(struct ncv_softc *); 10892739Salfredstatic int ncv_disconnected(struct ncv_softc *, struct targ_info *); 10967468Snon 11092739Salfredstatic __inline void ncvhw_set_count(bus_space_tag_t, bus_space_handle_t, int); 11192739Salfredstatic __inline u_int ncvhw_get_count(bus_space_tag_t, bus_space_handle_t); 11292739Salfredstatic __inline void ncvhw_select_register_0(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); 11392739Salfredstatic __inline void ncvhw_select_register_1(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); 11492739Salfredstatic __inline void ncvhw_fpush(bus_space_tag_t, bus_space_handle_t, u_int8_t *, int); 11567468Snon 11692739Salfredstatic void ncv_pdma_end(struct ncv_softc *sc, struct targ_info *); 11792739Salfredstatic int ncv_world_start(struct ncv_softc *, int); 11892739Salfredstatic void ncvhw_bus_reset(struct ncv_softc *); 11992739Salfredstatic void ncvhw_reset(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); 12092739Salfredstatic int ncvhw_check(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); 12192739Salfredstatic void ncvhw_init(bus_space_tag_t, bus_space_handle_t, struct ncv_hw *); 12292739Salfredstatic int ncvhw_start_selection(struct ncv_softc *sc, struct slccb *); 12392739Salfredstatic void ncvhw_attention(struct ncv_softc *); 12492739Salfredstatic int ncv_ccb_nexus_establish(struct ncv_softc *); 12592739Salfredstatic int ncv_lun_nexus_establish(struct ncv_softc *); 12692739Salfredstatic int ncv_target_nexus_establish(struct ncv_softc *); 12792739Salfredstatic int ncv_targ_init(struct ncv_softc *, struct targ_info *, int); 12892739Salfredstatic int ncv_catch_intr(struct ncv_softc *); 12967468Snon#ifdef NCV_POWER_CONTROL 13092739Salfredstatic int ncvhw_power(struct ncv_softc *, u_int); 13179697Snon#endif /* NCV_POWER_CONTROL */ 13292739Salfredstatic __inline void ncv_setup_and_start_pio(struct ncv_softc *, u_int); 13367468Snon 13467468Snonstruct scsi_low_funcs ncv_funcs = { 13567468Snon SC_LOW_INIT_T ncv_world_start, 13667468Snon SC_LOW_BUSRST_T ncvhw_bus_reset, 13773025Snon SC_LOW_TARG_INIT_T ncv_targ_init, 13879697Snon SC_LOW_LUN_INIT_T NULL, 13967468Snon 14067468Snon SC_LOW_SELECT_T ncvhw_start_selection, 14179697Snon SC_LOW_NEXUS_T ncv_lun_nexus_establish, 14279697Snon SC_LOW_NEXUS_T ncv_ccb_nexus_establish, 14367468Snon 14467468Snon SC_LOW_ATTEN_T ncvhw_attention, 14567468Snon SC_LOW_MSG_T ncv_msg, 14667468Snon 14779697Snon SC_LOW_TIMEOUT_T NULL, 14867468Snon SC_LOW_POLL_T ncvintr, 14967468Snon 15067468Snon NULL, /* SC_LOW_POWER_T ncvhw_power, */ 15167468Snon}; 15267468Snon 15367468Snon/************************************************************** 15467468Snon * hwfuncs 15567468Snon **************************************************************/ 15667468Snonstatic __inline void 15767468Snonncvhw_select_register_0(iot, ioh, hw) 15867468Snon bus_space_tag_t iot; 15967468Snon bus_space_handle_t ioh; 16067468Snon struct ncv_hw *hw; 16167468Snon{ 16267468Snon 16379697Snon bus_space_write_1(iot, ioh, cr0_cfg4, hw->hw_cfg4); 16467468Snon} 16567468Snon 16667468Snonstatic __inline void 16767468Snonncvhw_select_register_1(iot, ioh, hw) 16867468Snon bus_space_tag_t iot; 16967468Snon bus_space_handle_t ioh; 17067468Snon struct ncv_hw *hw; 17167468Snon{ 17267468Snon 17379697Snon bus_space_write_1(iot, ioh, cr1_cfg5, hw->hw_cfg5); 17467468Snon} 17567468Snon 17667468Snonstatic __inline void 17767468Snonncvhw_fpush(iot, ioh, buf, len) 17867468Snon bus_space_tag_t iot; 17967468Snon bus_space_handle_t ioh; 18067468Snon u_int8_t *buf; 18167468Snon int len; 18267468Snon{ 18367468Snon int ptr; 18467468Snon 18567468Snon for (ptr = 0; ptr < len; ptr ++) 18667468Snon bus_space_write_1(iot, ioh, cr0_sfifo, buf[ptr]); 18767468Snon} 18867468Snon 18979697Snonstatic __inline void 19079697Snonncvhw_set_count(iot, ioh, count) 19179697Snon bus_space_tag_t iot; 19279697Snon bus_space_handle_t ioh; 19379697Snon int count; 19479697Snon{ 19579697Snon 19679697Snon bus_space_write_1(iot, ioh, cr0_tclsb, (u_int8_t) count); 19779697Snon bus_space_write_1(iot, ioh, cr0_tcmsb, (u_int8_t) (count >> NBBY)); 19879697Snon bus_space_write_1(iot, ioh, cr0_tchsb, (u_int8_t) (count >> (NBBY * 2))); 19979697Snon} 20079697Snon 20179697Snonstatic __inline u_int 20279697Snonncvhw_get_count(iot, ioh) 20379697Snon bus_space_tag_t iot; 20479697Snon bus_space_handle_t ioh; 20579697Snon{ 20679697Snon u_int count; 20779697Snon 20879697Snon count = (u_int) bus_space_read_1(iot, ioh, cr0_tclsb); 20979697Snon count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tcmsb)) << NBBY; 21079697Snon count |= ((u_int) bus_space_read_1(iot, ioh, cr0_tchsb)) << (NBBY * 2); 21179697Snon return count; 21279697Snon} 21379697Snon 21467468Snonstatic int 21567468Snonncvhw_check(iot, ioh, hw) 21667468Snon bus_space_tag_t iot; 21767468Snon bus_space_handle_t ioh; 21867468Snon struct ncv_hw *hw; 21967468Snon{ 22067468Snon u_int8_t stat; 22167468Snon 22267468Snon ncvhw_select_register_0(iot, ioh, hw); 22367468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 22467468Snon if (bus_space_read_1(iot, ioh, cr0_cmd) != (CMD_NOP | CMD_DMA)) 22567468Snon { 22667468Snon#ifdef NCV_DEBUG 22767468Snon printf("ncv: cr0_cmd CMD_NOP|CMD_DMA failed\n"); 22867468Snon#endif /* NCV_DEBUG */ 22967468Snon return ENODEV; 23067468Snon } 23167468Snon 23267468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 23367468Snon if (bus_space_read_1(iot, ioh, cr0_cmd) != CMD_NOP) 23467468Snon { 23567468Snon#ifdef NCV_DEBUG 23667468Snon printf("ncv: cr0_cmd CMD_NOP failed\n"); 23767468Snon#endif /* NCV_DEBUG */ 23867468Snon return ENODEV; 23967468Snon } 24067468Snon 24167468Snon /* hardware reset */ 24267468Snon ncvhw_reset(iot, ioh, hw); 24367468Snon ncvhw_init(iot, ioh, hw); 24467468Snon 24567468Snon /* bus reset */ 24667468Snon ncvhw_select_register_0(iot, ioh, hw); 24767468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 24867468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); 24967468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 250240172Sjhb DELAY(100 * 1000); 25167468Snon 25267468Snon /* check response */ 25367468Snon bus_space_read_1(iot, ioh, cr0_stat); 25467468Snon stat = bus_space_read_1(iot, ioh, cr0_istat); 255240172Sjhb DELAY(1000); 25667468Snon 25767468Snon if (((stat & INTR_SBR) == 0) || 25867468Snon (bus_space_read_1(iot, ioh, cr0_istat) & INTR_SBR)) 25967468Snon { 26067468Snon#ifdef NCV_DEBUG 26167468Snon printf("ncv: cr0_istat SCSI BUS RESET failed\n"); 26267468Snon#endif /* NCV_DEBUG */ 26367468Snon return ENODEV; 26467468Snon } 26567468Snon 26667468Snon return 0; 26767468Snon} 26867468Snon 26967468Snonstatic void 27067468Snonncvhw_reset(iot, ioh, hw) 27167468Snon bus_space_tag_t iot; 27267468Snon bus_space_handle_t ioh; 27367468Snon struct ncv_hw *hw; 27467468Snon{ 27567468Snon 27667468Snon ncvhw_select_register_0(iot, ioh, hw); 27767468Snon 27867468Snon /* dummy cmd twice */ 27967468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 28067468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 28167468Snon 28267468Snon /* chip reset */ 28367468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTCHIP); 28467468Snon 28567468Snon /* again dummy cmd twice */ 28667468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 28767468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP); 28867468Snon} 28967468Snon 29067468Snonstatic void 29167468Snonncvhw_init(iot, ioh, hw) 29267468Snon bus_space_tag_t iot; 29367468Snon bus_space_handle_t ioh; 29467468Snon struct ncv_hw *hw; 29567468Snon{ 29667468Snon 29767468Snon ncvhw_select_register_0(iot, ioh, hw); 29879697Snon bus_space_write_1(iot, ioh, cr0_clk, hw->hw_clk); 29967468Snon bus_space_write_1(iot, ioh, cr0_srtout, SEL_TOUT); 30067468Snon bus_space_write_1(iot, ioh, cr0_period, 0); 30167468Snon bus_space_write_1(iot, ioh, cr0_offs, 0); 30267468Snon 30379697Snon bus_space_write_1(iot, ioh, cr0_cfg1, hw->hw_cfg1); 30479697Snon bus_space_write_1(iot, ioh, cr0_cfg2, hw->hw_cfg2); 30579697Snon bus_space_write_1(iot, ioh, cr0_cfg3, hw->hw_cfg3); 30667468Snon bus_space_write_1(iot, ioh, cr0_tchsb, 0); 30767468Snon 30867468Snon ncvhw_select_register_1(iot, ioh, hw); 30967468Snon bus_space_write_1(iot, ioh, cr1_fstat, 0x0); 31067468Snon bus_space_write_1(iot, ioh, cr1_pflag, 0x0); 31167468Snon bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); 31267468Snon 31367468Snon ncvhw_select_register_0(iot, ioh, hw); 31467468Snon} 31567468Snon 31667468Snon#ifdef NCV_POWER_CONTROL 31767468Snonstatic int 31867468Snonncvhw_power(sc, flags) 31967468Snon struct ncv_softc *sc; 32067468Snon u_int flags; 32167468Snon{ 32267468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 32367468Snon bus_space_tag_t iot = sc->sc_iot; 32467468Snon bus_space_handle_t ioh = sc->sc_ioh; 32567468Snon 32667468Snon if (flags == SCSI_LOW_POWDOWN) 32767468Snon { 328240325Sjhb device_printf(slp->sl_dev, "power down\n"); 32967468Snon ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 33067468Snon bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_POWDOWN); 33167468Snon } 33267468Snon else 33367468Snon { 33467468Snon switch (sc->sc_rstep) 33567468Snon { 33667468Snon case 0: 337240325Sjhb device_printf(slp->sl_dev, "resume step O\n"); 33867468Snon ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 33967468Snon bus_space_write_1(iot, ioh, cr1_atacmd, ATACMD_ENGAGE); 34067468Snon break; 34167468Snon 34267468Snon case 1: 343240325Sjhb device_printf(slp->sl_dev, "resume step I\n"); 34467468Snon ncvhw_reset(iot, ioh, &sc->sc_hw); 34567468Snon ncvhw_init(iot, ioh, &sc->sc_hw); 34667468Snon break; 34767468Snon } 34867468Snon } 34967468Snon 35067468Snon return 0; 35167468Snon} 35267468Snon#endif /* NCV_POWER_CONTROL */ 35367468Snon 35467468Snon/************************************************************** 35567468Snon * scsi low interface 35667468Snon **************************************************************/ 35767468Snonstatic void 35867468Snonncvhw_attention(sc) 35967468Snon struct ncv_softc *sc; 36067468Snon{ 36167468Snon 36267468Snon bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, CMD_SETATN); 363240172Sjhb DELAY(10); 36467468Snon} 36567468Snon 36667468Snonstatic void 36767468Snonncvhw_bus_reset(sc) 36867468Snon struct ncv_softc *sc; 36967468Snon{ 37067468Snon bus_space_tag_t iot = sc->sc_iot; 37167468Snon bus_space_handle_t ioh = sc->sc_ioh; 37267468Snon 37367468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 37467468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 37567468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_RSTSCSI); 37667468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_NOP | CMD_DMA); 37767468Snon} 37867468Snon 37967468Snonstatic int 38067468Snonncvhw_start_selection(sc, cb) 38167468Snon struct ncv_softc *sc; 38267468Snon struct slccb *cb; 38367468Snon{ 38467468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 38567468Snon bus_space_tag_t iot = sc->sc_iot; 38667468Snon bus_space_handle_t ioh = sc->sc_ioh; 38767468Snon struct targ_info *ti = cb->ti; 38879697Snon int s, len; 38979697Snon u_int flags; 39079697Snon u_int8_t cmd; 39167468Snon 39279697Snon sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 39367468Snon sc->sc_compseq = 0; 39479697Snon if (scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0) 39579697Snon { 39679697Snon cmd = CMD_SELATN; 39779697Snon sc->sc_selstop = 0; 39879697Snon flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT; 39979697Snon } 40079697Snon else if (scsi_low_is_msgout_continue(ti, 40179697Snon SCSI_LOW_MSG_IDENTIFY | SCSI_LOW_MSG_SIMPLE_QTAG) == 0) 40279697Snon { 40379697Snon cmd = CMD_SELATN3; 40479697Snon sc->sc_selstop = 0; 40579697Snon flags = SCSI_LOW_MSGOUT_UNIFY | SCSI_LOW_MSGOUT_INIT; 40679697Snon } 40779697Snon else 40879697Snon { 40979697Snon cmd = CMD_SELATNS; 41079697Snon sc->sc_selstop = 1; 41179697Snon flags = SCSI_LOW_MSGOUT_INIT; 41279697Snon } 41379697Snon 41467468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 41579697Snon if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0) 41679697Snon return SCSI_LOW_START_FAIL; 41767468Snon 41879697Snon ncv_target_nexus_establish(sc); 41979697Snon 42079697Snon len = scsi_low_msgout(slp, ti, flags); 42179697Snon if (sc->sc_selstop == 0) 42279697Snon scsi_low_cmd(slp, ti); 42379697Snon 42467468Snon s = splhigh(); 42579697Snon if ((bus_space_read_1(iot, ioh, cr0_stat) & STAT_INT) != 0) 42667468Snon { 42767468Snon splx(s); 42867468Snon return SCSI_LOW_START_FAIL; 42967468Snon } 43067468Snon 43167468Snon bus_space_write_1(iot, ioh, cr0_dstid, ti->ti_id); 43267468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 43379697Snon ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); 43479697Snon if (sc->sc_selstop == 0) 43567468Snon { 43667468Snon ncvhw_fpush(iot, ioh, 43767468Snon slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 43867468Snon } 43979697Snon bus_space_write_1(iot, ioh, cr0_cmd, cmd); 44067468Snon splx(s); 44167468Snon 44267468Snon SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); 44367468Snon return SCSI_LOW_START_OK; 44467468Snon} 44567468Snon 44667468Snonstatic int 44767468Snonncv_world_start(sc, fdone) 44867468Snon struct ncv_softc *sc; 44967468Snon int fdone; 45067468Snon{ 45167468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 45267468Snon bus_space_tag_t iot = sc->sc_iot; 45367468Snon bus_space_handle_t ioh = sc->sc_ioh; 45467468Snon u_int8_t stat; 45567468Snon 45679697Snon if ((slp->sl_cfgflags & CFG_NOPARITY) == 0) 45779697Snon sc->sc_hw.hw_cfg1 |= C1_PARENB; 45879697Snon else 45979697Snon sc->sc_hw.hw_cfg1 &= ~C1_PARENB; 46079697Snon 46167468Snon ncvhw_reset(iot, ioh, &sc->sc_hw); 46267468Snon ncvhw_init(iot, ioh, &sc->sc_hw); 46367468Snon 46471466Sjhb scsi_low_bus_reset(slp); 46567468Snon 46667468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 46767468Snon bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_stat); 46867468Snon stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat); 469240172Sjhb DELAY(1000); 47067468Snon 47167468Snon if (((stat & INTR_SBR) == 0) || 47267468Snon (bus_space_read_1(sc->sc_iot, sc->sc_ioh, cr0_istat) & INTR_SBR)) 47367468Snon return ENODEV; 47467468Snon 47567468Snon return 0; 47667468Snon} 47767468Snon 47867468Snonstatic int 47967468Snonncv_msg(sc, ti, msg) 48067468Snon struct ncv_softc *sc; 48167468Snon struct targ_info *ti; 48267468Snon u_int msg; 48367468Snon{ 48479697Snon bus_space_tag_t iot = sc->sc_iot; 48579697Snon bus_space_handle_t ioh = sc->sc_ioh; 48673025Snon struct ncv_targ_info *nti = (void *) ti; 48767468Snon u_int hwcycle, period; 48867468Snon 48979697Snon if ((msg & SCSI_LOW_MSG_WIDE) != 0) 49079697Snon { 49179697Snon if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) 49279697Snon { 49379697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 49479697Snon return EINVAL; 49579697Snon } 49679697Snon return 0; 49779697Snon } 49879697Snon 49967468Snon if ((msg & SCSI_LOW_MSG_SYNCH) == 0) 50067468Snon return 0; 50167468Snon 50273025Snon period = ti->ti_maxsynch.period; 50379697Snon hwcycle = (sc->sc_hw.hw_clk == 0) ? 40 : (5 * sc->sc_hw.hw_clk); 50479697Snon hwcycle = 1000 / hwcycle; 50567468Snon 50667468Snon if (period < 200 / 4 && period >= 100 / 4) 50779697Snon nti->nti_reg_cfg3 |= sc->sc_hw.hw_cfg3_fscsi; 50867468Snon else 50979697Snon nti->nti_reg_cfg3 &= ~sc->sc_hw.hw_cfg3_fscsi; 51067468Snon 51167468Snon period = ((period * 40 / hwcycle) + 5) / 10; 51273025Snon nti->nti_reg_period = period & 0x1f; 51373025Snon nti->nti_reg_offset = ti->ti_maxsynch.offset; 51479697Snon 51579697Snon bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period); 51679697Snon bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset); 51779697Snon bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3); 51867468Snon return 0; 51967468Snon} 52067468Snon 52167468Snonstatic int 52279697Snonncv_targ_init(sc, ti, action) 52367468Snon struct ncv_softc *sc; 52467468Snon struct targ_info *ti; 52579697Snon int action; 52667468Snon{ 52773025Snon struct ncv_targ_info *nti = (void *) ti; 52867468Snon 52979697Snon if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) 53079697Snon { 53179697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 53279697Snon ti->ti_maxsynch.period = sc->sc_hw.hw_mperiod; 53379697Snon ti->ti_maxsynch.offset = sc->sc_hw.hw_moffset; 53467468Snon 53579697Snon nti->nti_reg_cfg3 = sc->sc_hw.hw_cfg3; 53679697Snon nti->nti_reg_period = 0; 53779697Snon nti->nti_reg_offset = 0; 53879697Snon } 53967468Snon return 0; 54067468Snon} 54167468Snon 54267468Snon/************************************************************** 54367468Snon * General probe attach 54467468Snon **************************************************************/ 54592739Salfredstatic int ncv_setup_img(struct ncv_hw *, u_int, int); 54667468Snon 54767468Snonstatic int 54879697Snonncv_setup_img(hw, dvcfg, hostid) 54967468Snon struct ncv_hw *hw; 55067468Snon u_int dvcfg; 55179697Snon int hostid; 55267468Snon{ 55367468Snon 55467468Snon if (NCV_CLKFACTOR(dvcfg) > CLK_35M_F) 55567468Snon { 55667468Snon printf("ncv: invalid dvcfg flags\n"); 55767468Snon return EINVAL; 55867468Snon } 55967468Snon 56067468Snon if (NCV_C5IMG(dvcfg) != 0) 56167468Snon { 56279697Snon hw->hw_cfg5 = NCV_C5IMG(dvcfg); 56379697Snon hw->hw_clk = NCV_CLKFACTOR(dvcfg); 56467468Snon 56579697Snon if ((ncv_io_control & NCV_ENABLE_FAST_SCSI) != 0 && 56679697Snon (NCV_SPECIAL(dvcfg) & NCVHWCFG_MAX10M) != 0) 56779697Snon hw->hw_mperiod = 100 / 4; 56867468Snon 56967468Snon if (NCV_SPECIAL(dvcfg) & NCVHWCFG_FIFOBUG) 57079697Snon hw->hw_cfg3_fclk = 0x04; 57167468Snon 57267468Snon if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SCSI1) 57379697Snon hw->hw_cfg2 &= ~C2_SCSI2; 57467468Snon 57567468Snon if (NCV_SPECIAL(dvcfg) & NCVHWCFG_SLOW) 57679697Snon hw->hw_cfg1 |= C1_SLOW; 57767468Snon } 57867468Snon 57967468Snon /* setup configuration image 3 */ 58079697Snon if (hw->hw_clk != CLK_40M_F && hw->hw_clk <= CLK_25M_F) 58179697Snon hw->hw_cfg3 &= ~hw->hw_cfg3_fclk; 58279697Snon else 58379697Snon hw->hw_cfg3 |= hw->hw_cfg3_fclk; 58467468Snon 58567468Snon /* setup configuration image 1 */ 58679697Snon hw->hw_cfg1 = (hw->hw_cfg1 & 0xf0) | hostid; 58767468Snon return 0; 58867468Snon} 58967468Snon 59067468Snonint 59167468Snonncvprobesubr(iot, ioh, dvcfg, hsid) 59267468Snon bus_space_tag_t iot; 59367468Snon bus_space_handle_t ioh; 59467468Snon u_int dvcfg; 59567468Snon int hsid; 59667468Snon{ 59767468Snon struct ncv_hw hwtab; 59867468Snon 59967468Snon hwtab = ncv_template; 60067468Snon if (ncv_setup_img(&hwtab, dvcfg, hsid)) 60167468Snon return 0; 60267468Snon if (ncvhw_check(iot, ioh, &hwtab) != 0) 60367468Snon return 0; 60467468Snon 60567468Snon return 1; 60667468Snon} 60767468Snon 60867468Snonvoid 60967468Snonncvattachsubr(sc) 61067468Snon struct ncv_softc *sc; 61167468Snon{ 61267468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 61367468Snon 61467468Snon printf("\n"); 61567468Snon sc->sc_hw = ncv_template; 61667468Snon ncv_setup_img(&sc->sc_hw, slp->sl_cfgflags, slp->sl_hostid); 61767468Snon slp->sl_funcs = &ncv_funcs; 61879697Snon slp->sl_flags |= HW_READ_PADDING; 61979697Snon sc->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ 62079697Snon 62179697Snon (void) scsi_low_attach(slp, 0, NCV_NTARGETS, NCV_NLUNS, 62279697Snon sizeof(struct ncv_targ_info), 0); 62367468Snon} 62467468Snon 62567468Snon/************************************************************** 62667468Snon * PDMA 62767468Snon **************************************************************/ 62867468Snonstatic __inline void 62979697Snonncv_setup_and_start_pio(sc, reqlen) 63079697Snon struct ncv_softc *sc; 63179697Snon u_int reqlen; 63267468Snon{ 63379697Snon bus_space_tag_t iot = sc->sc_iot; 63479697Snon bus_space_handle_t ioh = sc->sc_ioh; 63567468Snon 63679697Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 63779697Snon ncvhw_set_count(iot, ioh, reqlen); 63879697Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS | CMD_DMA); 63967468Snon 64079697Snon ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 64179697Snon bus_space_write_1(iot, ioh, cr1_fstat, FIFO_EN); 64267468Snon} 64367468Snon 64479697Snonstatic void 64567468Snonncv_pdma_end(sc, ti) 64667468Snon struct ncv_softc *sc; 64767468Snon struct targ_info *ti; 64867468Snon{ 64967468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 65067468Snon bus_space_tag_t iot = sc->sc_iot; 65167468Snon bus_space_handle_t ioh = sc->sc_ioh; 65267468Snon int len; 65367468Snon 65467468Snon slp->sl_flags &= ~HW_PDMASTART; 65579697Snon if (slp->sl_Qnexus == NULL) 65679697Snon { 65779697Snon slp->sl_error |= PDMAERR; 65879697Snon goto out; 65979697Snon } 66079697Snon 66167468Snon if (ti->ti_phase == PH_DATA) 66267468Snon { 66367468Snon len = ncvhw_get_count(sc->sc_iot, sc->sc_ioh); 66467468Snon if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 66567468Snon len += (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 66667468Snon cr0_sffl) & CR0_SFFLR_BMASK); 66767468Snon 66879697Snon if ((u_int) len <= (u_int) sc->sc_sdatalen) 66967468Snon { 67067468Snon if ((slp->sl_scp.scp_direction == SCSI_LOW_READ) && 67167468Snon sc->sc_tdatalen != len) 67267468Snon goto bad; 67379697Snon 67479697Snon len = sc->sc_sdatalen - len; 67579697Snon if ((u_int) len > (u_int) slp->sl_scp.scp_datalen) 67679697Snon goto bad; 67779697Snon 67879697Snon slp->sl_scp.scp_data += len; 67979697Snon slp->sl_scp.scp_datalen -= len; 68067468Snon } 68167468Snon else 68267468Snon { 68367468Snonbad: 68479697Snon if ((slp->sl_error & PDMAERR) == 0) 68579697Snon { 686240325Sjhb device_printf(slp->sl_dev, 687240325Sjhb "strange cnt hw 0x%x soft 0x%x\n", len, 688240325Sjhb slp->sl_scp.scp_datalen); 68979697Snon } 69067468Snon slp->sl_error |= PDMAERR; 69167468Snon } 69279697Snon scsi_low_data_finish(slp); 69367468Snon } 69467468Snon else 69567468Snon { 696240325Sjhb device_printf(slp->sl_dev, "data phase miss\n"); 69767468Snon slp->sl_error |= PDMAERR; 69867468Snon } 69967468Snon 70079697Snonout: 70167468Snon ncvhw_select_register_1(iot, ioh, &sc->sc_hw); 70267468Snon bus_space_write_1(iot, ioh, cr1_fstat, 0); 70367468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 70467468Snon} 70567468Snon 70667468Snonstatic void 70767468Snonncv_pio_read(sc, buf, reqlen) 70867468Snon struct ncv_softc *sc; 70967468Snon u_int8_t *buf; 71067468Snon u_int reqlen; 71167468Snon{ 71267468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 71367468Snon bus_space_tag_t iot = sc->sc_iot; 71467468Snon bus_space_handle_t ioh = sc->sc_ioh; 71579697Snon int tout; 71667468Snon register u_int8_t fstat; 71767468Snon 71879697Snon ncv_setup_and_start_pio(sc, reqlen); 71967468Snon slp->sl_flags |= HW_PDMASTART; 72079697Snon sc->sc_sdatalen = reqlen; 72179697Snon tout = sc->sc_tmaxcnt; 72267468Snon 72379697Snon while (reqlen >= FIFO_F_SZ && tout -- > 0) 72467468Snon { 72567468Snon fstat = bus_space_read_1(iot, ioh, cr1_fstat); 72679697Snon if (fstat == (u_int8_t) -1) 72779697Snon goto out; 72867468Snon if (fstat & FIFO_F) 72967468Snon { 73067468Snon#define NCV_FAST32_ACCESS 73167468Snon#ifdef NCV_FAST32_ACCESS 73267468Snon bus_space_read_multi_4(iot, ioh, cr1_fdata, 73367468Snon (u_int32_t *) buf, FIFO_F_SZ / 4); 73467468Snon#else /* !NCV_FAST32_ACCESS */ 73567468Snon bus_space_read_multi_2(iot, ioh, cr1_fdata, 73667468Snon (u_int16_t *) buf, FIFO_F_SZ / 2); 73767468Snon#endif /* !NCV_FAST32_ACCESS */ 73867468Snon buf += FIFO_F_SZ; 73967468Snon reqlen -= FIFO_F_SZ; 74067468Snon } 74179697Snon else 74279697Snon { 74379697Snon if (fstat & FIFO_BRK) 74479697Snon break; 74567468Snon 746240172Sjhb DELAY(1); 74767468Snon } 74867468Snon } 74967468Snon 75079697Snon while (reqlen > 0 && tout -- > 0) 75167468Snon { 75267468Snon fstat = bus_space_read_1(iot, ioh, cr1_fstat); 75367468Snon if ((fstat & FIFO_E) == 0) 75467468Snon { 75567468Snon *buf++ = bus_space_read_1(iot, ioh, cr1_fdata); 75667468Snon reqlen --; 75767468Snon } 75879697Snon else 75979697Snon { 76079697Snon if (fstat & FIFO_BRK) 76179697Snon break; 76267468Snon 763240172Sjhb DELAY(1); 76479697Snon } 76567468Snon } 76667468Snon 76779697Snonout: 76867468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 76967468Snon sc->sc_tdatalen = reqlen; 77067468Snon} 77167468Snon 77267468Snonstatic void 77367468Snonncv_pio_write(sc, buf, reqlen) 77467468Snon struct ncv_softc *sc; 77567468Snon u_int8_t *buf; 77667468Snon u_int reqlen; 77767468Snon{ 77867468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 77967468Snon bus_space_tag_t iot = sc->sc_iot; 78067468Snon bus_space_handle_t ioh = sc->sc_ioh; 78179697Snon int tout; 78267468Snon register u_int8_t fstat; 78367468Snon 78479697Snon ncv_setup_and_start_pio(sc, reqlen); 78579697Snon sc->sc_sdatalen = reqlen; 78679697Snon tout = sc->sc_tmaxcnt; 78767468Snon slp->sl_flags |= HW_PDMASTART; 78867468Snon 78979697Snon while (reqlen >= FIFO_F_SZ && tout -- > 0) 79067468Snon { 79167468Snon fstat = bus_space_read_1(iot, ioh, cr1_fstat); 79267468Snon if (fstat & FIFO_BRK) 79367468Snon goto done; 79467468Snon 79579697Snon if ((fstat & FIFO_E) != 0) 79667468Snon { 79767468Snon#ifdef NCV_FAST32_ACCESS 79867468Snon bus_space_write_multi_4(iot, ioh, cr1_fdata, 79967468Snon (u_int32_t *) buf, FIFO_F_SZ / 4); 80067468Snon#else /* !NCV_FAST32_ACCESS */ 80167468Snon bus_space_write_multi_2(iot, ioh, cr1_fdata, 80267468Snon (u_int16_t *) buf, FIFO_F_SZ / 2); 80367468Snon#endif /* !NCV_FAST32_ACCESS */ 80467468Snon buf += FIFO_F_SZ; 80567468Snon reqlen -= FIFO_F_SZ; 80667468Snon } 80773025Snon else 80879697Snon { 809240172Sjhb DELAY(1); 81079697Snon } 81167468Snon } 81267468Snon 81379697Snon while (reqlen > 0 && tout -- > 0) 81467468Snon { 81567468Snon fstat = bus_space_read_1(iot, ioh, cr1_fstat); 81667468Snon if (fstat & FIFO_BRK) 81767468Snon break; 81867468Snon 81967468Snon if ((fstat & FIFO_F) == 0) /* fifo not full */ 82067468Snon { 82167468Snon bus_space_write_1(iot, ioh, cr1_fdata, *buf++); 82267468Snon reqlen --; 82367468Snon } 82473025Snon else 82579697Snon { 826240172Sjhb DELAY(1); 82779697Snon } 82867468Snon } 82967468Snon 83067468Snondone: 83167468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 83267468Snon} 83367468Snon 83467468Snon/************************************************************** 83567468Snon * disconnect & reselect (HW low) 83667468Snon **************************************************************/ 83779697Snonstatic int 83867468Snonncv_reselected(sc) 83967468Snon struct ncv_softc *sc; 84067468Snon{ 84167468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 84267468Snon bus_space_tag_t iot = sc->sc_iot; 84367468Snon bus_space_handle_t ioh = sc->sc_ioh; 84467468Snon struct targ_info *ti; 84567468Snon u_int sid; 84667468Snon 84767468Snon if ((bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK) != 2) 84867468Snon { 849240325Sjhb device_printf(slp->sl_dev, "illegal fifo bytes\n"); 85067468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "chip confused"); 85167468Snon return EJUSTRETURN; 85267468Snon } 85367468Snon 85467468Snon sid = (u_int) bus_space_read_1(iot, ioh, cr0_sfifo); 85579697Snon sid &= ~(1 << slp->sl_hostid); 85667468Snon sid = ffs(sid) - 1; 85767468Snon ti = scsi_low_reselected((struct scsi_low_softc *) sc, sid); 85867468Snon if (ti == NULL) 85967468Snon return EJUSTRETURN; 86067468Snon 86167468Snon#ifdef NCV_STATICS 86279697Snon ncv_statics.reselect ++; 86367468Snon#endif /* NCV_STATICS */ 86467468Snon bus_space_write_1(iot, ioh, cr0_dstid, sid); 86567468Snon return 0; 86667468Snon} 86767468Snon 86879697Snonstatic int 86967468Snonncv_disconnected(sc, ti) 87067468Snon struct ncv_softc *sc; 87167468Snon struct targ_info *ti; 87267468Snon{ 87367468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 87467468Snon bus_space_tag_t iot = sc->sc_iot; 87567468Snon bus_space_handle_t ioh = sc->sc_ioh; 87667468Snon 87767468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 87867468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_ENSEL); 87967468Snon 88067468Snon#ifdef NCV_STATICS 88179697Snon ncv_statics.disconnect ++; 88267468Snon#endif /* NCV_STATICS */ 88367468Snon 88467468Snon scsi_low_disconnected(slp, ti); 88567468Snon return 1; 88667468Snon} 88767468Snon 88867468Snon/************************************************************** 88967468Snon * SEQUENCER 89067468Snon **************************************************************/ 89167468Snonstatic int 89279697Snonncv_target_nexus_establish(sc) 89367468Snon struct ncv_softc *sc; 89467468Snon{ 89579697Snon struct scsi_low_softc *slp = &sc->sc_sclow; 89679697Snon struct targ_info *ti = slp->sl_Tnexus; 89779697Snon struct ncv_targ_info *nti = (void *) ti; 89867468Snon bus_space_tag_t iot = sc->sc_iot; 89967468Snon bus_space_handle_t ioh = sc->sc_ioh; 90067468Snon 90173025Snon bus_space_write_1(iot, ioh, cr0_period, nti->nti_reg_period); 90273025Snon bus_space_write_1(iot, ioh, cr0_offs, nti->nti_reg_offset); 90373025Snon bus_space_write_1(iot, ioh, cr0_cfg3, nti->nti_reg_cfg3); 90467468Snon return 0; 90567468Snon} 90667468Snon 90779697Snonstatic int 90879697Snonncv_lun_nexus_establish(sc) 90979697Snon struct ncv_softc *sc; 91079697Snon{ 91179697Snon 91279697Snon return 0; 91379697Snon} 91479697Snon 91579697Snonstatic int 91679697Snonncv_ccb_nexus_establish(sc) 91779697Snon struct ncv_softc *sc; 91879697Snon{ 91979697Snon struct scsi_low_softc *slp = &sc->sc_sclow; 92079697Snon struct slccb *cb = slp->sl_Qnexus; 92179697Snon 92279697Snon sc->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 92379697Snon return 0; 92479697Snon} 92579697Snon 92679697Snonstatic int 92779697Snonncv_catch_intr(sc) 92879697Snon struct ncv_softc *sc; 92979697Snon{ 93079697Snon bus_space_tag_t iot = sc->sc_iot; 93179697Snon bus_space_handle_t ioh = sc->sc_ioh; 93279697Snon int wc; 93379697Snon register u_int8_t status; 93479697Snon 93579697Snon for (wc = 0; wc < NCV_DELAY_MAX / NCV_DELAY_INTERVAL; wc ++) 93679697Snon { 93779697Snon status = bus_space_read_1(iot, ioh, cr0_stat); 93879697Snon if ((status & STAT_INT) != 0) 93979697Snon return 0; 94079697Snon 941240172Sjhb DELAY(NCV_DELAY_INTERVAL); 94279697Snon } 94379697Snon return EJUSTRETURN; 94479697Snon} 94579697Snon 94667468Snonint 94767468Snonncvintr(arg) 94867468Snon void *arg; 94967468Snon{ 95067468Snon struct ncv_softc *sc = arg; 95167468Snon struct scsi_low_softc *slp = &sc->sc_sclow; 95267468Snon bus_space_tag_t iot = sc->sc_iot; 95367468Snon bus_space_handle_t ioh = sc->sc_ioh; 95467468Snon struct targ_info *ti; 95567468Snon struct buf *bp; 95679697Snon u_int derror, flags; 95779697Snon int len; 95867468Snon u_int8_t regv, status, ireason; 95967468Snon 96079697Snonagain: 96167468Snon if (slp->sl_flags & HW_INACTIVE) 96267468Snon return 0; 96367468Snon 96467468Snon /******************************************** 96567468Snon * Status 96667468Snon ********************************************/ 96767468Snon ncvhw_select_register_0(iot, ioh, &sc->sc_hw); 96867468Snon status = bus_space_read_1(iot, ioh, cr0_stat); 96979697Snon if ((status & STAT_INT) == 0 || status == (u_int8_t) -1) 97067468Snon return 0; 97167468Snon 97267468Snon ireason = bus_space_read_1(iot, ioh, cr0_istat); 97379697Snon if ((ireason & INTR_SBR) != 0) 97467468Snon { 97567468Snon u_int8_t val; 97667468Snon 97767468Snon /* avoid power off hangup */ 97867468Snon val = bus_space_read_1(iot, ioh, cr0_cfg1); 97967468Snon bus_space_write_1(iot, ioh, cr0_cfg1, val | C1_SRR); 98067468Snon 98167468Snon /* status init */ 98267468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_SOFT, 98367468Snon "bus reset (power off?)"); 98467468Snon return 1; 98567468Snon } 98667468Snon 98767468Snon /******************************************** 98867468Snon * Debug section 98967468Snon ********************************************/ 99067468Snon#ifdef NCV_DEBUG 99167468Snon if (ncv_debug) 99267468Snon { 99367468Snon scsi_low_print(slp, NULL); 994240325Sjhb device_printf(slp->sl_dev, "st %x ist %x\n\n", 99567468Snon status, ireason); 996131914Smarcel#ifdef KDB 99767468Snon if (ncv_debug > 1) 998240172Sjhb kdb_enter(KDB_WHY_CAM, "ncv"); 999131914Smarcel#endif /* KDB */ 100067468Snon } 100167468Snon#endif /* NCV_DEBUG */ 100267468Snon 100367468Snon /******************************************** 100467468Snon * Reselect or Disconnect or Nexus check 100567468Snon ********************************************/ 100667468Snon /* (I) reselect */ 100767468Snon if (ireason == INTR_RESELECT) 100867468Snon { 100967468Snon if (ncv_reselected(sc) == EJUSTRETURN) 101067468Snon return 1; 101167468Snon } 101267468Snon 101367468Snon /* (II) nexus */ 101479697Snon if ((ti = slp->sl_Tnexus) == NULL) 101567468Snon return 0; 101667468Snon 101779697Snon derror = 0; 101867468Snon if ((status & (STAT_PE | STAT_GE)) != 0) 101967468Snon { 102067468Snon slp->sl_error |= PARITYERR; 102179697Snon if ((status & PHASE_MASK) == MESSAGE_IN_PHASE) 102279697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_PARITY, 0); 102367468Snon else 102467468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ERROR, 1); 102579697Snon derror = SCSI_LOW_DATA_PE; 102667468Snon } 102767468Snon 102867468Snon if ((ireason & (INTR_DIS | INTR_ILL)) != 0) 102967468Snon { 103067468Snon if ((ireason & INTR_ILL) == 0) 103167468Snon return ncv_disconnected(sc, ti); 103267468Snon 103367468Snon slp->sl_error |= FATALIO; 103467468Snon scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "illegal cmd"); 103567468Snon return 1; 103667468Snon } 103767468Snon 103867468Snon /******************************************** 103967468Snon * Internal scsi phase 104067468Snon ********************************************/ 104167468Snon switch (ti->ti_phase) 104267468Snon { 104367468Snon case PH_SELSTART: 104479697Snon scsi_low_arbit_win(slp); 104567468Snon SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); 104667468Snon 104767468Snon if (sc->sc_selstop == 0) 104867468Snon { 104967468Snon /* XXX: 105067468Snon * Here scsi phases expected are 105167468Snon * DATA PHASE: 105267468Snon * MSGIN : target wants to disconnect the host. 105367468Snon * STATUSIN : immediate command completed. 105479697Snon * CMD PHASE : command out failed 105567468Snon * MSGOUT : identify command failed. 105667468Snon */ 105767468Snon if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) 105867468Snon break; 105967468Snon } 106067468Snon else 106167468Snon { 106267468Snon if ((status & PHASE_MASK) != MESSAGE_OUT_PHASE) 106379697Snon break; 106479697Snon if ((ireason & INTR_FC) != 0) 106567468Snon { 106679697Snon SCSI_LOW_ASSERT_ATN(slp); 106767468Snon } 106867468Snon } 106979697Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); 107067468Snon break; 107167468Snon 107267468Snon case PH_RESEL: 107379697Snon ncv_target_nexus_establish(sc); 107467468Snon if ((status & PHASE_MASK) != MESSAGE_IN_PHASE) 107567468Snon { 1076240325Sjhb device_printf(slp->sl_dev, 1077240325Sjhb "unexpected phase after reselect\n"); 107879697Snon slp->sl_error |= FATALIO; 107967468Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); 108067468Snon return 1; 108167468Snon } 108267468Snon break; 108367468Snon 108467468Snon default: 108579697Snon if ((slp->sl_flags & HW_PDMASTART) != 0) 108679697Snon { 108767468Snon ncv_pdma_end(sc, ti); 108879697Snon } 108967468Snon break; 109067468Snon } 109167468Snon 109267468Snon /******************************************** 109367468Snon * Scsi phase sequencer 109467468Snon ********************************************/ 109567468Snon switch (status & PHASE_MASK) 109667468Snon { 109767468Snon case DATA_OUT_PHASE: /* data out */ 109867468Snon SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 109967468Snon if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) 110079697Snon { 110179697Snon scsi_low_attention(slp); 110279697Snon } 110367468Snon 110479697Snon if (slp->sl_scp.scp_datalen <= 0) 110579697Snon { 110679697Snon if ((ireason & INTR_BS) == 0) 110779697Snon break; 110879697Snon 110979697Snon if ((slp->sl_error & PDMAERR) == 0) 1110240325Sjhb device_printf(slp->sl_dev, "data underrun\n"); 111179697Snon slp->sl_error |= PDMAERR; 111279697Snon 111379697Snon if ((slp->sl_flags & HW_WRITE_PADDING) != 0) 111479697Snon { 111579697Snon u_int8_t padding[NCV_PADDING_SIZE]; 111679697Snon 1117240172Sjhb bzero(padding, sizeof(padding)); 111879697Snon ncv_pio_write(sc, padding, sizeof(padding)); 111979697Snon } 112079697Snon else 112179697Snon { 1122240325Sjhb device_printf(slp->sl_dev, 1123240325Sjhb "write padding required\n"); 112479697Snon } 112579697Snon } 112679697Snon else 112779697Snon { 112879697Snon len = slp->sl_scp.scp_datalen; 112979697Snon if ((ncv_io_control & NCV_WRITE_INTERRUPTS_DRIVEN) != 0) 113079697Snon { 113179697Snon if (len > ncv_data_write_bytes) 113279697Snon len = ncv_data_write_bytes; 113379697Snon } 113479697Snon ncv_pio_write(sc, slp->sl_scp.scp_data, len); 113579697Snon } 113667468Snon break; 113767468Snon 113867468Snon case DATA_IN_PHASE: /* data in */ 113967468Snon SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 114067468Snon if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) 114179697Snon { 114279697Snon scsi_low_attention(slp); 114379697Snon } 114467468Snon 114579697Snon if (slp->sl_scp.scp_datalen <= 0) 114679697Snon { 114779697Snon if ((ireason & INTR_BS) == 0) 114879697Snon break; 114979697Snon 115079697Snon if ((slp->sl_error & PDMAERR) == 0) 1151240325Sjhb device_printf(slp->sl_dev, "data overrun\n"); 115279697Snon slp->sl_error |= PDMAERR; 115379697Snon 115479697Snon if ((slp->sl_flags & HW_READ_PADDING) != 0) 115579697Snon { 115679697Snon u_int8_t padding[NCV_PADDING_SIZE]; 115779697Snon 115879697Snon ncv_pio_read(sc, padding, sizeof(padding)); 115979697Snon } 116079697Snon else 116179697Snon { 1162240325Sjhb device_printf(slp->sl_dev, 1163240325Sjhb "read padding required\n"); 116479697Snon break; 116579697Snon } 116679697Snon } 116779697Snon else 116879697Snon { 116979697Snon len = slp->sl_scp.scp_datalen; 117079697Snon if ((ncv_io_control & NCV_READ_INTERRUPTS_DRIVEN) != 0) 117179697Snon { 117279697Snon if (len > ncv_data_read_bytes) 117379697Snon len = ncv_data_read_bytes; 117479697Snon } 117579697Snon ncv_pio_read(sc, slp->sl_scp.scp_data, len); 117679697Snon } 117767468Snon break; 117867468Snon 117967468Snon case COMMAND_PHASE: /* cmd out */ 118067468Snon SCSI_LOW_SETUP_PHASE(ti, PH_CMD); 118167468Snon if (scsi_low_cmd(slp, ti) != 0) 118279697Snon { 118379697Snon scsi_low_attention(slp); 118479697Snon } 118567468Snon 118667468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 118767468Snon ncvhw_fpush(iot, ioh, 118867468Snon slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 118967468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 119067468Snon break; 119167468Snon 119267468Snon case STATUS_PHASE: /* status in */ 119367468Snon SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 119467468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 119567468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_ICCS); 119667468Snon sc->sc_compseq = 1; 119767468Snon break; 119867468Snon 119967468Snon default: 120067468Snon break; 120167468Snon 120267468Snon case MESSAGE_OUT_PHASE: /* msg out */ 120367468Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); 120467468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 120567468Snon 120679697Snon flags = SCSI_LOW_MSGOUT_UNIFY; 120779697Snon if (ti->ti_ophase != ti->ti_phase) 120879697Snon flags |= SCSI_LOW_MSGOUT_INIT; 120979697Snon len = scsi_low_msgout(slp, ti, flags); 121079697Snon 121179697Snon if (len > 1 && slp->sl_atten == 0) 121279697Snon { 121379697Snon scsi_low_attention(slp); 121479697Snon } 121579697Snon 121667468Snon ncvhw_fpush(iot, ioh, ti->ti_msgoutstr, len); 121767468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 121879697Snon SCSI_LOW_DEASSERT_ATN(slp); 121967468Snon break; 122067468Snon 122167468Snon case MESSAGE_IN_PHASE: /* msg in */ 122267468Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 122367468Snon 122467468Snon len = bus_space_read_1(iot, ioh, cr0_sffl) & CR0_SFFLR_BMASK; 122567468Snon if (sc->sc_compseq != 0) 122667468Snon { 122767468Snon sc->sc_compseq = 0; 122867468Snon if ((ireason & INTR_FC) && len == 2) 122967468Snon { 123079697Snon regv = bus_space_read_1(iot, ioh, cr0_sfifo); 123179697Snon scsi_low_statusin(slp, ti, regv | derror); 123267468Snon len --; 123367468Snon } 123467468Snon else 123567468Snon { 123679697Snon slp->sl_error |= FATALIO; 123779697Snon scsi_low_assert_msg(slp, ti, 123879697Snon SCSI_LOW_MSG_ABORT, 1); 123979697Snon bus_space_write_1(sc->sc_iot, sc->sc_ioh, 124079697Snon cr0_cmd, CMD_MSGOK); 124167468Snon break; 124267468Snon } 124367468Snon } 124467468Snon else if (ireason & INTR_BS) 124567468Snon { 124667468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_FLUSH); 124767468Snon bus_space_write_1(iot, ioh, cr0_cmd, CMD_TRANS); 124879697Snon if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0) 124979697Snon { 125079697Snon if (ncv_catch_intr(sc) == 0) 125179697Snon goto again; 125279697Snon } 125367468Snon break; 125467468Snon } 125567468Snon 125667468Snon if ((ireason & INTR_FC) && len == 1) 125767468Snon { 125867468Snon regv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 125967468Snon cr0_sfifo); 126079697Snon if (scsi_low_msgin(slp, ti, regv | derror) == 0) 126179697Snon { 126279697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0) 126379697Snon { 126479697Snon scsi_low_attention(slp); 126579697Snon } 126679697Snon } 126767468Snon bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, 126867468Snon CMD_MSGOK); 126979697Snon if ((ncv_io_control & NCV_FAST_INTERRUPTS) != 0) 127079697Snon { 127179697Snon /* XXX: 127279697Snon * clear a pending interrupt and sync with 127379697Snon * a next interrupt! 127479697Snon */ 127579697Snon ncv_catch_intr(sc); 127679697Snon } 127767468Snon } 127867468Snon else 127967468Snon { 128079697Snon slp->sl_error |= FATALIO; 128179697Snon scsi_low_assert_msg(slp, ti, SCSI_LOW_MSG_ABORT, 1); 128279697Snon bus_space_write_1(sc->sc_iot, sc->sc_ioh, cr0_cmd, 128379697Snon CMD_MSGOK); 128467468Snon } 128567468Snon break; 128667468Snon } 128767468Snon 128867468Snon return 1; 128967468Snon} 1290