179697Snon/* $NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $ */ 2119418Sobrien 3119418Sobrien#include <sys/cdefs.h> 4119418Sobrien__FBSDID("$FreeBSD$"); 573149Snyan/* $NetBSD$ */ 673149Snyan 773149Snyan#define CT_DEBUG 879697Snon#define CT_IO_CONTROL_FLAGS (CT_USE_CCSEQ | CT_FAST_INTR) 973149Snyan 10139749Simp/*- 1173149Snyan * [NetBSD for NEC PC-98 series] 1279697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1373149Snyan * NetBSD/pc98 porting staff. All rights reserved. 1473149Snyan * 1579697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1673149Snyan * Naofumi HONDA. All rights reserved. 1773149Snyan * 1873149Snyan * Redistribution and use in source and binary forms, with or without 1973149Snyan * modification, are permitted provided that the following conditions 2073149Snyan * are met: 2173149Snyan * 1. Redistributions of source code must retain the above copyright 2273149Snyan * notice, this list of conditions and the following disclaimer. 2373149Snyan * 2. Redistributions in binary form must reproduce the above copyright 2473149Snyan * notice, this list of conditions and the following disclaimer in the 2573149Snyan * documentation and/or other materials provided with the distribution. 2673149Snyan * 3. The name of the author may not be used to endorse or promote products 2773149Snyan * derived from this software without specific prior written permission. 2873149Snyan * 2973149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 3073149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 3173149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 3273149Snyan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 3373149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3473149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3573149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3673149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3773149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3873149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3973149Snyan * POSSIBILITY OF SUCH DAMAGE. 4073149Snyan */ 4173149Snyan 4273149Snyan#include <sys/param.h> 4373149Snyan#include <sys/systm.h> 4473149Snyan#include <sys/kernel.h> 4579697Snon#if defined(__FreeBSD__) && __FreeBSD_version > 500001 4673149Snyan#include <sys/bio.h> 4779697Snon#endif /* __ FreeBSD__ */ 4873149Snyan#include <sys/buf.h> 4973149Snyan#include <sys/queue.h> 5073149Snyan#include <sys/malloc.h> 5173149Snyan#include <sys/errno.h> 5273149Snyan 5379697Snon#ifdef __NetBSD__ 5479697Snon#include <sys/device.h> 5573149Snyan 5673149Snyan#include <machine/bus.h> 5773149Snyan#include <machine/intr.h> 5873149Snyan 5973149Snyan#include <dev/scsipi/scsi_all.h> 6073149Snyan#include <dev/scsipi/scsipi_all.h> 6173149Snyan#include <dev/scsipi/scsiconf.h> 6273149Snyan#include <dev/scsipi/scsi_disk.h> 6373149Snyan 6473149Snyan#include <machine/dvcfg.h> 6573149Snyan#include <machine/physio_proc.h> 6673149Snyan 6773149Snyan#include <i386/Cbus/dev/scsi_low.h> 6873149Snyan 6973149Snyan#include <dev/ic/wd33c93reg.h> 7073149Snyan#include <i386/Cbus/dev/ct/ctvar.h> 7179697Snon#include <i386/Cbus/dev/ct/ct_machdep.h> 7273149Snyan#endif /* __NetBSD__ */ 7373149Snyan 7473149Snyan#ifdef __FreeBSD__ 7573149Snyan#include <machine/bus.h> 7673149Snyan 77126928Speter#include <compat/netbsd/dvcfg.h> 78126928Speter#include <compat/netbsd/physio_proc.h> 7973149Snyan 8073149Snyan#include <cam/scsi/scsi_low.h> 8173149Snyan 8278209Snyan#include <dev/ic/wd33c93reg.h> 8373149Snyan#include <dev/ct/ctvar.h> 8479697Snon#include <dev/ct/ct_machdep.h> 8573149Snyan#endif /* __FreeBSD__ */ 8673149Snyan 8779697Snon#define CT_NTARGETS 8 8879697Snon#define CT_NLUNS 8 8979697Snon#define CT_RESET_DEFAULT 2000 9079697Snon#define CT_DELAY_MAX (2 * 1000 * 1000) 9179697Snon#define CT_DELAY_INTERVAL (1) 9279697Snon 9373149Snyan/*************************************************** 9473149Snyan * DEBUG 9573149Snyan ***************************************************/ 9673149Snyan#ifdef CT_DEBUG 9773149Snyanint ct_debug; 9873149Snyan#endif /* CT_DEBUG */ 9973149Snyan 10073149Snyan/*************************************************** 10179697Snon * IO control 10279697Snon ***************************************************/ 10379697Snon#define CT_USE_CCSEQ 0x0100 10479697Snon#define CT_FAST_INTR 0x0200 10579697Snon 10679697Snonu_int ct_io_control = CT_IO_CONTROL_FLAGS; 10779697Snon 10879697Snon/*************************************************** 10973149Snyan * default data 11073149Snyan ***************************************************/ 11173149Snyanu_int8_t cthw_cmdlevel[256] = { 11273149Snyan/* 0 1 2 3 4 5 6 7 8 9 A B C E D F */ 11373149Snyan/*0*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , 11473149Snyan/*1*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 11573149Snyan/*2*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 , 11673149Snyan/*3*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 11773149Snyan/*4*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 11873149Snyan/*5*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 11973149Snyan/*6*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12073149Snyan/*7*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12173149Snyan/*8*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12273149Snyan/*9*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12373149Snyan/*A*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12473149Snyan/*B*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12573149Snyan/*C*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12673149Snyan/*D*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12773149Snyan/*E*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12873149Snyan/*F*/0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 , 12973149Snyan}; 13073149Snyan 13179697Snon#if 0 13273149Snyan/* default synch data table */ 13373149Snyan/* A 10 6.6 5.0 4.0 3.3 2.8 2.5 2.0 M/s */ 13473149Snyan/* X 100 150 200 250 300 350 400 500 ns */ 13579697Snonstatic struct ct_synch_data ct_synch_data_FSCSI[] = { 13673149Snyan {25, 0xa0}, {37, 0xb0}, {50, 0x20}, {62, 0xd0}, {75, 0x30}, 13773149Snyan {87, 0xf0}, {100, 0x40}, {125, 0x50}, {0, 0} 13873149Snyan}; 13973149Snyan 14079697Snonstatic struct ct_synch_data ct_synch_data_SCSI[] = { 14179697Snon {50, 0x20}, {75, 0x30}, {100, 0x40}, {125, 0x50}, {0, 0} 14279697Snon}; 14379697Snon#endif 14479697Snon/*************************************************** 14579697Snon * DEVICE STRUCTURE 14679697Snon ***************************************************/ 14779697Snonextern struct cfdriver ct_cd; 14873149Snyan 14973149Snyan/***************************************************************** 15073149Snyan * Interface functions 15173149Snyan *****************************************************************/ 15292739Salfredstatic int ct_xfer(struct ct_softc *, u_int8_t *, int, int, u_int *); 15392739Salfredstatic void ct_io_xfer(struct ct_softc *); 15492739Salfredstatic int ct_reselected(struct ct_softc *, u_int8_t); 15592739Salfredstatic void ct_phase_error(struct ct_softc *, u_int8_t); 15692739Salfredstatic int ct_start_selection(struct ct_softc *, struct slccb *); 15792739Salfredstatic int ct_msg(struct ct_softc *, struct targ_info *, u_int); 15892739Salfredstatic int ct_world_start(struct ct_softc *, int); 15992739Salfredstatic __inline void cthw_phase_bypass(struct ct_softc *, u_int8_t); 16092739Salfredstatic int cthw_chip_reset(struct ct_bus_access_handle *, int *, int, int); 16192739Salfredstatic void cthw_bus_reset(struct ct_softc *); 16292739Salfredstatic int ct_ccb_nexus_establish(struct ct_softc *); 16392739Salfredstatic int ct_lun_nexus_establish(struct ct_softc *); 16492739Salfredstatic int ct_target_nexus_establish(struct ct_softc *, int, int); 16592739Salfredstatic void cthw_attention(struct ct_softc *); 16692739Salfredstatic int ct_targ_init(struct ct_softc *, struct targ_info *, int); 16792739Salfredstatic int ct_unbusy(struct ct_softc *); 16892739Salfredstatic void ct_attention(struct ct_softc *); 16992739Salfredstatic struct ct_synch_data *ct_make_synch_table(struct ct_softc *); 17092739Salfredstatic int ct_catch_intr(struct ct_softc *); 17173149Snyan 17273149Snyanstruct scsi_low_funcs ct_funcs = { 17373149Snyan SC_LOW_INIT_T ct_world_start, 17473149Snyan SC_LOW_BUSRST_T cthw_bus_reset, 17573149Snyan SC_LOW_TARG_INIT_T ct_targ_init, 17679697Snon SC_LOW_LUN_INIT_T NULL, 17773149Snyan 17873149Snyan SC_LOW_SELECT_T ct_start_selection, 17979697Snon SC_LOW_NEXUS_T ct_lun_nexus_establish, 18079697Snon SC_LOW_NEXUS_T ct_ccb_nexus_establish, 18173149Snyan 18273149Snyan SC_LOW_ATTEN_T cthw_attention, 18373149Snyan SC_LOW_MSG_T ct_msg, 18473149Snyan 18579697Snon SC_LOW_TIMEOUT_T NULL, 18673149Snyan SC_LOW_POLL_T ctintr, 18773149Snyan 18873149Snyan NULL, /* SC_LOW_POWER_T cthw_power, */ 18973149Snyan}; 19073149Snyan 19173149Snyan/************************************************** 19273149Snyan * HW functions 19373149Snyan **************************************************/ 19473149Snyanstatic __inline void 195243455Snyancthw_phase_bypass(struct ct_softc *ct, u_int8_t ph) 19673149Snyan{ 19779697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 19873149Snyan 19979697Snon ct_cr_write_1(chp, wd3s_cph, ph); 20079697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR); 20173149Snyan} 20273149Snyan 20373149Snyanstatic void 204243455Snyancthw_bus_reset(struct ct_softc *ct) 20573149Snyan{ 20673149Snyan 20773149Snyan /* 20873149Snyan * wd33c93 does not have bus reset function. 20973149Snyan */ 21073149Snyan if (ct->ct_bus_reset != NULL) 21173149Snyan ((*ct->ct_bus_reset) (ct)); 21273149Snyan} 21373149Snyan 21473149Snyanstatic int 215243455Snyancthw_chip_reset(struct ct_bus_access_handle *chp, int *chiprevp, int chipclk, 216243455Snyan int hostid) 21773149Snyan{ 21873149Snyan#define CT_SELTIMEOUT_20MHz_REGV (0x80) 21973149Snyan u_int8_t aux, regv; 22073149Snyan u_int seltout; 22173149Snyan int wc; 22273149Snyan 22373149Snyan /* issue abort cmd */ 22479697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT); 22579697Snon SCSI_LOW_DELAY(1000); /* 1ms wait */ 22679697Snon (void) ct_stat_read_1(chp); 22779697Snon (void) ct_cr_read_1(chp, wd3s_stat); 22873149Snyan 22973149Snyan /* setup chip registers */ 23073149Snyan regv = 0; 23173149Snyan seltout = CT_SELTIMEOUT_20MHz_REGV; 23273149Snyan switch (chipclk) 23373149Snyan { 23479697Snon case 8: 23573149Snyan case 10: 23673149Snyan seltout = (seltout * chipclk) / 20; 23779697Snon regv = IDR_FS_8_10; 23873149Snyan break; 23973149Snyan 24079697Snon case 12: 24173149Snyan case 15: 24273149Snyan seltout = (seltout * chipclk) / 20; 24373149Snyan regv = IDR_FS_12_15; 24473149Snyan break; 24573149Snyan 24679697Snon case 16: 24773149Snyan case 20: 24873149Snyan seltout = (seltout * chipclk) / 20; 24978210Snyan regv = IDR_FS_16_20; 25073149Snyan break; 25173149Snyan 25273149Snyan default: 253118594Snon panic("ct: illegal chip clk rate"); 25473149Snyan break; 25573149Snyan } 25673149Snyan 25779697Snon regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF; 25879697Snon ct_cr_write_1(chp, wd3s_oid, regv); 25979697Snon 26079697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); 26173149Snyan for (wc = CT_RESET_DEFAULT; wc > 0; wc --) 26273149Snyan { 26379697Snon aux = ct_stat_read_1(chp); 26473149Snyan if (aux != 0xff && (aux & STR_INT)) 26573149Snyan { 26679697Snon regv = ct_cr_read_1(chp, wd3s_stat); 26779697Snon if (regv == BSR_RESET || regv == BSR_AFM_RESET) 26873149Snyan break; 26973149Snyan 27079697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); 27173149Snyan } 27279697Snon SCSI_LOW_DELAY(1); 27373149Snyan } 27473149Snyan if (wc == 0) 27573149Snyan return ENXIO; 27673149Snyan 27779697Snon ct_cr_write_1(chp, wd3s_tout, seltout); 27879697Snon ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL); 27979697Snon ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT); 28079697Snon ct_cr_write_1(chp, wd3s_synch, 0); 28179697Snon if (chiprevp != NULL) 28279697Snon { 28379697Snon *chiprevp = CT_WD33C93; 28479697Snon if (regv == BSR_RESET) 28579697Snon goto out; 28673149Snyan 28779697Snon *chiprevp = CT_WD33C93_A; 28879697Snon ct_cr_write_1(chp, wd3s_qtag, 0xaa); 28979697Snon if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa) 29079697Snon { 29179697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 29279697Snon goto out; 29379697Snon } 29479697Snon ct_cr_write_1(chp, wd3s_qtag, 0x55); 29579697Snon if (ct_cr_read_1(chp, wd3s_qtag) != 0x55) 29679697Snon { 29779697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 29879697Snon goto out; 29979697Snon } 30079697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 30179697Snon *chiprevp = CT_WD33C93_B; 30279697Snon } 30379697Snon 30479697Snonout: 30579697Snon (void) ct_stat_read_1(chp); 30679697Snon (void) ct_cr_read_1(chp, wd3s_stat); 30773149Snyan return 0; 30873149Snyan} 30973149Snyan 31079697Snonstatic struct ct_synch_data * 311243455Snyanct_make_synch_table(struct ct_softc *ct) 31279697Snon{ 31379697Snon struct ct_synch_data *sdtp, *sdp; 31479697Snon u_int base, i, period; 31579697Snon 31679697Snon sdtp = sdp = &ct->sc_default_sdt[0]; 31779697Snon 31879697Snon if ((ct->sc_chipclk % 5) == 0) 31979697Snon base = 1000 / (5 * 2); /* 5 MHz type */ 32079697Snon else 32179697Snon base = 1000 / (4 * 2); /* 4 MHz type */ 32279697Snon 32379697Snon if (ct->sc_chiprev >= CT_WD33C93_B) 32479697Snon { 32579697Snon /* fast scsi */ 32679697Snon for (i = 2; i < 8; i ++, sdp ++) 32779697Snon { 32879697Snon period = (base * i) / 2; 32979697Snon if (period >= 200) /* 5 MHz */ 33079697Snon break; 33179697Snon sdp->cs_period = period / 4; 33279697Snon sdp->cs_syncr = (i * 0x10) | 0x80; 33379697Snon } 33479697Snon } 33579697Snon 33679697Snon for (i = 2; i < 8; i ++, sdp ++) 33779697Snon { 33879697Snon period = (base * i); 33979697Snon if (period > 500) /* 2 MHz */ 34079697Snon break; 34179697Snon sdp->cs_period = period / 4; 34279697Snon sdp->cs_syncr = (i * 0x10); 34379697Snon } 34479697Snon 34579697Snon sdp->cs_period = 0; 34679697Snon sdp->cs_syncr = 0; 34779697Snon return sdtp; 34879697Snon} 34979697Snon 35073149Snyan/************************************************** 35173149Snyan * Attach & Probe 35273149Snyan **************************************************/ 35373149Snyanint 354243455Snyanctprobesubr(struct ct_bus_access_handle *chp, u_int dvcfg, int hsid, 355243455Snyan u_int chipclk, int *chiprevp) 35673149Snyan{ 35773149Snyan 35873149Snyan#if 0 35979697Snon if ((ct_stat_read_1(chp) & STR_BSY) != 0) 36073149Snyan return 0; 36173149Snyan#endif 36279697Snon if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0) 36373149Snyan return 0; 36473149Snyan return 1; 36573149Snyan} 36673149Snyan 36773149Snyanint 36873149Snyanctprint(aux, name) 36973149Snyan void *aux; 37073149Snyan const char *name; 37173149Snyan{ 37273149Snyan 37373149Snyan if (name != NULL) 37473149Snyan printf("%s: scsibus ", name); 37573149Snyan return UNCONF; 37673149Snyan} 37773149Snyan 37873149Snyanvoid 379243455Snyanctattachsubr(struct ct_softc *ct) 38073149Snyan{ 38173149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 38273149Snyan 38379697Snon ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ 38473149Snyan slp->sl_funcs = &ct_funcs; 38579697Snon slp->sl_flags |= HW_READ_PADDING; 38679697Snon (void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS, 38779697Snon sizeof(struct ct_targ_info), 0); 38873149Snyan} 38973149Snyan 39073149Snyan/************************************************** 39173149Snyan * SCSI LOW interface functions 39273149Snyan **************************************************/ 39373149Snyanstatic void 394243455Snyancthw_attention(struct ct_softc *ct) 39573149Snyan{ 39679697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 39773149Snyan 39879697Snon ct->sc_atten = 1; 39979697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0) 40073149Snyan return; 40173149Snyan 40279697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN); 40379697Snon SCSI_LOW_DELAY(10); 40479697Snon if ((ct_stat_read_1(chp) & STR_LCI) == 0) 40579697Snon ct->sc_atten = 0; 40679697Snon ct_unbusy(ct); 40779697Snon return; 40879697Snon} 40979697Snon 41079697Snonstatic void 411243455Snyanct_attention(struct ct_softc *ct) 41279697Snon{ 41379697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 41479697Snon 41579697Snon if (slp->sl_atten == 0) 41673149Snyan { 41779697Snon ct_unbusy(ct); 41879697Snon scsi_low_attention(slp); 41973149Snyan } 42079697Snon else if (ct->sc_atten != 0) 42179697Snon { 42279697Snon ct_unbusy(ct); 42379697Snon cthw_attention(ct); 42479697Snon } 42573149Snyan} 42673149Snyan 42773149Snyanstatic int 428243455Snyanct_targ_init(struct ct_softc *ct, struct targ_info *ti, int action) 42973149Snyan{ 43073149Snyan struct ct_targ_info *cti = (void *) ti; 43173149Snyan 43279697Snon if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) 43373149Snyan { 43479697Snon if (ct->sc_sdp == NULL) 43579697Snon { 43679697Snon ct->sc_sdp = ct_make_synch_table(ct); 43779697Snon } 43879697Snon 43979697Snon switch (ct->sc_chiprev) 44079697Snon { 44179697Snon default: 44279697Snon ti->ti_maxsynch.offset = 5; 44379697Snon break; 44479697Snon 44579697Snon case CT_WD33C93_A: 44679697Snon case CT_AM33C93_A: 44779697Snon ti->ti_maxsynch.offset = 12; 44879697Snon break; 44979697Snon 45079697Snon case CT_WD33C93_B: 45179697Snon case CT_WD33C93_C: 45279697Snon ti->ti_maxsynch.offset = 12; 45379697Snon break; 45479697Snon } 45579697Snon 45679697Snon ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period; 45779697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 45879697Snon cti->cti_syncreg = 0; 45973149Snyan } 46073149Snyan 46173149Snyan return 0; 46273149Snyan} 46373149Snyan 46473149Snyanstatic int 465243455Snyanct_world_start(struct ct_softc *ct, int fdone) 46673149Snyan{ 46773149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 46879697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 46973149Snyan 47073149Snyan if (ct->sc_sdp == NULL) 47179697Snon { 47279697Snon ct->sc_sdp = ct_make_synch_table(ct); 47379697Snon } 47473149Snyan 47573149Snyan if (slp->sl_cfgflags & CFG_NOPARITY) 47673149Snyan ct->sc_creg = CR_DEFAULT; 47773149Snyan else 47873149Snyan ct->sc_creg = CR_DEFAULT_HP; 47973149Snyan 48073149Snyan if (ct->sc_dma & CT_DMA_DMASTART) 48173149Snyan (*ct->ct_dma_xfer_stop) (ct); 48273149Snyan if (ct->sc_dma & CT_DMA_PIOSTART) 48373149Snyan (*ct->ct_pio_xfer_stop) (ct); 48473149Snyan ct->sc_dma = 0; 48573149Snyan ct->sc_atten = 0; 48673149Snyan 48779697Snon cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); 48873149Snyan scsi_low_bus_reset(slp); 48979697Snon cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); 49073149Snyan 49173149Snyan SOFT_INTR_REQUIRED(slp); 49273149Snyan return 0; 49373149Snyan} 49473149Snyan 49573149Snyanstatic int 496243455Snyanct_start_selection(struct ct_softc *ct, struct slccb *cb) 49773149Snyan{ 49873149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 49979697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 50079697Snon 50179697Snon struct targ_info *ti = slp->sl_Tnexus; 50279697Snon struct lun_info *li = slp->sl_Lnexus; 50379697Snon int s, satok; 50473149Snyan u_int8_t cmd; 50573149Snyan 50679697Snon ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 50773149Snyan ct->sc_atten = 0; 50879697Snon satok = 0; 50979697Snon 51079697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 51179697Snon { 51279697Snon if (ct->sc_chiprev >= CT_WD33C93_A) 51379697Snon satok = 1; 51479697Snon else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0) 51579697Snon satok = 1; 51679697Snon } 51779697Snon 51879697Snon if (satok != 0 && 51979697Snon scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0) 52073149Snyan { 52179697Snon cmd = WD3S_SELECT_ATN_TFR; 52273149Snyan ct->sc_satgo = CT_SAT_GOING; 52373149Snyan } 52473149Snyan else 52573149Snyan { 52673149Snyan cmd = WD3S_SELECT_ATN; 52773149Snyan ct->sc_satgo = 0; 52873149Snyan } 52973149Snyan 53079697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0) 53173149Snyan return SCSI_LOW_START_FAIL; 53273149Snyan 53373149Snyan if ((ct->sc_satgo & CT_SAT_GOING) != 0) 53479697Snon { 53579697Snon (void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT); 53679697Snon scsi_low_cmd(slp, ti); 53779697Snon ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); 53879697Snon ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 53979697Snon } 54079697Snon else 54179697Snon { 54279697Snon /* anyway attention assert */ 54379697Snon SCSI_LOW_ASSERT_ATN(slp); 54479697Snon } 54573149Snyan 54679697Snon ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction); 54779697Snon 54873149Snyan s = splhigh(); 54979697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0) 55073149Snyan { 55173149Snyan /* XXX: 55273149Snyan * Reload a lun again here. 55373149Snyan */ 55479697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 55579697Snon ct_cr_write_1(chp, wd3s_cmd, cmd); 55679697Snon if ((ct_stat_read_1(chp) & STR_LCI) == 0) 55773149Snyan { 55873149Snyan splx(s); 55973149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); 56073149Snyan return SCSI_LOW_START_OK; 56173149Snyan } 56273149Snyan } 56373149Snyan splx(s); 56473149Snyan return SCSI_LOW_START_FAIL; 56573149Snyan} 56673149Snyan 56773149Snyanstatic int 568243455Snyanct_msg(struct ct_softc *ct, struct targ_info *ti, u_int msg) 56973149Snyan{ 57079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 57173149Snyan struct ct_targ_info *cti = (void *) ti; 57273149Snyan struct ct_synch_data *csp = ct->sc_sdp; 57373149Snyan u_int offset, period; 57479697Snon int error; 57573149Snyan 57679697Snon if ((msg & SCSI_LOW_MSG_WIDE) != 0) 57779697Snon { 57879697Snon if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) 57979697Snon { 58079697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 58179697Snon return EINVAL; 58279697Snon } 58373149Snyan return 0; 58479697Snon } 58573149Snyan 58679697Snon if ((msg & SCSI_LOW_MSG_SYNCH) == 0) 58779697Snon return 0; 58879697Snon 58973149Snyan offset = ti->ti_maxsynch.offset; 59073149Snyan period = ti->ti_maxsynch.period; 59173149Snyan for ( ; csp->cs_period != 0; csp ++) 59273149Snyan { 59373149Snyan if (period == csp->cs_period) 59473149Snyan break; 59573149Snyan } 59673149Snyan 59773149Snyan if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0) 59873149Snyan { 59973149Snyan ti->ti_maxsynch.period = 0; 60073149Snyan ti->ti_maxsynch.offset = 0; 60173149Snyan cti->cti_syncreg = 0; 60279697Snon error = EINVAL; 60373149Snyan } 60479697Snon else 60579697Snon { 60679697Snon cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr); 60779697Snon error = 0; 60879697Snon } 60973149Snyan 61073149Snyan if (ct->ct_synch_setup != 0) 61179697Snon (*ct->ct_synch_setup) (ct, ti); 61279697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 61379697Snon return error; 61473149Snyan} 61573149Snyan 61673149Snyan/************************************************* 61773149Snyan * <DATA PHASE> 61873149Snyan *************************************************/ 61973149Snyanstatic int 620243455Snyanct_xfer(struct ct_softc *ct, u_int8_t *data, int len, int direction, 621243455Snyan u_int *statp) 62273149Snyan{ 62379697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 62473149Snyan int wc; 62573149Snyan register u_int8_t aux; 62673149Snyan 62779697Snon *statp = 0; 62873149Snyan if (len == 1) 62973149Snyan { 63079697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO); 63173149Snyan } 63273149Snyan else 63373149Snyan { 63479697Snon cthw_set_count(chp, len); 63579697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); 63673149Snyan } 63773149Snyan 63879697Snon aux = ct_stat_read_1(chp); 63973149Snyan if ((aux & STR_LCI) != 0) 64073149Snyan { 64179697Snon cthw_set_count(chp, 0); 64273149Snyan return len; 64373149Snyan } 64473149Snyan 64579697Snon for (wc = 0; wc < ct->sc_tmaxcnt; wc ++) 64673149Snyan { 64773149Snyan /* check data ready */ 64873149Snyan if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR)) 64973149Snyan { 65073149Snyan if (direction == SCSI_LOW_READ) 65179697Snon { 65279697Snon *data = ct_cr_read_1(chp, wd3s_data); 65379697Snon if ((aux & STR_PE) != 0) 65479697Snon *statp |= SCSI_LOW_DATA_PE; 65579697Snon } 65673149Snyan else 65779697Snon { 65879697Snon ct_cr_write_1(chp, wd3s_data, *data); 65979697Snon } 66073149Snyan len --; 66173149Snyan if (len <= 0) 66273149Snyan break; 66373149Snyan data ++; 66473149Snyan } 66579697Snon else 66679697Snon { 66779697Snon SCSI_LOW_DELAY(1); 66879697Snon } 66973149Snyan 67073149Snyan /* check phase miss */ 67179697Snon aux = ct_stat_read_1(chp); 67273149Snyan if ((aux & STR_INT) != 0) 67373149Snyan break; 67473149Snyan } 67573149Snyan return len; 67673149Snyan} 67773149Snyan 67879697Snon#define CT_PADDING_BUF_SIZE 32 67979697Snon 68073149Snyanstatic void 681243455Snyanct_io_xfer(struct ct_softc *ct) 68273149Snyan{ 68373149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 68479697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 68573149Snyan struct sc_p *sp = &slp->sl_scp; 68679697Snon u_int stat; 68773149Snyan int len; 68879697Snon u_int8_t pbuf[CT_PADDING_BUF_SIZE]; 68973149Snyan 69079697Snon /* polling mode */ 69179697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg); 69273149Snyan 69373149Snyan if (sp->scp_datalen <= 0) 69473149Snyan { 69573149Snyan slp->sl_error |= PDMAERR; 69679697Snon 69779697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 69879697Snon SCSI_LOW_BZERO(pbuf, CT_PADDING_BUF_SIZE); 69979697Snon ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE, 70079697Snon sp->scp_direction, &stat); 70173149Snyan } 70273149Snyan else 70379697Snon { 70473149Snyan len = ct_xfer(ct, sp->scp_data, sp->scp_datalen, 70579697Snon sp->scp_direction, &stat); 70679697Snon sp->scp_data += (sp->scp_datalen - len); 70779697Snon sp->scp_datalen = len; 70879697Snon } 70973149Snyan} 71073149Snyan 71173149Snyan/************************************************** 71273149Snyan * <PHASE ERROR> 71373149Snyan **************************************************/ 71473149Snyanstruct ct_err { 71573149Snyan u_char *pe_msg; 71673149Snyan u_int pe_err; 71773149Snyan u_int pe_errmsg; 71873149Snyan int pe_done; 71973149Snyan}; 72073149Snyan 72173149Snyanstruct ct_err ct_cmderr[] = { 72273149Snyan/*0*/ { "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1}, 72373149Snyan/*1*/ { "unexpected bus free", FATALIO, 0, 1}, 72473149Snyan/*2*/ { NULL, SELTIMEOUTIO, 0, 1}, 72573149Snyan/*3*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 72673149Snyan/*4*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 72773149Snyan/*5*/ { "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1}, 72873149Snyan/*6*/ { "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0}, 72973149Snyan/*7*/ { "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 73073149Snyan}; 73173149Snyan 73273149Snyanstatic void 733243455Snyanct_phase_error(struct ct_softc *ct, u_int8_t scsi_status) 73473149Snyan{ 73573149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 73679697Snon struct targ_info *ti = slp->sl_Tnexus; 73773149Snyan struct ct_err *pep; 73873149Snyan u_int msg = 0; 73973149Snyan 74073149Snyan if ((scsi_status & BSR_CM) == BSR_CMDERR && 74173149Snyan (scsi_status & BSR_PHVALID) == 0) 74273149Snyan { 74373149Snyan pep = &ct_cmderr[scsi_status & BSR_PM]; 74473149Snyan slp->sl_error |= pep->pe_err; 74573149Snyan if ((pep->pe_err & PARITYERR) != 0) 74673149Snyan { 74773149Snyan if (ti->ti_phase == PH_MSGIN) 74873149Snyan msg = SCSI_LOW_MSG_PARITY; 74973149Snyan else 75073149Snyan msg = SCSI_LOW_MSG_ERROR; 75173149Snyan } 75273149Snyan else 75373149Snyan msg = pep->pe_errmsg; 75473149Snyan 75573149Snyan if (msg != 0) 75679697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1); 75773149Snyan 75873149Snyan if (pep->pe_msg != NULL) 75973149Snyan { 76073149Snyan printf("%s: phase error: %s", 76173149Snyan slp->sl_xname, pep->pe_msg); 76279697Snon scsi_low_print(slp, slp->sl_Tnexus); 76373149Snyan } 76473149Snyan 76573149Snyan if (pep->pe_done != 0) 76673149Snyan scsi_low_disconnected(slp, ti); 76773149Snyan } 76873149Snyan else 76973149Snyan { 77073149Snyan slp->sl_error |= FATALIO; 77173149Snyan scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error"); 77273149Snyan } 77373149Snyan} 77473149Snyan 77573149Snyan/************************************************** 77673149Snyan * ### SCSI PHASE SEQUENCER ### 77773149Snyan **************************************************/ 77879697Snonstatic int 779243455Snyanct_reselected(struct ct_softc *ct, u_int8_t scsi_status) 78073149Snyan{ 78173149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 78279697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 78373149Snyan struct targ_info *ti; 78473149Snyan u_int sid; 78579697Snon u_int8_t regv; 78673149Snyan 78773149Snyan ct->sc_atten = 0; 78879697Snon ct->sc_satgo &= ~CT_SAT_GOING; 78979697Snon regv = ct_cr_read_1(chp, wd3s_sid); 79079697Snon if ((regv & SIDR_VALID) == 0) 79179697Snon return EJUSTRETURN; 79279697Snon 79379697Snon sid = regv & SIDR_IDM; 79473149Snyan if ((ti = scsi_low_reselected(slp, sid)) == NULL) 79573149Snyan return EJUSTRETURN; 79673149Snyan 79779697Snon ct_target_nexus_establish(ct, 0, SCSI_LOW_READ); 79879697Snon if (scsi_status != BSR_AFM_RESEL) 79979697Snon return EJUSTRETURN; 80079697Snon 80179697Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 80279697Snon regv = ct_cr_read_1(chp, wd3s_data); 80379697Snon if (scsi_low_msgin(slp, ti, (u_int) regv) == 0) 80479697Snon { 80579697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0) 80679697Snon { 80779697Snon /* XXX: scsi_low_attetion */ 80879697Snon scsi_low_attention(slp); 80979697Snon } 81079697Snon } 81179697Snon 81279697Snon if (ct->sc_atten != 0) 81379697Snon { 81479697Snon ct_attention(ct); 81579697Snon } 81679697Snon 81779697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); 81873149Snyan return EJUSTRETURN; 81973149Snyan} 82073149Snyan 82173149Snyanstatic int 822243455Snyanct_target_nexus_establish(struct ct_softc *ct, int lun, int dir) 82373149Snyan{ 82479697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 82579697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 82679697Snon struct targ_info *ti = slp->sl_Tnexus; 82773149Snyan struct ct_targ_info *cti = (void *) ti; 82873149Snyan 82979697Snon if (dir == SCSI_LOW_WRITE) 83079697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id); 83173149Snyan else 83279697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); 83379697Snon ct_cr_write_1(chp, wd3s_lun, lun); 83479697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); 83579697Snon ct_cr_write_1(chp, wd3s_cph, 0); 83679697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 83779697Snon cthw_set_count(chp, 0); 83879697Snon return 0; 83979697Snon} 84073149Snyan 84179697Snonstatic int 842243455Snyanct_lun_nexus_establish(struct ct_softc *ct) 84379697Snon{ 84479697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 84579697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 84679697Snon struct lun_info *li = slp->sl_Lnexus; 84779697Snon 84879697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 84973149Snyan return 0; 85073149Snyan} 85173149Snyan 85279697Snonstatic int 853243455Snyanct_ccb_nexus_establish(struct ct_softc *ct) 85479697Snon{ 85579697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 85679697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 85779697Snon struct lun_info *li = slp->sl_Lnexus; 85879697Snon struct targ_info *ti = slp->sl_Tnexus; 85979697Snon struct ct_targ_info *cti = (void *) ti; 86079697Snon struct slccb *cb = slp->sl_Qnexus; 86179697Snon 86279697Snon ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 86379697Snon 86479697Snon if ((ct->sc_satgo & CT_SAT_GOING) != 0) 86579697Snon { 86679697Snon ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); 86779697Snon ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 86879697Snon } 86979697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 87079697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id); 87179697Snon else 87279697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); 87379697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 87479697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 87579697Snon return 0; 87679697Snon} 87779697Snon 87879697Snonstatic int 879243455Snyanct_unbusy(struct ct_softc *ct) 88079697Snon{ 88179697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 88279697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 88379697Snon int wc; 88479697Snon register u_int8_t regv; 88579697Snon 88679697Snon for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) 88779697Snon { 88879697Snon regv = ct_stat_read_1(chp); 88979697Snon if ((regv & (STR_BSY | STR_CIP)) == 0) 89079697Snon return 0; 89179697Snon if (regv == (u_int8_t) -1) 89279697Snon return EIO; 89379697Snon 89479697Snon SCSI_LOW_DELAY(CT_DELAY_INTERVAL); 89579697Snon } 89679697Snon 89779697Snon printf("%s: unbusy timeout\n", slp->sl_xname); 89879697Snon return EBUSY; 89979697Snon} 90079697Snon 90179697Snonstatic int 902243455Snyanct_catch_intr(struct ct_softc *ct) 90379697Snon{ 90479697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 90579697Snon int wc; 90679697Snon register u_int8_t regv; 90779697Snon 90879697Snon for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) 90979697Snon { 91079697Snon regv = ct_stat_read_1(chp); 91179697Snon if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT) 91279697Snon return 0; 91379697Snon 91479697Snon SCSI_LOW_DELAY(CT_DELAY_INTERVAL); 91579697Snon } 91679697Snon return EJUSTRETURN; 91779697Snon} 91879697Snon 91973149Snyanint 920243455Snyanctintr(void *arg) 92173149Snyan{ 92273149Snyan struct ct_softc *ct = arg; 92373149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 92479697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 92573149Snyan struct targ_info *ti; 92673149Snyan struct physio_proc *pp; 92773149Snyan struct buf *bp; 92879697Snon u_int derror, flags; 92979697Snon int len, satgo, error; 93073149Snyan u_int8_t scsi_status, regv; 93173149Snyan 93279697Snonagain: 93373149Snyan if (slp->sl_flags & HW_INACTIVE) 93473149Snyan return 0; 93573149Snyan 93673149Snyan /************************************************** 93773149Snyan * Get status & bus phase 93873149Snyan **************************************************/ 93979697Snon if ((ct_stat_read_1(chp) & STR_INT) == 0) 94073149Snyan return 0; 94173149Snyan 94279697Snon scsi_status = ct_cr_read_1(chp, wd3s_stat); 94373149Snyan if (scsi_status == ((u_int8_t) -1)) 94473149Snyan return 1; 94573149Snyan 94673149Snyan /************************************************** 94773149Snyan * Check reselection, or nexus 94873149Snyan **************************************************/ 94979697Snon if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL) 95073149Snyan { 95179697Snon if (ct_reselected(ct, scsi_status) == EJUSTRETURN) 95273149Snyan return 1; 95373149Snyan } 95473149Snyan 95579697Snon if ((ti = slp->sl_Tnexus) == NULL) 95673149Snyan return 1; 95773149Snyan 95873149Snyan /************************************************** 95973149Snyan * Debug section 96073149Snyan **************************************************/ 96173149Snyan#ifdef CT_DEBUG 96273149Snyan if (ct_debug > 0) 96373149Snyan { 96473149Snyan scsi_low_print(slp, NULL); 96573149Snyan printf("%s: scsi_status 0x%x\n\n", slp->sl_xname, 96673149Snyan (u_int) scsi_status); 967131911Smarcel#ifdef KDB 96873149Snyan if (ct_debug > 1) 96979697Snon SCSI_LOW_DEBUGGER("ct"); 970131911Smarcel#endif /* KDB */ 97173149Snyan } 97273149Snyan#endif /* CT_DEBUG */ 97373149Snyan 97473149Snyan /************************************************** 97573149Snyan * Internal scsi phase 97673149Snyan **************************************************/ 97773149Snyan satgo = ct->sc_satgo; 97879697Snon ct->sc_satgo &= ~CT_SAT_GOING; 97973149Snyan 98073149Snyan switch (ti->ti_phase) 98173149Snyan { 98273149Snyan case PH_SELSTART: 98373149Snyan if ((satgo & CT_SAT_GOING) == 0) 98473149Snyan { 98573149Snyan if (scsi_status != BSR_SELECTED) 98673149Snyan { 98773149Snyan ct_phase_error(ct, scsi_status); 98873149Snyan return 1; 98973149Snyan } 99079697Snon scsi_low_arbit_win(slp); 99173149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); 99273149Snyan return 1; 99373149Snyan } 99473149Snyan else 99573149Snyan { 99679697Snon scsi_low_arbit_win(slp); 99779697Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */ 99873149Snyan } 99973149Snyan break; 100073149Snyan 100173149Snyan case PH_RESEL: 100273149Snyan if ((scsi_status & BSR_PHVALID) == 0 || 100373149Snyan (scsi_status & BSR_PM) != BSR_MSGIN) 100473149Snyan { 100573149Snyan scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 100673149Snyan "phase miss after reselect"); 100773149Snyan return 1; 100873149Snyan } 100973149Snyan break; 101073149Snyan 101173149Snyan default: 101273149Snyan if (slp->sl_flags & HW_PDMASTART) 101373149Snyan { 101473149Snyan slp->sl_flags &= ~HW_PDMASTART; 101573149Snyan if (ct->sc_dma & CT_DMA_DMASTART) 101673149Snyan { 101773149Snyan (*ct->ct_dma_xfer_stop) (ct); 101873149Snyan ct->sc_dma &= ~CT_DMA_DMASTART; 101973149Snyan } 102079697Snon else if (ct->sc_dma & CT_DMA_PIOSTART) 102173149Snyan { 102273149Snyan (*ct->ct_pio_xfer_stop) (ct); 102373149Snyan ct->sc_dma &= ~CT_DMA_PIOSTART; 102473149Snyan } 102579697Snon else 102679697Snon { 102779697Snon scsi_low_data_finish(slp); 102879697Snon } 102973149Snyan } 103073149Snyan break; 103173149Snyan } 103273149Snyan 103373149Snyan /************************************************** 103473149Snyan * parse scsi phase 103573149Snyan **************************************************/ 103673149Snyan if (scsi_status & BSR_PHVALID) 103773149Snyan { 103873149Snyan /************************************************** 103973149Snyan * Normal SCSI phase. 104073149Snyan **************************************************/ 104173149Snyan if ((scsi_status & BSR_CM) == BSR_CMDABT) 104273149Snyan { 104373149Snyan ct_phase_error(ct, scsi_status); 104473149Snyan return 1; 104573149Snyan } 104673149Snyan 104773149Snyan switch (scsi_status & BSR_PM) 104873149Snyan { 104973149Snyan case BSR_DATAOUT: 105073149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 105173149Snyan if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) 105279697Snon { 105379697Snon ct_attention(ct); 105479697Snon } 105573149Snyan goto common_data_phase; 105673149Snyan 105773149Snyan case BSR_DATAIN: 105873149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 105973149Snyan if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) 106079697Snon { 106179697Snon ct_attention(ct); 106279697Snon } 106373149Snyan 106473149Snyancommon_data_phase: 106579697Snon if (slp->sl_scp.scp_datalen > 0) 106673149Snyan { 106779697Snon slp->sl_flags |= HW_PDMASTART; 106879697Snon if ((ct->sc_xmode & CT_XMODE_PIO) != 0) 106979697Snon { 107079697Snon pp = physio_proc_enter(bp); 107179697Snon error = (*ct->ct_pio_xfer_start) (ct); 107279697Snon physio_proc_leave(pp); 107379697Snon if (error == 0) 107479697Snon { 107579697Snon ct->sc_dma |= CT_DMA_PIOSTART; 107679697Snon return 1; 107779697Snon } 107879697Snon } 107973149Snyan 108079697Snon if ((ct->sc_xmode & CT_XMODE_DMA) != 0) 108179697Snon { 108279697Snon error = (*ct->ct_dma_xfer_start) (ct); 108379697Snon if (error == 0) 108479697Snon { 108579697Snon ct->sc_dma |= CT_DMA_DMASTART; 108679697Snon return 1; 108779697Snon } 108879697Snon } 108973149Snyan } 109073149Snyan else 109179697Snon { 109279697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_READ) 109379697Snon { 109479697Snon if (!(slp->sl_flags & HW_READ_PADDING)) 109579697Snon { 109679697Snon printf("%s: read padding required\n", slp->sl_xname); 109779697Snon return 1; 109879697Snon } 109979697Snon } 110079697Snon else 110179697Snon { 110279697Snon if (!(slp->sl_flags & HW_WRITE_PADDING)) 110379697Snon { 110479697Snon printf("%s: write padding required\n", slp->sl_xname); 110579697Snon return 1; 110679697Snon } 110779697Snon } 110879697Snon slp->sl_flags |= HW_PDMASTART; 110973149Snyan } 111079697Snon 111179697Snon ct_io_xfer(ct); 111273149Snyan return 1; 111373149Snyan 111473149Snyan case BSR_CMDOUT: 111573149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_CMD); 111673149Snyan if (scsi_low_cmd(slp, ti) != 0) 111779697Snon { 111879697Snon ct_attention(ct); 111979697Snon } 112073149Snyan 112179697Snon if (ct_xfer(ct, slp->sl_scp.scp_cmd, 112273149Snyan slp->sl_scp.scp_cmdlen, 112379697Snon SCSI_LOW_WRITE, &derror) != 0) 112473149Snyan { 112573149Snyan printf("%s: scsi cmd xfer short\n", 112673149Snyan slp->sl_xname); 112773149Snyan } 112873149Snyan return 1; 112973149Snyan 113073149Snyan case BSR_STATIN: 113173149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 113279697Snon if ((ct_io_control & CT_USE_CCSEQ) != 0) 113373149Snyan { 113479697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0 || 113579697Snon ct->sc_atten != 0) 113679697Snon { 113779697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, 113879697Snon &derror); 113979697Snon scsi_low_statusin(slp, ti, 114079697Snon regv | derror); 114179697Snon } 114279697Snon else 114379697Snon { 114479697Snon ct->sc_satgo |= CT_SAT_GOING; 114579697Snon cthw_set_count(chp, 0); 114679697Snon cthw_phase_bypass(ct, 0x41); 114779697Snon } 114873149Snyan } 114973149Snyan else 115073149Snyan { 115179697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); 115279697Snon scsi_low_statusin(slp, ti, regv | derror); 115373149Snyan } 115473149Snyan return 1; 115573149Snyan 115673149Snyan case BSR_UNSPINFO0: 115773149Snyan case BSR_UNSPINFO1: 115873149Snyan printf("%s: illegal bus phase (0x%x)\n", slp->sl_xname, 115973149Snyan (u_int) scsi_status); 116073149Snyan scsi_low_print(slp, ti); 116173149Snyan return 1; 116273149Snyan 116373149Snyan case BSR_MSGOUT: 116473149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); 116579697Snon flags = SCSI_LOW_MSGOUT_UNIFY; 116679697Snon if (ti->ti_ophase != ti->ti_phase) 116779697Snon flags |= SCSI_LOW_MSGOUT_INIT; 116879697Snon len = scsi_low_msgout(slp, ti, flags); 116979697Snon 117079697Snon if (len > 1 && slp->sl_atten == 0) 117173149Snyan { 117279697Snon ct_attention(ct); 117379697Snon } 117479697Snon 117579697Snon if (ct_xfer(ct, ti->ti_msgoutstr, len, 117679697Snon SCSI_LOW_WRITE, &derror) != 0) 117779697Snon { 117873149Snyan printf("%s: scsi msgout xfer short\n", 117973149Snyan slp->sl_xname); 118073149Snyan } 118179697Snon SCSI_LOW_DEASSERT_ATN(slp); 118279697Snon ct->sc_atten = 0; 118373149Snyan return 1; 118473149Snyan 118573149Snyan case BSR_MSGIN:/* msg in */ 118673149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 118779697Snon 118879697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); 118979697Snon if (scsi_low_msgin(slp, ti, regv | derror) == 0) 119079697Snon { 119179697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0) 119279697Snon { 119379697Snon /* XXX: scsi_low_attetion */ 119479697Snon scsi_low_attention(slp); 119579697Snon } 119679697Snon } 119779697Snon 119879697Snon if ((ct_io_control & CT_FAST_INTR) != 0) 119979697Snon { 120079697Snon if (ct_catch_intr(ct) == 0) 120179697Snon goto again; 120279697Snon } 120373149Snyan return 1; 120473149Snyan } 120573149Snyan } 120673149Snyan else 120773149Snyan { 120873149Snyan /************************************************** 120973149Snyan * Special SCSI phase 121073149Snyan **************************************************/ 121173149Snyan switch (scsi_status) 121273149Snyan { 121373149Snyan case BSR_SATSDP: /* SAT with save data pointer */ 121473149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 121579697Snon ct->sc_satgo |= CT_SAT_GOING; 121673149Snyan scsi_low_msgin(slp, ti, MSG_SAVESP); 121773149Snyan cthw_phase_bypass(ct, 0x41); 121873149Snyan return 1; 121973149Snyan 122073149Snyan case BSR_SATFIN: /* SAT COMPLETE */ 122173149Snyan /* 122273149Snyan * emulate statusin => msgin 122373149Snyan */ 122479697Snon SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 122579697Snon scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun)); 122679697Snon 122773149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 122879697Snon scsi_low_msgin(slp, ti, MSG_COMP); 122979697Snon 123073149Snyan scsi_low_disconnected(slp, ti); 123173149Snyan return 1; 123273149Snyan 123373149Snyan case BSR_ACKREQ: /* negate ACK */ 123473149Snyan if (ct->sc_atten != 0) 123579697Snon { 123679697Snon ct_attention(ct); 123779697Snon } 123873149Snyan 123979697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); 124079697Snon if ((ct_io_control & CT_FAST_INTR) != 0) 124179697Snon { 124279697Snon /* XXX: 124379697Snon * Should clear a pending interrupt and 124479697Snon * sync with a next interrupt! 124579697Snon */ 124679697Snon ct_catch_intr(ct); 124779697Snon } 124873149Snyan return 1; 124973149Snyan 125073149Snyan case BSR_DISC: /* disconnect */ 125173149Snyan if (slp->sl_msgphase == MSGPH_NULL && 125273149Snyan (satgo & CT_SAT_GOING) != 0) 125373149Snyan { 125473149Snyan /* 125573149Snyan * emulate disconnect msg 125673149Snyan */ 125773149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 125879697Snon scsi_low_msgin(slp, ti, MSG_DISCON); 125973149Snyan } 126073149Snyan scsi_low_disconnected(slp, ti); 126173149Snyan return 1; 126273149Snyan 126373149Snyan default: 126473149Snyan break; 126573149Snyan } 126673149Snyan } 126773149Snyan 126873149Snyan ct_phase_error(ct, scsi_status); 126973149Snyan return 1; 127073149Snyan} 1271