ct.c revision 118594
173149Snyan/* $FreeBSD: head/sys/dev/ct/ct.c 118594 2003-08-07 08:13:37Z non $ */ 279697Snon/* $NecBSD: ct.c,v 1.13.12.5 2001/06/26 07:31:53 honda Exp $ */ 373149Snyan/* $NetBSD$ */ 473149Snyan 573149Snyan#define CT_DEBUG 679697Snon#define CT_IO_CONTROL_FLAGS (CT_USE_CCSEQ | CT_FAST_INTR) 773149Snyan 873149Snyan/* 973149Snyan * [NetBSD for NEC PC-98 series] 1079697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1173149Snyan * NetBSD/pc98 porting staff. All rights reserved. 1273149Snyan * 1379697Snon * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 1473149Snyan * Naofumi HONDA. All rights reserved. 1573149Snyan * 1673149Snyan * Redistribution and use in source and binary forms, with or without 1773149Snyan * modification, are permitted provided that the following conditions 1873149Snyan * are met: 1973149Snyan * 1. Redistributions of source code must retain the above copyright 2073149Snyan * notice, this list of conditions and the following disclaimer. 2173149Snyan * 2. Redistributions in binary form must reproduce the above copyright 2273149Snyan * notice, this list of conditions and the following disclaimer in the 2373149Snyan * documentation and/or other materials provided with the distribution. 2473149Snyan * 3. The name of the author may not be used to endorse or promote products 2573149Snyan * derived from this software without specific prior written permission. 2673149Snyan * 2773149Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2873149Snyan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2973149Snyan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 3073149Snyan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 3173149Snyan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 3273149Snyan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3373149Snyan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3473149Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3573149Snyan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 3673149Snyan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3773149Snyan * POSSIBILITY OF SUCH DAMAGE. 3873149Snyan */ 3973149Snyan 4073149Snyan#include "opt_ddb.h" 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 7773149Snyan#include <machine/dvcfg.h> 7873149Snyan#include <machine/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 19573149Snyancthw_phase_bypass(ct, ph) 19673149Snyan struct ct_softc *ct; 19773149Snyan u_int8_t ph; 19873149Snyan{ 19979697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 20073149Snyan 20179697Snon ct_cr_write_1(chp, wd3s_cph, ph); 20279697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_SELECT_ATN_TFR); 20373149Snyan} 20473149Snyan 20573149Snyanstatic void 20673149Snyancthw_bus_reset(ct) 20773149Snyan struct ct_softc *ct; 20873149Snyan{ 20973149Snyan 21073149Snyan /* 21173149Snyan * wd33c93 does not have bus reset function. 21273149Snyan */ 21373149Snyan if (ct->ct_bus_reset != NULL) 21473149Snyan ((*ct->ct_bus_reset) (ct)); 21573149Snyan} 21673149Snyan 21773149Snyanstatic int 21879697Snoncthw_chip_reset(chp, chiprevp, chipclk, hostid) 21979697Snon struct ct_bus_access_handle *chp; 22079697Snon int *chiprevp; 22173149Snyan int chipclk, hostid; 22273149Snyan{ 22373149Snyan#define CT_SELTIMEOUT_20MHz_REGV (0x80) 22473149Snyan u_int8_t aux, regv; 22573149Snyan u_int seltout; 22673149Snyan int wc; 22773149Snyan 22873149Snyan /* issue abort cmd */ 22979697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_ABORT); 23079697Snon SCSI_LOW_DELAY(1000); /* 1ms wait */ 23179697Snon (void) ct_stat_read_1(chp); 23279697Snon (void) ct_cr_read_1(chp, wd3s_stat); 23373149Snyan 23473149Snyan /* setup chip registers */ 23573149Snyan regv = 0; 23673149Snyan seltout = CT_SELTIMEOUT_20MHz_REGV; 23773149Snyan switch (chipclk) 23873149Snyan { 23979697Snon case 8: 24073149Snyan case 10: 24173149Snyan seltout = (seltout * chipclk) / 20; 24279697Snon regv = IDR_FS_8_10; 24373149Snyan break; 24473149Snyan 24579697Snon case 12: 24673149Snyan case 15: 24773149Snyan seltout = (seltout * chipclk) / 20; 24873149Snyan regv = IDR_FS_12_15; 24973149Snyan break; 25073149Snyan 25179697Snon case 16: 25273149Snyan case 20: 25373149Snyan seltout = (seltout * chipclk) / 20; 25478210Snyan regv = IDR_FS_16_20; 25573149Snyan break; 25673149Snyan 25773149Snyan default: 258118594Snon panic("ct: illegal chip clk rate"); 25973149Snyan break; 26073149Snyan } 26173149Snyan 26279697Snon regv |= IDR_EHP | hostid | IDR_RAF | IDR_EAF; 26379697Snon ct_cr_write_1(chp, wd3s_oid, regv); 26479697Snon 26579697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); 26673149Snyan for (wc = CT_RESET_DEFAULT; wc > 0; wc --) 26773149Snyan { 26879697Snon aux = ct_stat_read_1(chp); 26973149Snyan if (aux != 0xff && (aux & STR_INT)) 27073149Snyan { 27179697Snon regv = ct_cr_read_1(chp, wd3s_stat); 27279697Snon if (regv == BSR_RESET || regv == BSR_AFM_RESET) 27373149Snyan break; 27473149Snyan 27579697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_RESET); 27673149Snyan } 27779697Snon SCSI_LOW_DELAY(1); 27873149Snyan } 27973149Snyan if (wc == 0) 28073149Snyan return ENXIO; 28173149Snyan 28279697Snon ct_cr_write_1(chp, wd3s_tout, seltout); 28379697Snon ct_cr_write_1(chp, wd3s_sid, SIDR_RESEL); 28479697Snon ct_cr_write_1(chp, wd3s_ctrl, CR_DEFAULT); 28579697Snon ct_cr_write_1(chp, wd3s_synch, 0); 28679697Snon if (chiprevp != NULL) 28779697Snon { 28879697Snon *chiprevp = CT_WD33C93; 28979697Snon if (regv == BSR_RESET) 29079697Snon goto out; 29173149Snyan 29279697Snon *chiprevp = CT_WD33C93_A; 29379697Snon ct_cr_write_1(chp, wd3s_qtag, 0xaa); 29479697Snon if (ct_cr_read_1(chp, wd3s_qtag) != 0xaa) 29579697Snon { 29679697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 29779697Snon goto out; 29879697Snon } 29979697Snon ct_cr_write_1(chp, wd3s_qtag, 0x55); 30079697Snon if (ct_cr_read_1(chp, wd3s_qtag) != 0x55) 30179697Snon { 30279697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 30379697Snon goto out; 30479697Snon } 30579697Snon ct_cr_write_1(chp, wd3s_qtag, 0x0); 30679697Snon *chiprevp = CT_WD33C93_B; 30779697Snon } 30879697Snon 30979697Snonout: 31079697Snon (void) ct_stat_read_1(chp); 31179697Snon (void) ct_cr_read_1(chp, wd3s_stat); 31273149Snyan return 0; 31373149Snyan} 31473149Snyan 31579697Snonstatic struct ct_synch_data * 31679697Snonct_make_synch_table(ct) 31779697Snon struct ct_softc *ct; 31879697Snon{ 31979697Snon struct ct_synch_data *sdtp, *sdp; 32079697Snon u_int base, i, period; 32179697Snon 32279697Snon sdtp = sdp = &ct->sc_default_sdt[0]; 32379697Snon 32479697Snon if ((ct->sc_chipclk % 5) == 0) 32579697Snon base = 1000 / (5 * 2); /* 5 MHz type */ 32679697Snon else 32779697Snon base = 1000 / (4 * 2); /* 4 MHz type */ 32879697Snon 32979697Snon if (ct->sc_chiprev >= CT_WD33C93_B) 33079697Snon { 33179697Snon /* fast scsi */ 33279697Snon for (i = 2; i < 8; i ++, sdp ++) 33379697Snon { 33479697Snon period = (base * i) / 2; 33579697Snon if (period >= 200) /* 5 MHz */ 33679697Snon break; 33779697Snon sdp->cs_period = period / 4; 33879697Snon sdp->cs_syncr = (i * 0x10) | 0x80; 33979697Snon } 34079697Snon } 34179697Snon 34279697Snon for (i = 2; i < 8; i ++, sdp ++) 34379697Snon { 34479697Snon period = (base * i); 34579697Snon if (period > 500) /* 2 MHz */ 34679697Snon break; 34779697Snon sdp->cs_period = period / 4; 34879697Snon sdp->cs_syncr = (i * 0x10); 34979697Snon } 35079697Snon 35179697Snon sdp->cs_period = 0; 35279697Snon sdp->cs_syncr = 0; 35379697Snon return sdtp; 35479697Snon} 35579697Snon 35673149Snyan/************************************************** 35773149Snyan * Attach & Probe 35873149Snyan **************************************************/ 35973149Snyanint 36079697Snonctprobesubr(chp, dvcfg, hsid, chipclk, chiprevp) 36179697Snon struct ct_bus_access_handle *chp; 36273149Snyan u_int dvcfg, chipclk; 36373149Snyan int hsid; 36479697Snon int *chiprevp; 36573149Snyan{ 36673149Snyan 36773149Snyan#if 0 36879697Snon if ((ct_stat_read_1(chp) & STR_BSY) != 0) 36973149Snyan return 0; 37073149Snyan#endif 37179697Snon if (cthw_chip_reset(chp, chiprevp, chipclk, hsid) != 0) 37273149Snyan return 0; 37373149Snyan return 1; 37473149Snyan} 37573149Snyan 37673149Snyanint 37773149Snyanctprint(aux, name) 37873149Snyan void *aux; 37973149Snyan const char *name; 38073149Snyan{ 38173149Snyan 38273149Snyan if (name != NULL) 38373149Snyan printf("%s: scsibus ", name); 38473149Snyan return UNCONF; 38573149Snyan} 38673149Snyan 38773149Snyanvoid 38873149Snyanctattachsubr(ct) 38973149Snyan struct ct_softc *ct; 39073149Snyan{ 39173149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 39273149Snyan 39379697Snon ct->sc_tmaxcnt = SCSI_LOW_MIN_TOUT * 1000 * 1000; /* default */ 39473149Snyan slp->sl_funcs = &ct_funcs; 39579697Snon slp->sl_flags |= HW_READ_PADDING; 39679697Snon (void) scsi_low_attach(slp, 0, CT_NTARGETS, CT_NLUNS, 39779697Snon sizeof(struct ct_targ_info), 0); 39873149Snyan} 39973149Snyan 40073149Snyan/************************************************** 40173149Snyan * SCSI LOW interface functions 40273149Snyan **************************************************/ 40373149Snyanstatic void 40473149Snyancthw_attention(ct) 40573149Snyan struct ct_softc *ct; 40673149Snyan{ 40779697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 40873149Snyan 40979697Snon ct->sc_atten = 1; 41079697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_CIP)) != 0) 41173149Snyan return; 41273149Snyan 41379697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_ASSERT_ATN); 41479697Snon SCSI_LOW_DELAY(10); 41579697Snon if ((ct_stat_read_1(chp) & STR_LCI) == 0) 41679697Snon ct->sc_atten = 0; 41779697Snon ct_unbusy(ct); 41879697Snon return; 41979697Snon} 42079697Snon 42179697Snonstatic void 42279697Snonct_attention(ct) 42379697Snon struct ct_softc *ct; 42479697Snon{ 42579697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 42679697Snon 42779697Snon if (slp->sl_atten == 0) 42873149Snyan { 42979697Snon ct_unbusy(ct); 43079697Snon scsi_low_attention(slp); 43173149Snyan } 43279697Snon else if (ct->sc_atten != 0) 43379697Snon { 43479697Snon ct_unbusy(ct); 43579697Snon cthw_attention(ct); 43679697Snon } 43773149Snyan} 43873149Snyan 43973149Snyanstatic int 44079697Snonct_targ_init(ct, ti, action) 44173149Snyan struct ct_softc *ct; 44273149Snyan struct targ_info *ti; 44379697Snon int action; 44473149Snyan{ 44573149Snyan struct ct_targ_info *cti = (void *) ti; 44673149Snyan 44779697Snon if (action == SCSI_LOW_INFO_ALLOC || action == SCSI_LOW_INFO_REVOKE) 44873149Snyan { 44979697Snon if (ct->sc_sdp == NULL) 45079697Snon { 45179697Snon ct->sc_sdp = ct_make_synch_table(ct); 45279697Snon } 45379697Snon 45479697Snon switch (ct->sc_chiprev) 45579697Snon { 45679697Snon default: 45779697Snon ti->ti_maxsynch.offset = 5; 45879697Snon break; 45979697Snon 46079697Snon case CT_WD33C93_A: 46179697Snon case CT_AM33C93_A: 46279697Snon ti->ti_maxsynch.offset = 12; 46379697Snon break; 46479697Snon 46579697Snon case CT_WD33C93_B: 46679697Snon case CT_WD33C93_C: 46779697Snon ti->ti_maxsynch.offset = 12; 46879697Snon break; 46979697Snon } 47079697Snon 47179697Snon ti->ti_maxsynch.period = ct->sc_sdp[0].cs_period; 47279697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 47379697Snon cti->cti_syncreg = 0; 47473149Snyan } 47573149Snyan 47673149Snyan return 0; 47773149Snyan} 47873149Snyan 47973149Snyanstatic int 48073149Snyanct_world_start(ct, fdone) 48173149Snyan struct ct_softc *ct; 48273149Snyan int fdone; 48373149Snyan{ 48473149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 48579697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 48673149Snyan 48773149Snyan if (ct->sc_sdp == NULL) 48879697Snon { 48979697Snon ct->sc_sdp = ct_make_synch_table(ct); 49079697Snon } 49173149Snyan 49273149Snyan if (slp->sl_cfgflags & CFG_NOPARITY) 49373149Snyan ct->sc_creg = CR_DEFAULT; 49473149Snyan else 49573149Snyan ct->sc_creg = CR_DEFAULT_HP; 49673149Snyan 49773149Snyan if (ct->sc_dma & CT_DMA_DMASTART) 49873149Snyan (*ct->ct_dma_xfer_stop) (ct); 49973149Snyan if (ct->sc_dma & CT_DMA_PIOSTART) 50073149Snyan (*ct->ct_pio_xfer_stop) (ct); 50173149Snyan ct->sc_dma = 0; 50273149Snyan ct->sc_atten = 0; 50373149Snyan 50479697Snon cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); 50573149Snyan scsi_low_bus_reset(slp); 50679697Snon cthw_chip_reset(chp, NULL, ct->sc_chipclk, slp->sl_hostid); 50773149Snyan 50873149Snyan SOFT_INTR_REQUIRED(slp); 50973149Snyan return 0; 51073149Snyan} 51173149Snyan 51273149Snyanstatic int 51373149Snyanct_start_selection(ct, cb) 51473149Snyan struct ct_softc *ct; 51573149Snyan struct slccb *cb; 51673149Snyan{ 51773149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 51879697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 51979697Snon 52079697Snon struct targ_info *ti = slp->sl_Tnexus; 52179697Snon struct lun_info *li = slp->sl_Lnexus; 52279697Snon int s, satok; 52373149Snyan u_int8_t cmd; 52473149Snyan 52579697Snon ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 52673149Snyan ct->sc_atten = 0; 52779697Snon satok = 0; 52879697Snon 52979697Snon if (scsi_low_is_disconnect_ok(cb) != 0) 53079697Snon { 53179697Snon if (ct->sc_chiprev >= CT_WD33C93_A) 53279697Snon satok = 1; 53379697Snon else if (cthw_cmdlevel[slp->sl_scp.scp_cmd[0]] != 0) 53479697Snon satok = 1; 53579697Snon } 53679697Snon 53779697Snon if (satok != 0 && 53879697Snon scsi_low_is_msgout_continue(ti, SCSI_LOW_MSG_IDENTIFY) == 0) 53973149Snyan { 54079697Snon cmd = WD3S_SELECT_ATN_TFR; 54173149Snyan ct->sc_satgo = CT_SAT_GOING; 54273149Snyan } 54373149Snyan else 54473149Snyan { 54573149Snyan cmd = WD3S_SELECT_ATN; 54673149Snyan ct->sc_satgo = 0; 54773149Snyan } 54873149Snyan 54979697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) != 0) 55073149Snyan return SCSI_LOW_START_FAIL; 55173149Snyan 55273149Snyan if ((ct->sc_satgo & CT_SAT_GOING) != 0) 55379697Snon { 55479697Snon (void) scsi_low_msgout(slp, ti, SCSI_LOW_MSGOUT_INIT); 55579697Snon scsi_low_cmd(slp, ti); 55679697Snon ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); 55779697Snon ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 55879697Snon } 55979697Snon else 56079697Snon { 56179697Snon /* anyway attention assert */ 56279697Snon SCSI_LOW_ASSERT_ATN(slp); 56379697Snon } 56473149Snyan 56579697Snon ct_target_nexus_establish(ct, li->li_lun, slp->sl_scp.scp_direction); 56679697Snon 56773149Snyan s = splhigh(); 56879697Snon if ((ct_stat_read_1(chp) & (STR_BSY | STR_INT | STR_CIP)) == 0) 56973149Snyan { 57073149Snyan /* XXX: 57173149Snyan * Reload a lun again here. 57273149Snyan */ 57379697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 57479697Snon ct_cr_write_1(chp, wd3s_cmd, cmd); 57579697Snon if ((ct_stat_read_1(chp) & STR_LCI) == 0) 57673149Snyan { 57773149Snyan splx(s); 57873149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_SELSTART); 57973149Snyan return SCSI_LOW_START_OK; 58073149Snyan } 58173149Snyan } 58273149Snyan splx(s); 58373149Snyan return SCSI_LOW_START_FAIL; 58473149Snyan} 58573149Snyan 58673149Snyanstatic int 58773149Snyanct_msg(ct, ti, msg) 58873149Snyan struct ct_softc *ct; 58973149Snyan struct targ_info *ti; 59073149Snyan u_int msg; 59173149Snyan{ 59279697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 59373149Snyan struct ct_targ_info *cti = (void *) ti; 59473149Snyan struct ct_synch_data *csp = ct->sc_sdp; 59573149Snyan u_int offset, period; 59679697Snon int error; 59773149Snyan 59879697Snon if ((msg & SCSI_LOW_MSG_WIDE) != 0) 59979697Snon { 60079697Snon if (ti->ti_width != SCSI_LOW_BUS_WIDTH_8) 60179697Snon { 60279697Snon ti->ti_width = SCSI_LOW_BUS_WIDTH_8; 60379697Snon return EINVAL; 60479697Snon } 60573149Snyan return 0; 60679697Snon } 60773149Snyan 60879697Snon if ((msg & SCSI_LOW_MSG_SYNCH) == 0) 60979697Snon return 0; 61079697Snon 61173149Snyan offset = ti->ti_maxsynch.offset; 61273149Snyan period = ti->ti_maxsynch.period; 61373149Snyan for ( ; csp->cs_period != 0; csp ++) 61473149Snyan { 61573149Snyan if (period == csp->cs_period) 61673149Snyan break; 61773149Snyan } 61873149Snyan 61973149Snyan if (ti->ti_maxsynch.period != 0 && csp->cs_period == 0) 62073149Snyan { 62173149Snyan ti->ti_maxsynch.period = 0; 62273149Snyan ti->ti_maxsynch.offset = 0; 62373149Snyan cti->cti_syncreg = 0; 62479697Snon error = EINVAL; 62573149Snyan } 62679697Snon else 62779697Snon { 62879697Snon cti->cti_syncreg = ((offset & 0x0f) | csp->cs_syncr); 62979697Snon error = 0; 63079697Snon } 63173149Snyan 63273149Snyan if (ct->ct_synch_setup != 0) 63379697Snon (*ct->ct_synch_setup) (ct, ti); 63479697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 63579697Snon return error; 63673149Snyan} 63773149Snyan 63873149Snyan/************************************************* 63973149Snyan * <DATA PHASE> 64073149Snyan *************************************************/ 64173149Snyanstatic int 64279697Snonct_xfer(ct, data, len, direction, statp) 64373149Snyan struct ct_softc *ct; 64473149Snyan u_int8_t *data; 64573149Snyan int len, direction; 64679697Snon u_int *statp; 64773149Snyan{ 64879697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 64973149Snyan int wc; 65073149Snyan register u_int8_t aux; 65173149Snyan 65279697Snon *statp = 0; 65373149Snyan if (len == 1) 65473149Snyan { 65579697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_SBT | WD3S_TFR_INFO); 65673149Snyan } 65773149Snyan else 65873149Snyan { 65979697Snon cthw_set_count(chp, len); 66079697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_TFR_INFO); 66173149Snyan } 66273149Snyan 66379697Snon aux = ct_stat_read_1(chp); 66473149Snyan if ((aux & STR_LCI) != 0) 66573149Snyan { 66679697Snon cthw_set_count(chp, 0); 66773149Snyan return len; 66873149Snyan } 66973149Snyan 67079697Snon for (wc = 0; wc < ct->sc_tmaxcnt; wc ++) 67173149Snyan { 67273149Snyan /* check data ready */ 67373149Snyan if ((aux & (STR_BSY | STR_DBR)) == (STR_BSY | STR_DBR)) 67473149Snyan { 67573149Snyan if (direction == SCSI_LOW_READ) 67679697Snon { 67779697Snon *data = ct_cr_read_1(chp, wd3s_data); 67879697Snon if ((aux & STR_PE) != 0) 67979697Snon *statp |= SCSI_LOW_DATA_PE; 68079697Snon } 68173149Snyan else 68279697Snon { 68379697Snon ct_cr_write_1(chp, wd3s_data, *data); 68479697Snon } 68573149Snyan len --; 68673149Snyan if (len <= 0) 68773149Snyan break; 68873149Snyan data ++; 68973149Snyan } 69079697Snon else 69179697Snon { 69279697Snon SCSI_LOW_DELAY(1); 69379697Snon } 69473149Snyan 69573149Snyan /* check phase miss */ 69679697Snon aux = ct_stat_read_1(chp); 69773149Snyan if ((aux & STR_INT) != 0) 69873149Snyan break; 69973149Snyan } 70073149Snyan return len; 70173149Snyan} 70273149Snyan 70379697Snon#define CT_PADDING_BUF_SIZE 32 70479697Snon 70573149Snyanstatic void 70673149Snyanct_io_xfer(ct) 70773149Snyan struct ct_softc *ct; 70873149Snyan{ 70973149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 71079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 71173149Snyan struct sc_p *sp = &slp->sl_scp; 71279697Snon u_int stat; 71373149Snyan int len; 71479697Snon u_int8_t pbuf[CT_PADDING_BUF_SIZE]; 71573149Snyan 71679697Snon /* polling mode */ 71779697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg); 71873149Snyan 71973149Snyan if (sp->scp_datalen <= 0) 72073149Snyan { 72173149Snyan slp->sl_error |= PDMAERR; 72279697Snon 72379697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 72479697Snon SCSI_LOW_BZERO(pbuf, CT_PADDING_BUF_SIZE); 72579697Snon ct_xfer(ct, pbuf, CT_PADDING_BUF_SIZE, 72679697Snon sp->scp_direction, &stat); 72773149Snyan } 72873149Snyan else 72979697Snon { 73073149Snyan len = ct_xfer(ct, sp->scp_data, sp->scp_datalen, 73179697Snon sp->scp_direction, &stat); 73279697Snon sp->scp_data += (sp->scp_datalen - len); 73379697Snon sp->scp_datalen = len; 73479697Snon } 73573149Snyan} 73673149Snyan 73773149Snyan/************************************************** 73873149Snyan * <PHASE ERROR> 73973149Snyan **************************************************/ 74073149Snyanstruct ct_err { 74173149Snyan u_char *pe_msg; 74273149Snyan u_int pe_err; 74373149Snyan u_int pe_errmsg; 74473149Snyan int pe_done; 74573149Snyan}; 74673149Snyan 74773149Snyanstruct ct_err ct_cmderr[] = { 74873149Snyan/*0*/ { "illegal cmd", FATALIO, SCSI_LOW_MSG_ABORT, 1}, 74973149Snyan/*1*/ { "unexpected bus free", FATALIO, 0, 1}, 75073149Snyan/*2*/ { NULL, SELTIMEOUTIO, 0, 1}, 75173149Snyan/*3*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 75273149Snyan/*4*/ { "scsi bus parity error", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 75373149Snyan/*5*/ { "unknown" , FATALIO, SCSI_LOW_MSG_ABORT, 1}, 75473149Snyan/*6*/ { "miss reselection (target mode)", FATALIO, SCSI_LOW_MSG_ABORT, 0}, 75573149Snyan/*7*/ { "wrong status byte", PARITYERR, SCSI_LOW_MSG_ERROR, 0}, 75673149Snyan}; 75773149Snyan 75873149Snyanstatic void 75973149Snyanct_phase_error(ct, scsi_status) 76073149Snyan struct ct_softc *ct; 76173149Snyan u_int8_t scsi_status; 76273149Snyan{ 76373149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 76479697Snon struct targ_info *ti = slp->sl_Tnexus; 76573149Snyan struct ct_err *pep; 76673149Snyan u_int msg = 0; 76773149Snyan 76873149Snyan if ((scsi_status & BSR_CM) == BSR_CMDERR && 76973149Snyan (scsi_status & BSR_PHVALID) == 0) 77073149Snyan { 77173149Snyan pep = &ct_cmderr[scsi_status & BSR_PM]; 77273149Snyan slp->sl_error |= pep->pe_err; 77373149Snyan if ((pep->pe_err & PARITYERR) != 0) 77473149Snyan { 77573149Snyan if (ti->ti_phase == PH_MSGIN) 77673149Snyan msg = SCSI_LOW_MSG_PARITY; 77773149Snyan else 77873149Snyan msg = SCSI_LOW_MSG_ERROR; 77973149Snyan } 78073149Snyan else 78173149Snyan msg = pep->pe_errmsg; 78273149Snyan 78373149Snyan if (msg != 0) 78479697Snon scsi_low_assert_msg(slp, slp->sl_Tnexus, msg, 1); 78573149Snyan 78673149Snyan if (pep->pe_msg != NULL) 78773149Snyan { 78873149Snyan printf("%s: phase error: %s", 78973149Snyan slp->sl_xname, pep->pe_msg); 79079697Snon scsi_low_print(slp, slp->sl_Tnexus); 79173149Snyan } 79273149Snyan 79373149Snyan if (pep->pe_done != 0) 79473149Snyan scsi_low_disconnected(slp, ti); 79573149Snyan } 79673149Snyan else 79773149Snyan { 79873149Snyan slp->sl_error |= FATALIO; 79973149Snyan scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, "phase error"); 80073149Snyan } 80173149Snyan} 80273149Snyan 80373149Snyan/************************************************** 80473149Snyan * ### SCSI PHASE SEQUENCER ### 80573149Snyan **************************************************/ 80679697Snonstatic int 80779697Snonct_reselected(ct, scsi_status) 80873149Snyan struct ct_softc *ct; 80979697Snon u_int8_t scsi_status; 81073149Snyan{ 81173149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 81279697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 81373149Snyan struct targ_info *ti; 81473149Snyan u_int sid; 81579697Snon u_int8_t regv; 81673149Snyan 81773149Snyan ct->sc_atten = 0; 81879697Snon ct->sc_satgo &= ~CT_SAT_GOING; 81979697Snon regv = ct_cr_read_1(chp, wd3s_sid); 82079697Snon if ((regv & SIDR_VALID) == 0) 82179697Snon return EJUSTRETURN; 82279697Snon 82379697Snon sid = regv & SIDR_IDM; 82473149Snyan if ((ti = scsi_low_reselected(slp, sid)) == NULL) 82573149Snyan return EJUSTRETURN; 82673149Snyan 82779697Snon ct_target_nexus_establish(ct, 0, SCSI_LOW_READ); 82879697Snon if (scsi_status != BSR_AFM_RESEL) 82979697Snon return EJUSTRETURN; 83079697Snon 83179697Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 83279697Snon regv = ct_cr_read_1(chp, wd3s_data); 83379697Snon if (scsi_low_msgin(slp, ti, (u_int) regv) == 0) 83479697Snon { 83579697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0) 83679697Snon { 83779697Snon /* XXX: scsi_low_attetion */ 83879697Snon scsi_low_attention(slp); 83979697Snon } 84079697Snon } 84179697Snon 84279697Snon if (ct->sc_atten != 0) 84379697Snon { 84479697Snon ct_attention(ct); 84579697Snon } 84679697Snon 84779697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); 84873149Snyan return EJUSTRETURN; 84973149Snyan} 85073149Snyan 85173149Snyanstatic int 85279697Snonct_target_nexus_establish(ct, lun, dir) 85373149Snyan struct ct_softc *ct; 85479697Snon int lun, dir; 85573149Snyan{ 85679697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 85779697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 85879697Snon struct targ_info *ti = slp->sl_Tnexus; 85973149Snyan struct ct_targ_info *cti = (void *) ti; 86073149Snyan 86179697Snon if (dir == SCSI_LOW_WRITE) 86279697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id); 86373149Snyan else 86479697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); 86579697Snon ct_cr_write_1(chp, wd3s_lun, lun); 86679697Snon ct_cr_write_1(chp, wd3s_ctrl, ct->sc_creg | CR_DMA); 86779697Snon ct_cr_write_1(chp, wd3s_cph, 0); 86879697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 86979697Snon cthw_set_count(chp, 0); 87079697Snon return 0; 87179697Snon} 87273149Snyan 87379697Snonstatic int 87479697Snonct_lun_nexus_establish(ct) 87579697Snon struct ct_softc *ct; 87679697Snon{ 87779697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 87879697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 87979697Snon struct lun_info *li = slp->sl_Lnexus; 88079697Snon 88179697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 88273149Snyan return 0; 88373149Snyan} 88473149Snyan 88579697Snonstatic int 88679697Snonct_ccb_nexus_establish(ct) 88779697Snon struct ct_softc *ct; 88879697Snon{ 88979697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 89079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 89179697Snon struct lun_info *li = slp->sl_Lnexus; 89279697Snon struct targ_info *ti = slp->sl_Tnexus; 89379697Snon struct ct_targ_info *cti = (void *) ti; 89479697Snon struct slccb *cb = slp->sl_Qnexus; 89579697Snon 89679697Snon ct->sc_tmaxcnt = cb->ccb_tcmax * 1000 * 1000; 89779697Snon 89879697Snon if ((ct->sc_satgo & CT_SAT_GOING) != 0) 89979697Snon { 90079697Snon ct_cr_write_1(chp, wd3s_oid, slp->sl_scp.scp_cmdlen); 90179697Snon ct_write_cmds(chp, slp->sl_scp.scp_cmd, slp->sl_scp.scp_cmdlen); 90279697Snon } 90379697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_WRITE) 90479697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id); 90579697Snon else 90679697Snon ct_cr_write_1(chp, wd3s_did, ti->ti_id | DIDR_DPD); 90779697Snon ct_cr_write_1(chp, wd3s_lun, li->li_lun); 90879697Snon ct_cr_write_1(chp, wd3s_synch, cti->cti_syncreg); 90979697Snon return 0; 91079697Snon} 91179697Snon 91279697Snonstatic int 91379697Snonct_unbusy(ct) 91479697Snon struct ct_softc *ct; 91579697Snon{ 91679697Snon struct scsi_low_softc *slp = &ct->sc_sclow; 91779697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 91879697Snon int wc; 91979697Snon register u_int8_t regv; 92079697Snon 92179697Snon for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) 92279697Snon { 92379697Snon regv = ct_stat_read_1(chp); 92479697Snon if ((regv & (STR_BSY | STR_CIP)) == 0) 92579697Snon return 0; 92679697Snon if (regv == (u_int8_t) -1) 92779697Snon return EIO; 92879697Snon 92979697Snon SCSI_LOW_DELAY(CT_DELAY_INTERVAL); 93079697Snon } 93179697Snon 93279697Snon printf("%s: unbusy timeout\n", slp->sl_xname); 93379697Snon return EBUSY; 93479697Snon} 93579697Snon 93679697Snonstatic int 93779697Snonct_catch_intr(ct) 93879697Snon struct ct_softc *ct; 93979697Snon{ 94079697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 94179697Snon int wc; 94279697Snon register u_int8_t regv; 94379697Snon 94479697Snon for (wc = 0; wc < CT_DELAY_MAX / CT_DELAY_INTERVAL; wc ++) 94579697Snon { 94679697Snon regv = ct_stat_read_1(chp); 94779697Snon if ((regv & (STR_INT | STR_BSY | STR_CIP)) == STR_INT) 94879697Snon return 0; 94979697Snon 95079697Snon SCSI_LOW_DELAY(CT_DELAY_INTERVAL); 95179697Snon } 95279697Snon return EJUSTRETURN; 95379697Snon} 95479697Snon 95573149Snyanint 95673149Snyanctintr(arg) 95773149Snyan void *arg; 95873149Snyan{ 95973149Snyan struct ct_softc *ct = arg; 96073149Snyan struct scsi_low_softc *slp = &ct->sc_sclow; 96179697Snon struct ct_bus_access_handle *chp = &ct->sc_ch; 96273149Snyan struct targ_info *ti; 96373149Snyan struct physio_proc *pp; 96473149Snyan struct buf *bp; 96579697Snon u_int derror, flags; 96679697Snon int len, satgo, error; 96773149Snyan u_int8_t scsi_status, regv; 96873149Snyan 96979697Snonagain: 97073149Snyan if (slp->sl_flags & HW_INACTIVE) 97173149Snyan return 0; 97273149Snyan 97373149Snyan /************************************************** 97473149Snyan * Get status & bus phase 97573149Snyan **************************************************/ 97679697Snon if ((ct_stat_read_1(chp) & STR_INT) == 0) 97773149Snyan return 0; 97873149Snyan 97979697Snon scsi_status = ct_cr_read_1(chp, wd3s_stat); 98073149Snyan if (scsi_status == ((u_int8_t) -1)) 98173149Snyan return 1; 98273149Snyan 98373149Snyan /************************************************** 98473149Snyan * Check reselection, or nexus 98573149Snyan **************************************************/ 98679697Snon if (scsi_status == BSR_RESEL || scsi_status == BSR_AFM_RESEL) 98773149Snyan { 98879697Snon if (ct_reselected(ct, scsi_status) == EJUSTRETURN) 98973149Snyan return 1; 99073149Snyan } 99173149Snyan 99279697Snon if ((ti = slp->sl_Tnexus) == NULL) 99373149Snyan return 1; 99473149Snyan 99573149Snyan /************************************************** 99673149Snyan * Debug section 99773149Snyan **************************************************/ 99873149Snyan#ifdef CT_DEBUG 99973149Snyan if (ct_debug > 0) 100073149Snyan { 100173149Snyan scsi_low_print(slp, NULL); 100273149Snyan printf("%s: scsi_status 0x%x\n\n", slp->sl_xname, 100373149Snyan (u_int) scsi_status); 100479697Snon#ifdef DDB 100573149Snyan if (ct_debug > 1) 100679697Snon SCSI_LOW_DEBUGGER("ct"); 100779697Snon#endif /* DDB */ 100873149Snyan } 100973149Snyan#endif /* CT_DEBUG */ 101073149Snyan 101173149Snyan /************************************************** 101273149Snyan * Internal scsi phase 101373149Snyan **************************************************/ 101473149Snyan satgo = ct->sc_satgo; 101579697Snon ct->sc_satgo &= ~CT_SAT_GOING; 101673149Snyan 101773149Snyan switch (ti->ti_phase) 101873149Snyan { 101973149Snyan case PH_SELSTART: 102073149Snyan if ((satgo & CT_SAT_GOING) == 0) 102173149Snyan { 102273149Snyan if (scsi_status != BSR_SELECTED) 102373149Snyan { 102473149Snyan ct_phase_error(ct, scsi_status); 102573149Snyan return 1; 102673149Snyan } 102779697Snon scsi_low_arbit_win(slp); 102873149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_SELECTED); 102973149Snyan return 1; 103073149Snyan } 103173149Snyan else 103273149Snyan { 103379697Snon scsi_low_arbit_win(slp); 103479697Snon SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); /* XXX */ 103573149Snyan } 103673149Snyan break; 103773149Snyan 103873149Snyan case PH_RESEL: 103973149Snyan if ((scsi_status & BSR_PHVALID) == 0 || 104073149Snyan (scsi_status & BSR_PM) != BSR_MSGIN) 104173149Snyan { 104273149Snyan scsi_low_restart(slp, SCSI_LOW_RESTART_HARD, 104373149Snyan "phase miss after reselect"); 104473149Snyan return 1; 104573149Snyan } 104673149Snyan break; 104773149Snyan 104873149Snyan default: 104973149Snyan if (slp->sl_flags & HW_PDMASTART) 105073149Snyan { 105173149Snyan slp->sl_flags &= ~HW_PDMASTART; 105273149Snyan if (ct->sc_dma & CT_DMA_DMASTART) 105373149Snyan { 105473149Snyan (*ct->ct_dma_xfer_stop) (ct); 105573149Snyan ct->sc_dma &= ~CT_DMA_DMASTART; 105673149Snyan } 105779697Snon else if (ct->sc_dma & CT_DMA_PIOSTART) 105873149Snyan { 105973149Snyan (*ct->ct_pio_xfer_stop) (ct); 106073149Snyan ct->sc_dma &= ~CT_DMA_PIOSTART; 106173149Snyan } 106279697Snon else 106379697Snon { 106479697Snon scsi_low_data_finish(slp); 106579697Snon } 106673149Snyan } 106773149Snyan break; 106873149Snyan } 106973149Snyan 107073149Snyan /************************************************** 107173149Snyan * parse scsi phase 107273149Snyan **************************************************/ 107373149Snyan if (scsi_status & BSR_PHVALID) 107473149Snyan { 107573149Snyan /************************************************** 107673149Snyan * Normal SCSI phase. 107773149Snyan **************************************************/ 107873149Snyan if ((scsi_status & BSR_CM) == BSR_CMDABT) 107973149Snyan { 108073149Snyan ct_phase_error(ct, scsi_status); 108173149Snyan return 1; 108273149Snyan } 108373149Snyan 108473149Snyan switch (scsi_status & BSR_PM) 108573149Snyan { 108673149Snyan case BSR_DATAOUT: 108773149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 108873149Snyan if (scsi_low_data(slp, ti, &bp, SCSI_LOW_WRITE) != 0) 108979697Snon { 109079697Snon ct_attention(ct); 109179697Snon } 109273149Snyan goto common_data_phase; 109373149Snyan 109473149Snyan case BSR_DATAIN: 109573149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_DATA); 109673149Snyan if (scsi_low_data(slp, ti, &bp, SCSI_LOW_READ) != 0) 109779697Snon { 109879697Snon ct_attention(ct); 109979697Snon } 110073149Snyan 110173149Snyancommon_data_phase: 110279697Snon if (slp->sl_scp.scp_datalen > 0) 110373149Snyan { 110479697Snon slp->sl_flags |= HW_PDMASTART; 110579697Snon if ((ct->sc_xmode & CT_XMODE_PIO) != 0) 110679697Snon { 110779697Snon pp = physio_proc_enter(bp); 110879697Snon error = (*ct->ct_pio_xfer_start) (ct); 110979697Snon physio_proc_leave(pp); 111079697Snon if (error == 0) 111179697Snon { 111279697Snon ct->sc_dma |= CT_DMA_PIOSTART; 111379697Snon return 1; 111479697Snon } 111579697Snon } 111673149Snyan 111779697Snon if ((ct->sc_xmode & CT_XMODE_DMA) != 0) 111879697Snon { 111979697Snon error = (*ct->ct_dma_xfer_start) (ct); 112079697Snon if (error == 0) 112179697Snon { 112279697Snon ct->sc_dma |= CT_DMA_DMASTART; 112379697Snon return 1; 112479697Snon } 112579697Snon } 112673149Snyan } 112773149Snyan else 112879697Snon { 112979697Snon if (slp->sl_scp.scp_direction == SCSI_LOW_READ) 113079697Snon { 113179697Snon if (!(slp->sl_flags & HW_READ_PADDING)) 113279697Snon { 113379697Snon printf("%s: read padding required\n", slp->sl_xname); 113479697Snon return 1; 113579697Snon } 113679697Snon } 113779697Snon else 113879697Snon { 113979697Snon if (!(slp->sl_flags & HW_WRITE_PADDING)) 114079697Snon { 114179697Snon printf("%s: write padding required\n", slp->sl_xname); 114279697Snon return 1; 114379697Snon } 114479697Snon } 114579697Snon slp->sl_flags |= HW_PDMASTART; 114673149Snyan } 114779697Snon 114879697Snon ct_io_xfer(ct); 114973149Snyan return 1; 115073149Snyan 115173149Snyan case BSR_CMDOUT: 115273149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_CMD); 115373149Snyan if (scsi_low_cmd(slp, ti) != 0) 115479697Snon { 115579697Snon ct_attention(ct); 115679697Snon } 115773149Snyan 115879697Snon if (ct_xfer(ct, slp->sl_scp.scp_cmd, 115973149Snyan slp->sl_scp.scp_cmdlen, 116079697Snon SCSI_LOW_WRITE, &derror) != 0) 116173149Snyan { 116273149Snyan printf("%s: scsi cmd xfer short\n", 116373149Snyan slp->sl_xname); 116473149Snyan } 116573149Snyan return 1; 116673149Snyan 116773149Snyan case BSR_STATIN: 116873149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 116979697Snon if ((ct_io_control & CT_USE_CCSEQ) != 0) 117073149Snyan { 117179697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0 || 117279697Snon ct->sc_atten != 0) 117379697Snon { 117479697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, 117579697Snon &derror); 117679697Snon scsi_low_statusin(slp, ti, 117779697Snon regv | derror); 117879697Snon } 117979697Snon else 118079697Snon { 118179697Snon ct->sc_satgo |= CT_SAT_GOING; 118279697Snon cthw_set_count(chp, 0); 118379697Snon cthw_phase_bypass(ct, 0x41); 118479697Snon } 118573149Snyan } 118673149Snyan else 118773149Snyan { 118879697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); 118979697Snon scsi_low_statusin(slp, ti, regv | derror); 119073149Snyan } 119173149Snyan return 1; 119273149Snyan 119373149Snyan case BSR_UNSPINFO0: 119473149Snyan case BSR_UNSPINFO1: 119573149Snyan printf("%s: illegal bus phase (0x%x)\n", slp->sl_xname, 119673149Snyan (u_int) scsi_status); 119773149Snyan scsi_low_print(slp, ti); 119873149Snyan return 1; 119973149Snyan 120073149Snyan case BSR_MSGOUT: 120173149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGOUT); 120279697Snon flags = SCSI_LOW_MSGOUT_UNIFY; 120379697Snon if (ti->ti_ophase != ti->ti_phase) 120479697Snon flags |= SCSI_LOW_MSGOUT_INIT; 120579697Snon len = scsi_low_msgout(slp, ti, flags); 120679697Snon 120779697Snon if (len > 1 && slp->sl_atten == 0) 120873149Snyan { 120979697Snon ct_attention(ct); 121079697Snon } 121179697Snon 121279697Snon if (ct_xfer(ct, ti->ti_msgoutstr, len, 121379697Snon SCSI_LOW_WRITE, &derror) != 0) 121479697Snon { 121573149Snyan printf("%s: scsi msgout xfer short\n", 121673149Snyan slp->sl_xname); 121773149Snyan } 121879697Snon SCSI_LOW_DEASSERT_ATN(slp); 121979697Snon ct->sc_atten = 0; 122073149Snyan return 1; 122173149Snyan 122273149Snyan case BSR_MSGIN:/* msg in */ 122373149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 122479697Snon 122579697Snon ct_xfer(ct, ®v, 1, SCSI_LOW_READ, &derror); 122679697Snon if (scsi_low_msgin(slp, ti, regv | derror) == 0) 122779697Snon { 122879697Snon if (scsi_low_is_msgout_continue(ti, 0) != 0) 122979697Snon { 123079697Snon /* XXX: scsi_low_attetion */ 123179697Snon scsi_low_attention(slp); 123279697Snon } 123379697Snon } 123479697Snon 123579697Snon if ((ct_io_control & CT_FAST_INTR) != 0) 123679697Snon { 123779697Snon if (ct_catch_intr(ct) == 0) 123879697Snon goto again; 123979697Snon } 124073149Snyan return 1; 124173149Snyan } 124273149Snyan } 124373149Snyan else 124473149Snyan { 124573149Snyan /************************************************** 124673149Snyan * Special SCSI phase 124773149Snyan **************************************************/ 124873149Snyan switch (scsi_status) 124973149Snyan { 125073149Snyan case BSR_SATSDP: /* SAT with save data pointer */ 125173149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 125279697Snon ct->sc_satgo |= CT_SAT_GOING; 125373149Snyan scsi_low_msgin(slp, ti, MSG_SAVESP); 125473149Snyan cthw_phase_bypass(ct, 0x41); 125573149Snyan return 1; 125673149Snyan 125773149Snyan case BSR_SATFIN: /* SAT COMPLETE */ 125873149Snyan /* 125973149Snyan * emulate statusin => msgin 126073149Snyan */ 126179697Snon SCSI_LOW_SETUP_PHASE(ti, PH_STAT); 126279697Snon scsi_low_statusin(slp, ti, ct_cr_read_1(chp, wd3s_lun)); 126379697Snon 126473149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 126579697Snon scsi_low_msgin(slp, ti, MSG_COMP); 126679697Snon 126773149Snyan scsi_low_disconnected(slp, ti); 126873149Snyan return 1; 126973149Snyan 127073149Snyan case BSR_ACKREQ: /* negate ACK */ 127173149Snyan if (ct->sc_atten != 0) 127279697Snon { 127379697Snon ct_attention(ct); 127479697Snon } 127573149Snyan 127679697Snon ct_cr_write_1(chp, wd3s_cmd, WD3S_NEGATE_ACK); 127779697Snon if ((ct_io_control & CT_FAST_INTR) != 0) 127879697Snon { 127979697Snon /* XXX: 128079697Snon * Should clear a pending interrupt and 128179697Snon * sync with a next interrupt! 128279697Snon */ 128379697Snon ct_catch_intr(ct); 128479697Snon } 128573149Snyan return 1; 128673149Snyan 128773149Snyan case BSR_DISC: /* disconnect */ 128873149Snyan if (slp->sl_msgphase == MSGPH_NULL && 128973149Snyan (satgo & CT_SAT_GOING) != 0) 129073149Snyan { 129173149Snyan /* 129273149Snyan * emulate disconnect msg 129373149Snyan */ 129473149Snyan SCSI_LOW_SETUP_PHASE(ti, PH_MSGIN); 129579697Snon scsi_low_msgin(slp, ti, MSG_DISCON); 129673149Snyan } 129773149Snyan scsi_low_disconnected(slp, ti); 129873149Snyan return 1; 129973149Snyan 130073149Snyan default: 130173149Snyan break; 130273149Snyan } 130373149Snyan } 130473149Snyan 130573149Snyan ct_phase_error(ct, scsi_status); 130673149Snyan return 1; 130773149Snyan} 1308