ncr53c9x.c revision 145386
1130293Sscottl/*- 2130293Sscottl * Copyright (c) 2004 Scott Long 3130293Sscottl * All rights reserved. 4130293Sscottl * 5130293Sscottl * Redistribution and use in source and binary forms, with or without 6130293Sscottl * modification, are permitted provided that the following conditions 7130293Sscottl * are met: 8130293Sscottl * 1. Redistributions of source code must retain the above copyright 9130293Sscottl * notice, this list of conditions and the following disclaimer. 10130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 11130293Sscottl * notice, this list of conditions and the following disclaimer in the 12130293Sscottl * documentation and/or other materials provided with the distribution. 13130293Sscottl * 14130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130293Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130293Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130293Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18130293Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130293Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130293Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130293Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130293Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130293Sscottl * SUCH DAMAGE. 25130293Sscottl * 26130293Sscottl */ 27130293Sscottl 28145202Smarius/* $NetBSD: ncr53c9x.c,v 1.110 2003/11/02 11:07:45 wiz Exp $ */ 29130293Sscottl 30130293Sscottl/*- 31130293Sscottl * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. 32130293Sscottl * All rights reserved. 33130293Sscottl * 34130293Sscottl * This code is derived from software contributed to The NetBSD Foundation 35130293Sscottl * by Charles M. Hannum. 36130293Sscottl * 37130293Sscottl * Redistribution and use in source and binary forms, with or without 38130293Sscottl * modification, are permitted provided that the following conditions 39130293Sscottl * are met: 40130293Sscottl * 1. Redistributions of source code must retain the above copyright 41130293Sscottl * notice, this list of conditions and the following disclaimer. 42130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 43130293Sscottl * notice, this list of conditions and the following disclaimer in the 44130293Sscottl * documentation and/or other materials provided with the distribution. 45130293Sscottl * 3. All advertising materials mentioning features or use of this software 46130293Sscottl * must display the following acknowledgement: 47130293Sscottl * This product includes software developed by the NetBSD 48130293Sscottl * Foundation, Inc. and its contributors. 49130293Sscottl * 4. Neither the name of The NetBSD Foundation nor the names of its 50130293Sscottl * contributors may be used to endorse or promote products derived 51130293Sscottl * from this software without specific prior written permission. 52130293Sscottl * 53130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 54130293Sscottl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55130293Sscottl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56130293Sscottl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 57130293Sscottl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 58130293Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 59130293Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 60130293Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 61130293Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 62130293Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 63130293Sscottl * POSSIBILITY OF SUCH DAMAGE. 64130293Sscottl */ 65130293Sscottl 66139749Simp/*- 67130293Sscottl * Copyright (c) 1994 Peter Galbavy 68130293Sscottl * Copyright (c) 1995 Paul Kranenburg 69130293Sscottl * All rights reserved. 70130293Sscottl * 71130293Sscottl * Redistribution and use in source and binary forms, with or without 72130293Sscottl * modification, are permitted provided that the following conditions 73130293Sscottl * are met: 74130293Sscottl * 1. Redistributions of source code must retain the above copyright 75130293Sscottl * notice, this list of conditions and the following disclaimer. 76130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 77130293Sscottl * notice, this list of conditions and the following disclaimer in the 78130293Sscottl * documentation and/or other materials provided with the distribution. 79130293Sscottl * 3. All advertising materials mentioning features or use of this software 80130293Sscottl * must display the following acknowledgement: 81130293Sscottl * This product includes software developed by Peter Galbavy 82130293Sscottl * 4. The name of the author may not be used to endorse or promote products 83130293Sscottl * derived from this software without specific prior written permission. 84130293Sscottl * 85130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 86130293Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 87130293Sscottl * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 88130293Sscottl * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 89130293Sscottl * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 90130293Sscottl * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 91130293Sscottl * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 92130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 93130293Sscottl * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 94130293Sscottl * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 95130293Sscottl * POSSIBILITY OF SUCH DAMAGE. 96130293Sscottl */ 97130293Sscottl 98130293Sscottl/* 99130293Sscottl * Based on aic6360 by Jarle Greipsland 100130293Sscottl * 101130293Sscottl * Acknowledgements: Many of the algorithms used in this driver are 102133039Strhodes * inspired by the work of Julian Elischer (julian@FreeBSD.org) and 103130293Sscottl * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million! 104130293Sscottl */ 105130293Sscottl 106130293Sscottl#include <sys/cdefs.h> 107130293Sscottl__FBSDID("$FreeBSD: head/sys/dev/esp/ncr53c9x.c 145386 2005-04-22 03:37:10Z scottl $"); 108130293Sscottl 109130293Sscottl#include <sys/param.h> 110130293Sscottl#include <sys/systm.h> 111130293Sscottl#include <sys/bus.h> 112130293Sscottl#include <sys/kernel.h> 113130293Sscottl#include <sys/malloc.h> 114130293Sscottl#include <sys/resource.h> 115130293Sscottl#include <sys/lock.h> 116130293Sscottl#include <sys/mutex.h> 117130293Sscottl#include <sys/queue.h> 118130293Sscottl#include <sys/time.h> 119130293Sscottl#include <sys/callout.h> 120130293Sscottl 121130293Sscottl#include <cam/cam.h> 122130293Sscottl#include <cam/cam_ccb.h> 123130293Sscottl#include <cam/cam_debug.h> 124130293Sscottl#include <cam/cam_sim.h> 125130293Sscottl#include <cam/cam_xpt_sim.h> 126130293Sscottl#include <cam/scsi/scsi_all.h> 127130293Sscottl#include <cam/scsi/scsi_message.h> 128130293Sscottl 129130293Sscottl#include <dev/esp/ncr53c9xreg.h> 130130293Sscottl#include <dev/esp/ncr53c9xvar.h> 131130293Sscottl 132130293Sscottlint ncr53c9x_debug = NCR_SHOWMISC /*|NCR_SHOWPHASE|NCR_SHOWTRAC|NCR_SHOWCMDS*/; 133130293Sscottl#ifdef DEBUG 134130293Sscottlint ncr53c9x_notag = 0; 135130293Sscottl#endif 136130293Sscottl 137130293Sscottlstatic void ncr53c9x_select(struct ncr53c9x_softc *, struct ncr53c9x_ecb *); 138130293Sscottlstatic int ncr53c9x_reselect(struct ncr53c9x_softc *, int, int, int); 139130293Sscottlstatic void ncr53c9x_scsi_reset(struct ncr53c9x_softc *); 140130293Sscottlstatic void ncr53c9x_poll(struct cam_sim *); 141130293Sscottlstatic void ncr53c9x_sched(struct ncr53c9x_softc *); 142130293Sscottlstatic void ncr53c9x_done(struct ncr53c9x_softc *, struct ncr53c9x_ecb *); 143130293Sscottlstatic void ncr53c9x_msgin(struct ncr53c9x_softc *); 144130293Sscottlstatic void ncr53c9x_msgout(struct ncr53c9x_softc *); 145130293Sscottlstatic void ncr53c9x_timeout(void *arg); 146130293Sscottlstatic void ncr53c9x_watch(void *arg); 147130293Sscottlstatic void ncr53c9x_abort(struct ncr53c9x_softc *, struct ncr53c9x_ecb *); 148130293Sscottlstatic void ncr53c9x_dequeue(struct ncr53c9x_softc *, 149130293Sscottl struct ncr53c9x_ecb *); 150130293Sscottlstatic void ncr53c9x_sense(struct ncr53c9x_softc *, struct ncr53c9x_ecb *); 151130293Sscottlstatic void ncr53c9x_free_ecb(struct ncr53c9x_softc *, 152130293Sscottl struct ncr53c9x_ecb *); 153130293Sscottlstatic void ncr53c9x_wrfifo(struct ncr53c9x_softc *, u_char *, int); 154130293Sscottlstatic int ncr53c9x_rdfifo(struct ncr53c9x_softc *, int); 155130293Sscottl 156130293Sscottlstatic struct ncr53c9x_ecb *ncr53c9x_get_ecb(struct ncr53c9x_softc *); 157130293Sscottlstatic struct ncr53c9x_linfo *ncr53c9x_lunsearch(struct ncr53c9x_tinfo *, 158130293Sscottl int64_t lun); 159130293Sscottl 160130293Sscottlstatic __inline void ncr53c9x_readregs(struct ncr53c9x_softc *); 161130293Sscottlstatic __inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *, int); 162130293Sscottlstatic __inline void ncr53c9x_setsync(struct ncr53c9x_softc *, 163130293Sscottl struct ncr53c9x_tinfo *); 164130293Sscottl 165130293Sscottl#define NCR_RDFIFO_START 0 166130293Sscottl#define NCR_RDFIFO_CONTINUE 1 167130293Sscottl 168130293Sscottl#define NCR_SET_COUNT(sc, size) do { \ 169130293Sscottl NCR_WRITE_REG((sc), NCR_TCL, (size)); \ 170130293Sscottl NCR_WRITE_REG((sc), NCR_TCM, (size) >> 8); \ 171130293Sscottl if ((sc->sc_cfg2 & NCRCFG2_FE) || \ 172130293Sscottl (sc->sc_rev == NCR_VARIANT_FAS366)) { \ 173130293Sscottl NCR_WRITE_REG((sc), NCR_TCH, (size) >> 16); \ 174130293Sscottl } \ 175130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { \ 176130293Sscottl NCR_WRITE_REG(sc, NCR_RCH, 0); \ 177130293Sscottl } \ 178130293Sscottl} while (0) 179130293Sscottl 180130293Sscottl#ifndef mstohz 181130293Sscottl#define mstohz(ms) \ 182130293Sscottl (((ms) < 0x20000) ? \ 183130293Sscottl ((ms +0u) / 1000u) * hz : \ 184130293Sscottl ((ms +0u) * hz) /1000u) 185130293Sscottl#endif 186130293Sscottl 187130293Sscottl/* 188145202Smarius * Names for the NCR53c9x variants, corresponding to the variant tags 189130293Sscottl * in ncr53c9xvar.h. 190130293Sscottl */ 191130293Sscottlstatic const char *ncr53c9x_variant_names[] = { 192130293Sscottl "ESP100", 193130293Sscottl "ESP100A", 194130293Sscottl "ESP200", 195130293Sscottl "NCR53C94", 196130293Sscottl "NCR53C96", 197130293Sscottl "ESP406", 198130293Sscottl "FAS408", 199130293Sscottl "FAS216", 200130293Sscottl "AM53C974", 201130293Sscottl "FAS366/HME", 202130293Sscottl "NCR53C90 (86C01)", 203130293Sscottl}; 204130293Sscottl 205130293Sscottl/* 206130293Sscottl * Search linked list for LUN info by LUN id. 207130293Sscottl */ 208130293Sscottlstatic struct ncr53c9x_linfo * 209130293Sscottlncr53c9x_lunsearch(struct ncr53c9x_tinfo *ti, int64_t lun) 210130293Sscottl{ 211130293Sscottl struct ncr53c9x_linfo *li; 212130293Sscottl LIST_FOREACH(li, &ti->luns, link) 213130293Sscottl if (li->lun == lun) 214130293Sscottl return (li); 215130293Sscottl return (NULL); 216130293Sscottl} 217130293Sscottl 218130293Sscottl/* 219133039Strhodes * Attach this instance, and then all the sub-devices. 220130293Sscottl */ 221130293Sscottlint 222130293Sscottlncr53c9x_attach(struct ncr53c9x_softc *sc) 223130293Sscottl{ 224130293Sscottl struct cam_devq *devq; 225130293Sscottl struct cam_sim *sim; 226130293Sscottl struct cam_path *path; 227130406Sscottl struct ncr53c9x_ecb *ecb; 228130406Sscottl int i; 229130293Sscottl 230130293Sscottl mtx_init(&sc->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF); 231130293Sscottl 232130293Sscottl /* 233130293Sscottl * Note, the front-end has set us up to print the chip variation. 234130293Sscottl */ 235130293Sscottl if (sc->sc_rev >= NCR_VARIANT_MAX) { 236130293Sscottl device_printf(sc->sc_dev, "unknown variant %d, devices not " 237130293Sscottl "attached\n", sc->sc_rev); 238130293Sscottl return (EINVAL); 239130293Sscottl } 240130293Sscottl 241130293Sscottl device_printf(sc->sc_dev, "%s, %dMHz, SCSI ID %d\n", 242130293Sscottl ncr53c9x_variant_names[sc->sc_rev], sc->sc_freq, sc->sc_id); 243130293Sscottl 244130293Sscottl sc->sc_ntarg = (sc->sc_rev == NCR_VARIANT_FAS366) ? 16 : 8; 245130293Sscottl 246130293Sscottl /* 247130293Sscottl * Allocate SCSI message buffers. 248130293Sscottl * Front-ends can override allocation to avoid alignment 249130293Sscottl * handling in the DMA engines. Note that that ncr53c9x_msgout() 250130293Sscottl * can request a 1 byte DMA transfer. 251130293Sscottl */ 252130293Sscottl if (sc->sc_omess == NULL) 253130293Sscottl sc->sc_omess = malloc(NCR_MAX_MSG_LEN, M_DEVBUF, M_NOWAIT); 254130293Sscottl 255130293Sscottl if (sc->sc_imess == NULL) 256130293Sscottl sc->sc_imess = malloc(NCR_MAX_MSG_LEN + 1, M_DEVBUF, M_NOWAIT); 257130293Sscottl 258130293Sscottl sc->sc_tinfo = malloc(sc->sc_ntarg * sizeof(sc->sc_tinfo[0]), 259130293Sscottl M_DEVBUF, M_NOWAIT | M_ZERO); 260130293Sscottl 261130293Sscottl if (!sc->sc_omess || !sc->sc_imess || !sc->sc_tinfo) { 262130293Sscottl printf("out of memory\n"); 263130293Sscottl return (ENOMEM); 264130293Sscottl } 265130293Sscottl 266130293Sscottl callout_init(&sc->sc_watchdog, 0); 267130293Sscottl 268130293Sscottl /* 269130293Sscottl * Treat NCR53C90 with the 86C01 DMA chip exactly as ESP100 270130293Sscottl * from now on. 271130293Sscottl */ 272130293Sscottl if (sc->sc_rev == NCR_VARIANT_NCR53C90_86C01) 273130293Sscottl sc->sc_rev = NCR_VARIANT_ESP100; 274130293Sscottl 275130293Sscottl sc->sc_ccf = FREQTOCCF(sc->sc_freq); 276130293Sscottl 277130293Sscottl /* The value *must not* be == 1. Make it 2 */ 278130293Sscottl if (sc->sc_ccf == 1) 279130293Sscottl sc->sc_ccf = 2; 280130293Sscottl 281130293Sscottl /* 282130293Sscottl * The recommended timeout is 250ms. This register is loaded 283130293Sscottl * with a value calculated as follows, from the docs: 284130293Sscottl * 285130293Sscottl * (timout period) x (CLK frequency) 286130293Sscottl * reg = ------------------------------------- 287130293Sscottl * 8192 x (Clock Conversion Factor) 288130293Sscottl * 289130293Sscottl * Since CCF has a linear relation to CLK, this generally computes 290130293Sscottl * to the constant of 153. 291130293Sscottl */ 292130293Sscottl sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf); 293130293Sscottl 294130293Sscottl /* CCF register only has 3 bits; 0 is actually 8 */ 295130293Sscottl sc->sc_ccf &= 7; 296130293Sscottl 297130293Sscottl /* 298130293Sscottl * Register with CAM 299130293Sscottl */ 300130293Sscottl devq = cam_simq_alloc(sc->sc_ntarg); 301130293Sscottl if (devq == NULL) 302130293Sscottl return (ENOMEM); 303130293Sscottl 304130293Sscottl sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc, 305130406Sscottl device_get_unit(sc->sc_dev), 1, 306130406Sscottl NCR_TAG_DEPTH, devq); 307130293Sscottl if (sim == NULL) { 308130293Sscottl cam_simq_free(devq); 309130293Sscottl return (ENOMEM); 310130293Sscottl } 311130293Sscottl if (xpt_bus_register(sim, 0) != CAM_SUCCESS) { 312130293Sscottl cam_sim_free(sim, TRUE); 313130293Sscottl return (EIO); 314130293Sscottl } 315130293Sscottl 316130293Sscottl if (xpt_create_path(&path, NULL, cam_sim_path(sim), 317130293Sscottl CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) 318130293Sscottl != CAM_REQ_CMP) { 319130293Sscottl xpt_bus_deregister(cam_sim_path(sim)); 320130293Sscottl cam_sim_free(sim, TRUE); 321130293Sscottl return (EIO); 322130293Sscottl } 323130293Sscottl 324130293Sscottl sc->sc_sim = sim; 325130293Sscottl sc->sc_path = path; 326130293Sscottl 327130293Sscottl /* Reset state & bus */ 328130293Sscottl#if 0 329130293Sscottl sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; 330130293Sscottl#endif 331130293Sscottl sc->sc_state = 0; 332130293Sscottl ncr53c9x_init(sc, 1); 333130293Sscottl 334130406Sscottl TAILQ_INIT(&sc->free_list); 335130406Sscottl if ((sc->ecb_array = malloc(sizeof(struct ncr53c9x_ecb) * NCR_TAG_DEPTH, 336130406Sscottl M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { 337145202Smarius device_printf(sc->sc_dev, "cannot allocate ECB array\n"); 338130406Sscottl return (ENOMEM); 339130406Sscottl } 340130406Sscottl for (i = 0; i < NCR_TAG_DEPTH; i++) { 341130406Sscottl ecb = &sc->ecb_array[i]; 342130406Sscottl ecb->sc = sc; 343130406Sscottl ecb->tag_id = i; 344130406Sscottl TAILQ_INSERT_HEAD(&sc->free_list, ecb, free_links); 345130406Sscottl } 346130406Sscottl 347130293Sscottl callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc); 348130293Sscottl 349130293Sscottl return (0); 350130293Sscottl} 351130293Sscottl 352130293Sscottlint 353130293Sscottlncr53c9x_detach(struct ncr53c9x_softc *sc, int flags) 354130293Sscottl{ 355130293Sscottl 356130293Sscottl#if 0 /* don't allow detach for now */ 357130293Sscottl free(sc->sc_imess, M_DEVBUF); 358130293Sscottl free(sc->sc_omess, M_DEVBUF); 359130293Sscottl#endif 360130293Sscottl 361130293Sscottl return (EINVAL); 362130293Sscottl} 363130293Sscottl 364130293Sscottl/* 365130293Sscottl * This is the generic ncr53c9x reset function. It does not reset the SCSI bus, 366130293Sscottl * only this controller, but kills any on-going commands, and also stops 367130293Sscottl * and resets the DMA. 368130293Sscottl * 369130293Sscottl * After reset, registers are loaded with the defaults from the attach 370130293Sscottl * routine above. 371130293Sscottl */ 372130293Sscottlvoid 373130293Sscottlncr53c9x_reset(struct ncr53c9x_softc *sc) 374130293Sscottl{ 375130293Sscottl 376130293Sscottl /* reset DMA first */ 377130293Sscottl NCRDMA_RESET(sc); 378130293Sscottl 379130293Sscottl /* reset SCSI chip */ 380130293Sscottl NCRCMD(sc, NCRCMD_RSTCHIP); 381130293Sscottl NCRCMD(sc, NCRCMD_NOP); 382130293Sscottl DELAY(500); 383130293Sscottl 384130293Sscottl /* do these backwards, and fall through */ 385130293Sscottl switch (sc->sc_rev) { 386130293Sscottl case NCR_VARIANT_ESP406: 387130293Sscottl case NCR_VARIANT_FAS408: 388130293Sscottl NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT); 389130293Sscottl NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4); 390130293Sscottl case NCR_VARIANT_AM53C974: 391130293Sscottl case NCR_VARIANT_FAS216: 392130293Sscottl case NCR_VARIANT_NCR53C94: 393130293Sscottl case NCR_VARIANT_NCR53C96: 394130293Sscottl case NCR_VARIANT_ESP200: 395130293Sscottl sc->sc_features |= NCR_F_HASCFG3; 396130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); 397130293Sscottl case NCR_VARIANT_ESP100A: 398130293Sscottl sc->sc_features |= NCR_F_SELATN3; 399130293Sscottl NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); 400130293Sscottl case NCR_VARIANT_ESP100: 401130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 402130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 403130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 404130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 405130293Sscottl break; 406130293Sscottl 407130293Sscottl case NCR_VARIANT_FAS366: 408130293Sscottl sc->sc_features |= 409130293Sscottl NCR_F_HASCFG3 | NCR_F_FASTSCSI | NCR_F_SELATN3; 410130293Sscottl sc->sc_cfg3 = NCRFASCFG3_FASTCLK | NCRFASCFG3_OBAUTO; 411130293Sscottl sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI; 412130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); 413130293Sscottl sc->sc_cfg2 = 0; /* NCRCFG2_HMEFE| NCRCFG2_HME32 */ 414130293Sscottl NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); 415130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 416130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 417130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 418130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 419130293Sscottl break; 420130293Sscottl 421130293Sscottl default: 422130293Sscottl device_printf(sc->sc_dev, "unknown revision code, " 423130293Sscottl "assuming ESP100\n"); 424130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 425130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 426130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 427130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 428130293Sscottl } 429130293Sscottl 430130293Sscottl if (sc->sc_rev == NCR_VARIANT_AM53C974) 431130293Sscottl NCR_WRITE_REG(sc, NCR_AMDCFG4, sc->sc_cfg4); 432130293Sscottl 433130293Sscottl#if 0 434130293Sscottl device_printf(sc->sc_dev, "ncr53c9x_reset: revision %d\n", 435130293Sscottl sc->sc_rev); 436130293Sscottl device_printf(sc->sc_dev, "ncr53c9x_reset: cfg1 0x%x, cfg2 0x%x, " 437130293Sscottl "cfg3 0x%x, ccf 0x%x, timeout 0x%x\n", 438130293Sscottl sc->sc_cfg1, sc->sc_cfg2, sc->sc_cfg3, sc->sc_ccf, sc->sc_timeout); 439130293Sscottl#endif 440130293Sscottl} 441130293Sscottl 442130293Sscottl/* 443130293Sscottl * Reset the SCSI bus, but not the chip 444130293Sscottl */ 445130293Sscottlstatic void 446130293Sscottlncr53c9x_scsi_reset(struct ncr53c9x_softc *sc) 447130293Sscottl{ 448130293Sscottl 449130293Sscottl (*sc->sc_glue->gl_dma_stop)(sc); 450130293Sscottl 451130293Sscottl NCR_MISC(("%s: resetting SCSI bus\n", device_get_nameunit(sc->sc_dev))); 452130293Sscottl NCRCMD(sc, NCRCMD_RSTSCSI); 453130293Sscottl DELAY(250000); /* Give the bus a fighting chance to settle */ 454130293Sscottl} 455130293Sscottl 456130293Sscottl/* 457130293Sscottl * Initialize ncr53c9x state machine 458130293Sscottl */ 459130293Sscottlvoid 460130293Sscottlncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) 461130293Sscottl{ 462130293Sscottl struct ncr53c9x_ecb *ecb; 463130293Sscottl struct ncr53c9x_linfo *li; 464130293Sscottl int i, r; 465130293Sscottl 466130293Sscottl NCR_MISC(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state)); 467130293Sscottl 468130293Sscottl if (sc->sc_state == 0) { 469130293Sscottl /* First time through; initialize. */ 470130293Sscottl 471130293Sscottl TAILQ_INIT(&sc->ready_list); 472130293Sscottl sc->sc_nexus = NULL; 473130293Sscottl memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo)); 474130293Sscottl for (r = 0; r < sc->sc_ntarg; r++) { 475130293Sscottl LIST_INIT(&sc->sc_tinfo[r].luns); 476130293Sscottl } 477130293Sscottl } else { 478130293Sscottl /* Cancel any active commands. */ 479130293Sscottl sc->sc_state = NCR_CLEANING; 480130293Sscottl sc->sc_msgify = 0; 481130293Sscottl if ((ecb = sc->sc_nexus) != NULL) { 482130293Sscottl ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT; 483130293Sscottl ncr53c9x_done(sc, ecb); 484130293Sscottl } 485130293Sscottl /* Cancel outstanding disconnected commands on each LUN */ 486130293Sscottl for (r = 0; r < sc->sc_ntarg; r++) { 487130293Sscottl LIST_FOREACH(li, &sc->sc_tinfo[r].luns, link) { 488130293Sscottl if ((ecb = li->untagged) != NULL) { 489130293Sscottl li->untagged = NULL; 490130293Sscottl /* 491130293Sscottl * XXXXXXX 492130293Sscottl * 493130293Sscottl * Should we terminate a command 494130293Sscottl * that never reached the disk? 495130293Sscottl */ 496130293Sscottl li->busy = 0; 497130293Sscottl ecb->ccb->ccb_h.status = 498130293Sscottl CAM_CMD_TIMEOUT; 499130293Sscottl ncr53c9x_done(sc, ecb); 500130293Sscottl } 501130293Sscottl for (i = 0; i < 256; i++) 502130293Sscottl if ((ecb = li->queued[i])) { 503130293Sscottl li->queued[i] = NULL; 504130293Sscottl ecb->ccb->ccb_h.status = 505130293Sscottl CAM_CMD_TIMEOUT; 506130293Sscottl ncr53c9x_done(sc, ecb); 507130293Sscottl } 508130293Sscottl li->used = 0; 509130293Sscottl } 510130293Sscottl } 511130293Sscottl } 512130293Sscottl 513130293Sscottl /* 514130293Sscottl * reset the chip to a known state 515130293Sscottl */ 516130293Sscottl ncr53c9x_reset(sc); 517130293Sscottl 518130293Sscottl sc->sc_phase = sc->sc_prevphase = INVALID_PHASE; 519130293Sscottl for (r = 0; r < sc->sc_ntarg; r++) { 520130293Sscottl struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r]; 521130293Sscottl/* XXX - config flags per target: low bits: no reselect; high bits: no synch */ 522130293Sscottl 523130293Sscottl ti->flags = ((sc->sc_minsync && !(sc->sc_cfflags & (1<<((r&7)+8)))) 524130293Sscottl ? 0 : T_SYNCHOFF) | 525130293Sscottl ((sc->sc_cfflags & (1<<(r&7))) ? T_RSELECTOFF : 0); 526130293Sscottl#ifdef DEBUG 527130293Sscottl if (ncr53c9x_notag) 528130293Sscottl ti->flags &= ~T_TAG; 529130293Sscottl#endif 530130293Sscottl ti->period = sc->sc_minsync; 531130293Sscottl ti->offset = 0; 532130293Sscottl ti->cfg3 = 0; 533130293Sscottl } 534130293Sscottl 535130293Sscottl if (doreset) { 536130293Sscottl sc->sc_state = NCR_SBR; 537130293Sscottl NCRCMD(sc, NCRCMD_RSTSCSI); 538130293Sscottl } else { 539130293Sscottl sc->sc_state = NCR_IDLE; 540130293Sscottl ncr53c9x_sched(sc); 541130293Sscottl } 542130293Sscottl} 543130293Sscottl 544130293Sscottl/* 545130293Sscottl * Read the NCR registers, and save their contents for later use. 546130293Sscottl * NCR_STAT, NCR_STEP & NCR_INTR are mostly zeroed out when reading 547130293Sscottl * NCR_INTR - so make sure it is the last read. 548130293Sscottl * 549130293Sscottl * I think that (from reading the docs) most bits in these registers 550130293Sscottl * only make sense when he DMA CSR has an interrupt showing. Call only 551130293Sscottl * if an interrupt is pending. 552130293Sscottl */ 553130293Sscottlstatic __inline void 554130293Sscottlncr53c9x_readregs(struct ncr53c9x_softc *sc) 555130293Sscottl{ 556130293Sscottl 557130293Sscottl sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT); 558130293Sscottl /* Only the stepo bits are of interest */ 559130293Sscottl sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP) & NCRSTEP_MASK; 560130293Sscottl 561145202Smarius if (sc->sc_rev == NCR_VARIANT_FAS366) 562130293Sscottl sc->sc_espstat2 = NCR_READ_REG(sc, NCR_STAT2); 563130293Sscottl 564130293Sscottl sc->sc_espintr = NCR_READ_REG(sc, NCR_INTR); 565130293Sscottl 566130293Sscottl if (sc->sc_glue->gl_clear_latched_intr != NULL) 567130293Sscottl (*sc->sc_glue->gl_clear_latched_intr)(sc); 568130293Sscottl 569130293Sscottl /* 570130293Sscottl * Determine the SCSI bus phase, return either a real SCSI bus phase 571130293Sscottl * or some pseudo phase we use to detect certain exceptions. 572130293Sscottl */ 573130293Sscottl 574130293Sscottl sc->sc_phase = (sc->sc_espintr & NCRINTR_DIS) ? 575130293Sscottl /* Disconnected */ BUSFREE_PHASE : sc->sc_espstat & NCRSTAT_PHASE; 576130293Sscottl 577130293Sscottl NCR_INTS(("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] ", 578130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc->sc_espstat2)); 579130293Sscottl} 580130293Sscottl 581130293Sscottl/* 582130293Sscottl * Convert Synchronous Transfer Period to chip register Clock Per Byte value. 583130293Sscottl */ 584130293Sscottlstatic __inline int 585130293Sscottlncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period) 586130293Sscottl{ 587130293Sscottl int v; 588130293Sscottl v = (sc->sc_freq * period) / 250; 589130293Sscottl if (ncr53c9x_cpb2stp(sc, v) < period) 590130293Sscottl /* Correct round-down error */ 591130293Sscottl v++; 592130293Sscottl return (v); 593130293Sscottl} 594130293Sscottl 595130293Sscottlstatic __inline void 596130293Sscottlncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti) 597130293Sscottl{ 598130293Sscottl u_char syncoff, synctp; 599130293Sscottl u_char cfg3 = sc->sc_cfg3 | ti->cfg3; 600130293Sscottl 601130293Sscottl if (ti->flags & T_SYNCMODE) { 602130293Sscottl syncoff = ti->offset; 603130293Sscottl synctp = ncr53c9x_stp2cpb(sc, ti->period); 604130293Sscottl if (sc->sc_features & NCR_F_FASTSCSI) { 605130293Sscottl /* 606130293Sscottl * If the period is 200ns or less (ti->period <= 50), 607130293Sscottl * put the chip in Fast SCSI mode. 608130293Sscottl */ 609130293Sscottl if (ti->period <= 50) 610130293Sscottl /* 611130293Sscottl * There are (at least) 4 variations of the 612130293Sscottl * configuration 3 register. The drive attach 613130293Sscottl * routine sets the appropriate bit to put the 614130293Sscottl * chip into Fast SCSI mode so that it doesn't 615130293Sscottl * have to be figured out here each time. 616130293Sscottl */ 617130293Sscottl cfg3 |= sc->sc_cfg3_fscsi; 618130293Sscottl } 619130293Sscottl 620130293Sscottl /* 621130293Sscottl * Am53c974 requires different SYNCTP values when the 622130293Sscottl * FSCSI bit is off. 623130293Sscottl */ 624130293Sscottl if (sc->sc_rev == NCR_VARIANT_AM53C974 && 625130293Sscottl (cfg3 & NCRAMDCFG3_FSCSI) == 0) 626130293Sscottl synctp--; 627130293Sscottl } else { 628130293Sscottl syncoff = 0; 629130293Sscottl synctp = 0; 630130293Sscottl } 631130293Sscottl 632130293Sscottl if (sc->sc_features & NCR_F_HASCFG3) 633130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, cfg3); 634130293Sscottl 635130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, syncoff); 636130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCTP, synctp); 637130293Sscottl} 638130293Sscottl 639130293Sscottl/* 640130293Sscottl * Send a command to a target, set the driver state to NCR_SELECTING 641130293Sscottl * and let the caller take care of the rest. 642130293Sscottl * 643130293Sscottl * Keeping this as a function allows me to say that this may be done 644130293Sscottl * by DMA instead of programmed I/O soon. 645130293Sscottl */ 646130293Sscottlstatic void 647130293Sscottlncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 648130293Sscottl{ 649130293Sscottl int target = ecb->ccb->ccb_h.target_id; 650130293Sscottl int lun = ecb->ccb->ccb_h.target_lun; 651130293Sscottl struct ncr53c9x_tinfo *ti; 652130293Sscottl int tiflags; 653130293Sscottl u_char *cmd; 654130293Sscottl int clen; 655130293Sscottl int selatn3, selatns; 656130293Sscottl size_t dmasize; 657130293Sscottl 658130293Sscottl NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x,tag:%x,%x)] ", 659130293Sscottl target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1])); 660130293Sscottl 661130293Sscottl ti = &sc->sc_tinfo[target]; 662130293Sscottl tiflags = ti->flags; 663130293Sscottl sc->sc_state = NCR_SELECTING; 664130293Sscottl /* 665130293Sscottl * Schedule the timeout now, the first time we will go away 666130293Sscottl * expecting to come back due to an interrupt, because it is 667130293Sscottl * always possible that the interrupt may never happen. 668130293Sscottl */ 669130293Sscottl ecb->ccb->ccb_h.timeout_ch = 670130424Sscottl timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout)); 671130293Sscottl 672130293Sscottl /* 673130293Sscottl * The docs say the target register is never reset, and I 674130293Sscottl * can't think of a better place to set it 675130293Sscottl */ 676130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 677130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 678130293Sscottl NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HME); 679130293Sscottl } else { 680130293Sscottl NCR_WRITE_REG(sc, NCR_SELID, target); 681130293Sscottl } 682130293Sscottl ncr53c9x_setsync(sc, ti); 683130293Sscottl 684130293Sscottl if ((ecb->flags & ECB_SENSE) != 0) { 685130293Sscottl /* 686130293Sscottl * For REQUEST SENSE, we should not send an IDENTIFY or 687130293Sscottl * otherwise mangle the target. There should be no MESSAGE IN 688130293Sscottl * phase. 689130293Sscottl */ 690130293Sscottl if (sc->sc_features & NCR_F_DMASELECT) { 691130293Sscottl /* setup DMA transfer for command */ 692130293Sscottl dmasize = clen = ecb->clen; 693130293Sscottl sc->sc_cmdlen = clen; 694130293Sscottl sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd; 695130293Sscottl 696130293Sscottl /* Program the SCSI counter */ 697130293Sscottl NCR_SET_COUNT(sc, dmasize); 698130293Sscottl 699130293Sscottl if (sc->sc_rev != NCR_VARIANT_FAS366) 700130293Sscottl NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA); 701130293Sscottl 702130293Sscottl /* And get the targets attention */ 703130293Sscottl NCRCMD(sc, NCRCMD_SELNATN | NCRCMD_DMA); 704130293Sscottl NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, 705130293Sscottl &dmasize); 706130293Sscottl NCRDMA_GO(sc); 707130293Sscottl } else { 708130293Sscottl ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen); 709130293Sscottl NCRCMD(sc, NCRCMD_SELNATN); 710130293Sscottl } 711130293Sscottl return; 712130293Sscottl } 713130293Sscottl 714130293Sscottl selatn3 = selatns = 0; 715130293Sscottl if (ecb->tag[0] != 0) { 716130293Sscottl if (sc->sc_features & NCR_F_SELATN3) 717130293Sscottl /* use SELATN3 to send tag messages */ 718130293Sscottl selatn3 = 1; 719130293Sscottl else 720130293Sscottl /* We don't have SELATN3; use SELATNS to send tags */ 721130293Sscottl selatns = 1; 722130293Sscottl } 723130293Sscottl 724130293Sscottl if (ti->flags & T_NEGOTIATE) { 725130293Sscottl /* We have to use SELATNS to send sync/wide messages */ 726130293Sscottl selatn3 = 0; 727130293Sscottl selatns = 1; 728130293Sscottl } 729130293Sscottl 730130293Sscottl cmd = (u_char *)&ecb->cmd.cmd; 731130293Sscottl 732130293Sscottl if (selatn3) { 733130293Sscottl /* We'll use tags with SELATN3 */ 734130293Sscottl clen = ecb->clen + 3; 735130293Sscottl cmd -= 3; 736130293Sscottl cmd[0] = MSG_IDENTIFY(lun, 1); /* msg[0] */ 737130293Sscottl cmd[1] = ecb->tag[0]; /* msg[1] */ 738130293Sscottl cmd[2] = ecb->tag[1]; /* msg[2] */ 739130293Sscottl } else { 740130293Sscottl /* We don't have tags, or will send messages with SELATNS */ 741130293Sscottl clen = ecb->clen + 1; 742130293Sscottl cmd -= 1; 743130293Sscottl cmd[0] = MSG_IDENTIFY(lun, (tiflags & T_RSELECTOFF) == 0); 744130293Sscottl } 745130293Sscottl 746130293Sscottl if ((sc->sc_features & NCR_F_DMASELECT) && !selatns) { 747130293Sscottl 748130293Sscottl /* setup DMA transfer for command */ 749130293Sscottl dmasize = clen; 750130293Sscottl sc->sc_cmdlen = clen; 751130293Sscottl sc->sc_cmdp = cmd; 752130293Sscottl 753130293Sscottl /* Program the SCSI counter */ 754130293Sscottl NCR_SET_COUNT(sc, dmasize); 755130293Sscottl 756130293Sscottl /* load the count in */ 757130293Sscottl /* if (sc->sc_rev != NCR_VARIANT_FAS366) */ 758130293Sscottl NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA); 759130293Sscottl 760130293Sscottl /* And get the targets attention */ 761130293Sscottl if (selatn3) { 762130293Sscottl sc->sc_msgout = SEND_TAG; 763130293Sscottl sc->sc_flags |= NCR_ATN; 764130293Sscottl NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA); 765130293Sscottl } else 766130293Sscottl NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA); 767130293Sscottl NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize); 768130293Sscottl NCRDMA_GO(sc); 769130293Sscottl return; 770130293Sscottl } 771130293Sscottl 772130293Sscottl /* 773133039Strhodes * Who am I? This is where we tell the target that we are 774130293Sscottl * happy for it to disconnect etc. 775130293Sscottl */ 776130293Sscottl 777130293Sscottl /* Now get the command into the FIFO */ 778130293Sscottl ncr53c9x_wrfifo(sc, cmd, clen); 779130293Sscottl 780130293Sscottl /* And get the targets attention */ 781130293Sscottl if (selatns) { 782130293Sscottl NCR_MSGS(("SELATNS \n")); 783130293Sscottl /* Arbitrate, select and stop after IDENTIFY message */ 784130293Sscottl NCRCMD(sc, NCRCMD_SELATNS); 785130293Sscottl } else if (selatn3) { 786130293Sscottl sc->sc_msgout = SEND_TAG; 787130293Sscottl sc->sc_flags |= NCR_ATN; 788130293Sscottl NCRCMD(sc, NCRCMD_SELATN3); 789130293Sscottl } else 790130293Sscottl NCRCMD(sc, NCRCMD_SELATN); 791130293Sscottl} 792130293Sscottl 793130293Sscottlstatic void 794130293Sscottlncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 795130293Sscottl{ 796130293Sscottl 797130293Sscottl ecb->flags = 0; 798130406Sscottl TAILQ_INSERT_TAIL(&sc->free_list, ecb, free_links); 799130293Sscottl return; 800130293Sscottl} 801130293Sscottl 802130293Sscottlstatic struct ncr53c9x_ecb * 803130293Sscottlncr53c9x_get_ecb(struct ncr53c9x_softc *sc) 804130293Sscottl{ 805130293Sscottl struct ncr53c9x_ecb *ecb; 806130293Sscottl 807130406Sscottl ecb = TAILQ_FIRST(&sc->free_list); 808130293Sscottl if (ecb) { 809130406Sscottl if (ecb->flags != 0) 810130406Sscottl panic("ecb flags not cleared\n"); 811130406Sscottl TAILQ_REMOVE(&sc->free_list, ecb, free_links); 812130406Sscottl ecb->flags = ECB_ALLOC; 813130406Sscottl bzero(&ecb->ccb, sizeof(struct ncr53c9x_ecb) - 814130406Sscottl offsetof(struct ncr53c9x_ecb, ccb)); 815130293Sscottl } 816130293Sscottl return (ecb); 817130293Sscottl} 818130293Sscottl 819130293Sscottl/* 820133039Strhodes * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS: 821130293Sscottl */ 822130293Sscottl 823130293Sscottl/* 824130293Sscottl * Start a SCSI-command 825130293Sscottl * This function is called by the higher level SCSI-driver to queue/run 826130293Sscottl * SCSI-commands. 827130293Sscottl */ 828130293Sscottl 829130293Sscottlvoid 830130293Sscottlncr53c9x_action(struct cam_sim *sim, union ccb *ccb) 831130293Sscottl{ 832130293Sscottl struct ncr53c9x_softc *sc; 833130293Sscottl struct ncr53c9x_ecb *ecb; 834130293Sscottl 835130293Sscottl NCR_TRACE(("[ncr53c9x_action %d]", ccb->ccb_h.func_code)); 836130293Sscottl 837130293Sscottl sc = cam_sim_softc(sim); 838130293Sscottl mtx_lock(&sc->sc_lock); 839130293Sscottl 840130293Sscottl switch (ccb->ccb_h.func_code) { 841130293Sscottl case XPT_RESET_BUS: 842130293Sscottl ncr53c9x_scsi_reset(sc); 843130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 844130293Sscottl mtx_unlock(&sc->sc_lock); 845130293Sscottl xpt_done(ccb); 846130293Sscottl return; 847130293Sscottl case XPT_CALC_GEOMETRY: 848130293Sscottl mtx_unlock(&sc->sc_lock); 849130349Sscottl cam_calc_geometry(&ccb->ccg, sc->sc_extended_geom); 850130293Sscottl xpt_done(ccb); 851130293Sscottl return; 852130293Sscottl case XPT_PATH_INQ: 853130293Sscottl { 854130293Sscottl struct ccb_pathinq *cpi = &ccb->cpi; 855130293Sscottl 856130293Sscottl cpi->version_num = 1; 857130406Sscottl cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; 858130293Sscottl cpi->hba_inquiry |= 859130293Sscottl (sc->sc_rev == NCR_VARIANT_FAS366) ? PI_WIDE_16 : 0; 860130293Sscottl cpi->target_sprt = 0; 861130293Sscottl cpi->hba_misc = 0; 862130293Sscottl cpi->hba_eng_cnt = 0; 863130293Sscottl cpi->max_target = sc->sc_ntarg - 1; 864130293Sscottl cpi->max_lun = 8; 865130293Sscottl cpi->initiator_id = sc->sc_id; 866130293Sscottl cpi->bus_id = 0; 867130293Sscottl cpi->base_transfer_speed = 3300; 868130293Sscottl strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 869130293Sscottl strncpy(cpi->hba_vid, "Sun", HBA_IDLEN); 870130293Sscottl strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 871130293Sscottl cpi->unit_number = cam_sim_unit(sim); 872130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 873130293Sscottl mtx_unlock(&sc->sc_lock); 874130293Sscottl xpt_done(ccb); 875130293Sscottl return; 876130293Sscottl } 877130293Sscottl case XPT_GET_TRAN_SETTINGS: 878130293Sscottl { 879130293Sscottl struct ccb_trans_settings *cts = &ccb->cts; 880130293Sscottl struct ncr53c9x_tinfo *ti; 881130293Sscottl 882130293Sscottl ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 883130293Sscottl 884130293Sscottl if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) { 885130293Sscottl cts->sync_period = ti->period; 886130293Sscottl cts->sync_offset = ti->offset; 887130293Sscottl cts->bus_width = ti->width; 888130293Sscottl if ((ti->flags & T_TAG) != 0) 889130293Sscottl cts->flags |= 890130293Sscottl (CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); 891130293Sscottl else 892130293Sscottl cts->flags &= 893130293Sscottl ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); 894130293Sscottl } else { 895130293Sscottl cts->sync_period = sc->sc_maxsync; 896130293Sscottl cts->sync_offset = sc->sc_maxoffset; 897130293Sscottl cts->bus_width = sc->sc_maxwidth; 898130293Sscottl cts->flags |= (CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB); 899130293Sscottl } 900130293Sscottl cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 901130293Sscottl CCB_TRANS_SYNC_RATE_VALID | 902130293Sscottl CCB_TRANS_SYNC_OFFSET_VALID | 903130293Sscottl CCB_TRANS_DISC_VALID | 904130293Sscottl CCB_TRANS_TQ_VALID; 905130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 906130293Sscottl mtx_unlock(&sc->sc_lock); 907130293Sscottl xpt_done(ccb); 908130293Sscottl return; 909130293Sscottl } 910130293Sscottl case XPT_ABORT: 911130293Sscottl printf("XPT_ABORT called\n"); 912130293Sscottl ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 913130293Sscottl mtx_unlock(&sc->sc_lock); 914130293Sscottl xpt_done(ccb); 915130293Sscottl return; 916130293Sscottl case XPT_TERM_IO: 917130293Sscottl printf("XPT_TERM_IO called\n"); 918130293Sscottl ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 919130293Sscottl mtx_unlock(&sc->sc_lock); 920130293Sscottl xpt_done(ccb); 921130293Sscottl return; 922130293Sscottl case XPT_RESET_DEV: 923130293Sscottl printf("XPT_RESET_DEV called\n"); 924130293Sscottl case XPT_SCSI_IO: 925130293Sscottl { 926130293Sscottl struct ccb_scsiio *csio; 927130293Sscottl 928130293Sscottl if (ccb->ccb_h.target_id < 0 || 929130293Sscottl ccb->ccb_h.target_id >= sc->sc_ntarg) { 930130293Sscottl ccb->ccb_h.status = CAM_PATH_INVALID; 931130293Sscottl mtx_unlock(&sc->sc_lock); 932130293Sscottl xpt_done(ccb); 933130293Sscottl return; 934130293Sscottl } 935130293Sscottl /* Get an ECB to use. */ 936130293Sscottl ecb = ncr53c9x_get_ecb(sc); 937130293Sscottl /* 938130293Sscottl * This should never happen as we track resources 939130293Sscottl * in the mid-layer. 940130293Sscottl */ 941130293Sscottl if (ecb == NULL) { 942130293Sscottl xpt_freeze_simq(sim, 1); 943130293Sscottl ccb->ccb_h.status = CAM_REQUEUE_REQ; 944130293Sscottl printf("unable to allocate ecb\n"); 945130293Sscottl mtx_unlock(&sc->sc_lock); 946130293Sscottl xpt_done(ccb); 947130293Sscottl return; 948130293Sscottl } 949130293Sscottl 950130293Sscottl /* Initialize ecb */ 951130293Sscottl ecb->ccb = ccb; 952130293Sscottl ecb->timeout = ccb->ccb_h.timeout; 953130293Sscottl 954130372Sscottl if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 955130293Sscottl ecb->flags |= ECB_RESET; 956130293Sscottl ecb->clen = 0; 957130293Sscottl ecb->dleft = 0; 958130293Sscottl } else { 959130293Sscottl csio = &ccb->csio; 960130293Sscottl if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) 961130293Sscottl bcopy(csio->cdb_io.cdb_ptr, &ecb->cmd.cmd, 962130293Sscottl csio->cdb_len); 963130293Sscottl else 964130293Sscottl bcopy(csio->cdb_io.cdb_bytes, &ecb->cmd.cmd, 965130293Sscottl csio->cdb_len); 966130293Sscottl ecb->clen = csio->cdb_len; 967130293Sscottl ecb->daddr = csio->data_ptr; 968130293Sscottl ecb->dleft = csio->dxfer_len; 969130293Sscottl } 970130293Sscottl ecb->stat = 0; 971130293Sscottl 972130293Sscottl TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain); 973130293Sscottl ecb->flags |= ECB_READY; 974130293Sscottl if (sc->sc_state == NCR_IDLE) 975130293Sscottl ncr53c9x_sched(sc); 976130293Sscottl 977130293Sscottl break; 978130293Sscottl } 979130293Sscottl 980130293Sscottl case XPT_SET_TRAN_SETTINGS: 981130293Sscottl { 982130293Sscottl struct ncr53c9x_tinfo *ti; 983130293Sscottl struct ccb_trans_settings *cts = &ccb->cts; 984130293Sscottl int target = ccb->ccb_h.target_id; 985130293Sscottl 986130293Sscottl ti = &sc->sc_tinfo[target]; 987130293Sscottl 988130293Sscottl if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) { 989130293Sscottl if ((sc->sc_cfflags & (1<<((target & 7) + 16))) == 0 && 990130293Sscottl (cts->flags & CCB_TRANS_TAG_ENB)) { 991130293Sscottl NCR_MISC(("%s: target %d: tagged queuing\n", 992130293Sscottl device_get_nameunit(sc->sc_dev), target)); 993130293Sscottl ti->flags |= T_TAG; 994130293Sscottl } else 995130293Sscottl ti->flags &= ~T_TAG; 996130293Sscottl } 997130293Sscottl 998130293Sscottl if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { 999130293Sscottl if (cts->bus_width != 0) { 1000130293Sscottl NCR_MISC(("%s: target %d: wide negotiation\n", 1001130293Sscottl device_get_nameunit(sc->sc_dev), target)); 1002130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 1003130293Sscottl ti->flags |= T_WIDE; 1004130293Sscottl ti->width = 1; 1005130293Sscottl } 1006130293Sscottl } else { 1007130293Sscottl ti->flags &= ~T_WIDE; 1008130293Sscottl ti->width = 0; 1009130293Sscottl } 1010130406Sscottl ti->flags |= T_NEGOTIATE; 1011130293Sscottl } 1012130293Sscottl 1013130293Sscottl if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) { 1014130293Sscottl NCR_MISC(("%s: target %d: sync period negotiation\n", 1015130293Sscottl device_get_nameunit(sc->sc_dev), target)); 1016130293Sscottl ti->flags |= T_NEGOTIATE; 1017130293Sscottl ti->period = cts->sync_period; 1018130293Sscottl } 1019130293Sscottl 1020130293Sscottl if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) { 1021130293Sscottl NCR_MISC(("%s: target %d: sync offset negotiation\n", 1022130293Sscottl device_get_nameunit(sc->sc_dev), target)); 1023130293Sscottl ti->flags |= T_NEGOTIATE; 1024130293Sscottl ti->offset = cts->sync_offset; 1025130293Sscottl } 1026130293Sscottl 1027130293Sscottl mtx_unlock(&sc->sc_lock); 1028130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 1029130293Sscottl xpt_done(ccb); 1030130293Sscottl return; 1031130293Sscottl } 1032130293Sscottl 1033130293Sscottl default: 1034130293Sscottl device_printf(sc->sc_dev, "Unhandled function code %d\n", 1035130293Sscottl ccb->ccb_h.func_code); 1036130293Sscottl ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1037130293Sscottl mtx_unlock(&sc->sc_lock); 1038130293Sscottl xpt_done(ccb); 1039130293Sscottl return; 1040130293Sscottl } 1041130293Sscottl 1042130293Sscottl mtx_unlock(&sc->sc_lock); 1043130293Sscottl} 1044130293Sscottl 1045130293Sscottl/* 1046133039Strhodes * Used when interrupt driven I/O is not allowed, e.g. during boot. 1047130293Sscottl */ 1048130293Sscottlstatic void 1049130293Sscottlncr53c9x_poll(struct cam_sim *sim) 1050130293Sscottl{ 1051130293Sscottl struct ncr53c9x_softc *sc; 1052130293Sscottl 1053130293Sscottl NCR_TRACE(("[ncr53c9x_poll] ")); 1054130293Sscottl sc = cam_sim_softc(sim); 1055130293Sscottl if (NCRDMA_ISINTR(sc)) { 1056130293Sscottl ncr53c9x_intr(sc); 1057130293Sscottl } 1058130293Sscottl} 1059130293Sscottl 1060130293Sscottl/* 1061130293Sscottl * LOW LEVEL SCSI UTILITIES 1062130293Sscottl */ 1063130293Sscottl 1064130293Sscottl/* 1065130293Sscottl * Schedule a scsi operation. This has now been pulled out of the interrupt 1066130293Sscottl * handler so that we may call it from ncr53c9x_scsipi_request and 1067145202Smarius * ncr53c9x_done. This may save us an unnecessary interrupt just to get 1068130293Sscottl * things going. Should only be called when state == NCR_IDLE and at bio pl. 1069130293Sscottl */ 1070130293Sscottlstatic void 1071130293Sscottlncr53c9x_sched(struct ncr53c9x_softc *sc) 1072130293Sscottl{ 1073130293Sscottl struct ncr53c9x_ecb *ecb; 1074130293Sscottl struct ncr53c9x_tinfo *ti; 1075130293Sscottl struct ncr53c9x_linfo *li; 1076130293Sscottl int lun; 1077130293Sscottl int tag; 1078130293Sscottl 1079130293Sscottl NCR_TRACE(("[ncr53c9x_sched] ")); 1080130293Sscottl if (sc->sc_state != NCR_IDLE) 1081130293Sscottl panic("ncr53c9x_sched: not IDLE (state=%d)", sc->sc_state); 1082130293Sscottl 1083130293Sscottl /* 1084130293Sscottl * Find first ecb in ready queue that is for a target/lunit 1085130293Sscottl * combinations that is not busy. 1086130293Sscottl */ 1087130293Sscottl for (ecb = TAILQ_FIRST(&sc->ready_list); ecb != NULL; 1088130293Sscottl ecb = TAILQ_NEXT(ecb, chain)) { 1089130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1090130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1091130293Sscottl 1092130293Sscottl /* Select type of tag for this command */ 1093130293Sscottl if ((ti->flags & (T_RSELECTOFF)) != 0) 1094130293Sscottl tag = 0; 1095130293Sscottl else if ((ti->flags & (T_TAG)) == 0) 1096130293Sscottl tag = 0; 1097130293Sscottl else if ((ecb->flags & ECB_SENSE) != 0) 1098130293Sscottl tag = 0; 1099130406Sscottl else if ((ecb->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0) 1100130406Sscottl tag = 0; 1101130406Sscottl else if (ecb->ccb->csio.tag_action == CAM_TAG_ACTION_NONE) 1102130406Sscottl tag = 0; 1103130293Sscottl else 1104130293Sscottl tag = ecb->ccb->csio.tag_action; 1105130293Sscottl 1106130293Sscottl li = TINFO_LUN(ti, lun); 1107130293Sscottl if (li == NULL) { 1108130293Sscottl /* Initialize LUN info and add to list. */ 1109130293Sscottl if ((li = malloc(sizeof(*li), 1110130293Sscottl M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { 1111130293Sscottl continue; 1112130293Sscottl } 1113130293Sscottl li->lun = lun; 1114130293Sscottl 1115130293Sscottl LIST_INSERT_HEAD(&ti->luns, li, link); 1116130293Sscottl if (lun < NCR_NLUN) 1117130293Sscottl ti->lun[lun] = li; 1118130293Sscottl } 1119130293Sscottl li->last_used = time_second; 1120130293Sscottl if (tag == 0) { 1121130293Sscottl /* Try to issue this as an un-tagged command */ 1122130293Sscottl if (li->untagged == NULL) 1123130293Sscottl li->untagged = ecb; 1124130293Sscottl } 1125130293Sscottl if (li->untagged != NULL) { 1126130293Sscottl tag = 0; 1127130293Sscottl if ((li->busy != 1) && li->used == 0) { 1128130293Sscottl /* We need to issue this untagged command now */ 1129130293Sscottl ecb = li->untagged; 1130130293Sscottl } else { 1131130293Sscottl /* Not ready yet */ 1132130293Sscottl continue; 1133130293Sscottl } 1134130293Sscottl } 1135130293Sscottl ecb->tag[0] = tag; 1136130293Sscottl if (tag != 0) { 1137130406Sscottl li->queued[ecb->tag_id] = ecb; 1138130406Sscottl ecb->tag[1] = ecb->tag_id; 1139130293Sscottl li->used++; 1140130293Sscottl } 1141130293Sscottl if (li->untagged != NULL && (li->busy != 1)) { 1142130293Sscottl li->busy = 1; 1143130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1144130293Sscottl ecb->flags &= ~ECB_READY; 1145130293Sscottl sc->sc_nexus = ecb; 1146130293Sscottl ncr53c9x_select(sc, ecb); 1147130293Sscottl break; 1148130293Sscottl } 1149130293Sscottl if (li->untagged == NULL && tag != 0) { 1150130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1151130293Sscottl ecb->flags &= ~ECB_READY; 1152130293Sscottl sc->sc_nexus = ecb; 1153130293Sscottl ncr53c9x_select(sc, ecb); 1154130293Sscottl break; 1155130293Sscottl } else 1156130293Sscottl NCR_TRACE(("%d:%d busy\n", 1157130293Sscottl ecb->ccb->ccb_h.target_id, 1158130293Sscottl ecb->ccb->ccb_h.target_lun)); 1159130293Sscottl } 1160130293Sscottl} 1161130293Sscottl 1162130293Sscottlstatic void 1163130293Sscottlncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1164130293Sscottl{ 1165130293Sscottl union ccb *ccb = ecb->ccb; 1166130293Sscottl struct ncr53c9x_tinfo *ti; 1167130293Sscottl struct scsi_request_sense *ss = (void *)&ecb->cmd.cmd; 1168130293Sscottl struct ncr53c9x_linfo *li; 1169130293Sscottl int lun; 1170130293Sscottl 1171130293Sscottl NCR_TRACE(("requesting sense ")); 1172130293Sscottl 1173130293Sscottl lun = ccb->ccb_h.target_lun; 1174130293Sscottl ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 1175130293Sscottl 1176130293Sscottl /* Next, setup a request sense command block */ 1177130293Sscottl memset(ss, 0, sizeof(*ss)); 1178130293Sscottl ss->opcode = REQUEST_SENSE; 1179130293Sscottl ss->byte2 = ccb->ccb_h.target_lun << SCSI_CMD_LUN_SHIFT; 1180130293Sscottl ss->length = sizeof(struct scsi_sense_data); 1181130293Sscottl ecb->clen = sizeof(*ss); 1182130293Sscottl ecb->daddr = (char *)&ecb->ccb->csio.sense_data; 1183130293Sscottl ecb->dleft = sizeof(struct scsi_sense_data); 1184130293Sscottl ecb->flags |= ECB_SENSE; 1185130293Sscottl ecb->timeout = NCR_SENSE_TIMEOUT; 1186130293Sscottl ti->senses++; 1187130293Sscottl li = TINFO_LUN(ti, lun); 1188130293Sscottl if (li->busy) 1189130293Sscottl li->busy = 0; 1190130293Sscottl ncr53c9x_dequeue(sc, ecb); 1191130293Sscottl li->untagged = ecb; /* must be executed first to fix C/A */ 1192130293Sscottl li->busy = 2; 1193130293Sscottl if (ecb == sc->sc_nexus) { 1194130293Sscottl ncr53c9x_select(sc, ecb); 1195130293Sscottl } else { 1196130293Sscottl TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); 1197130293Sscottl ecb->flags |= ECB_READY; 1198130293Sscottl if (sc->sc_state == NCR_IDLE) 1199130293Sscottl ncr53c9x_sched(sc); 1200130293Sscottl } 1201130293Sscottl} 1202130293Sscottl 1203130293Sscottl/* 1204130293Sscottl * POST PROCESSING OF SCSI_CMD (usually current) 1205130293Sscottl */ 1206130293Sscottlstatic void 1207130293Sscottlncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1208130293Sscottl{ 1209130293Sscottl union ccb *ccb = ecb->ccb; 1210130293Sscottl struct ncr53c9x_tinfo *ti; 1211130293Sscottl struct ncr53c9x_linfo *li; 1212130293Sscottl int lun; 1213130293Sscottl 1214130293Sscottl NCR_TRACE(("[ncr53c9x_done(status:%x)] ", ccb->ccb_h.status)); 1215130293Sscottl 1216130293Sscottl ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 1217130293Sscottl lun = ccb->ccb_h.target_lun; 1218130293Sscottl li = TINFO_LUN(ti, lun); 1219130293Sscottl 1220130424Sscottl untimeout(ncr53c9x_timeout, ecb, ccb->ccb_h.timeout_ch); 1221130293Sscottl 1222130293Sscottl /* 1223130293Sscottl * Now, if we've come here with no error code, i.e. we've kept the 1224130293Sscottl * initial XS_NOERROR, and the status code signals that we should 1225130293Sscottl * check sense, we'll need to set up a request sense cmd block and 1226130293Sscottl * push the command back into the ready queue *before* any other 1227130293Sscottl * commands for this target/lunit, else we lose the sense info. 1228130293Sscottl * We don't support chk sense conditions for the request sense cmd. 1229130293Sscottl */ 1230130293Sscottl if (ccb->ccb_h.status == CAM_REQ_CMP) { 1231130293Sscottl if ((ecb->flags & ECB_ABORT) != 0) { 1232130293Sscottl ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1233130406Sscottl } else if ((ecb->flags & ECB_SENSE) != 0 && 1234130406Sscottl (ecb->stat != SCSI_STATUS_CHECK_COND)) { 1235130372Sscottl ccb->ccb_h.status = CAM_AUTOSNS_VALID; 1236130293Sscottl } else if (ecb->stat == SCSI_STATUS_CHECK_COND) { 1237130293Sscottl if ((ecb->flags & ECB_SENSE) != 0) 1238130293Sscottl ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 1239130293Sscottl else { 1240130293Sscottl /* First, save the return values */ 1241130293Sscottl ccb->csio.resid = ecb->dleft; 1242130293Sscottl ncr53c9x_sense(sc, ecb); 1243130293Sscottl return; 1244130293Sscottl } 1245130293Sscottl } else { 1246130293Sscottl ccb->csio.resid = ecb->dleft; 1247130293Sscottl } 1248130293Sscottl#if 0 1249130293Sscottl if (xs->status == SCSI_QUEUE_FULL || xs->status == XS_BUSY) 1250130293Sscottl xs->error = XS_BUSY; 1251130293Sscottl#endif 1252130293Sscottl } 1253130293Sscottl 1254130293Sscottl#ifdef NCR53C9X_DEBUG 1255130293Sscottl if (ncr53c9x_debug & NCR_SHOWTRAC) { 1256130293Sscottl if (ccb->csio.resid != 0) 1257130293Sscottl printf("resid=%d ", ccb->csio.resid); 1258130293Sscottl#if 0 1259130293Sscottl if (xs->error == XS_SENSE) 1260130293Sscottl printf("sense=0x%02x\n", 1261130293Sscottl xs->sense.scsi_sense.error_code); 1262130293Sscottl else 1263130293Sscottl printf("error=%d\n", xs->error); 1264130293Sscottl#endif 1265130293Sscottl } 1266130293Sscottl#endif 1267130293Sscottl 1268130293Sscottl /* 1269130293Sscottl * Remove the ECB from whatever queue it's on. 1270130293Sscottl */ 1271130293Sscottl ncr53c9x_dequeue(sc, ecb); 1272130293Sscottl if (ecb == sc->sc_nexus) { 1273130293Sscottl sc->sc_nexus = NULL; 1274130293Sscottl if (sc->sc_state != NCR_CLEANING) { 1275130293Sscottl sc->sc_state = NCR_IDLE; 1276130293Sscottl ncr53c9x_sched(sc); 1277130293Sscottl } 1278130293Sscottl } 1279130293Sscottl 1280130293Sscottl if (ccb->ccb_h.status == CAM_SEL_TIMEOUT) { 1281130293Sscottl /* Selection timeout -- discard this LUN if empty */ 1282130293Sscottl if (li->untagged == NULL && li->used == 0) { 1283130293Sscottl if (lun < NCR_NLUN) 1284130293Sscottl ti->lun[lun] = NULL; 1285130293Sscottl LIST_REMOVE(li, link); 1286130293Sscottl free(li, M_DEVBUF); 1287130293Sscottl } 1288130293Sscottl } 1289130293Sscottl 1290130293Sscottl ncr53c9x_free_ecb(sc, ecb); 1291130293Sscottl ti->cmds++; 1292130293Sscottl xpt_done(ccb); 1293130293Sscottl} 1294130293Sscottl 1295130293Sscottlstatic void 1296130293Sscottlncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1297130293Sscottl{ 1298130293Sscottl struct ncr53c9x_tinfo *ti; 1299130293Sscottl struct ncr53c9x_linfo *li; 1300130293Sscottl int64_t lun; 1301130293Sscottl 1302130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1303130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1304130293Sscottl li = TINFO_LUN(ti, lun); 1305130293Sscottl#ifdef DIAGNOSTIC 1306130293Sscottl if (li == NULL || li->lun != lun) 1307130293Sscottl panic("ncr53c9x_dequeue: lun %qx for ecb %p does not exist", 1308130293Sscottl (long long) lun, ecb); 1309130293Sscottl#endif 1310130293Sscottl if (li->untagged == ecb) { 1311130293Sscottl li->busy = 0; 1312130293Sscottl li->untagged = NULL; 1313130293Sscottl } 1314130293Sscottl if (ecb->tag[0] && li->queued[ecb->tag[1]] != NULL) { 1315130293Sscottl#ifdef DIAGNOSTIC 1316130293Sscottl if (li->queued[ecb->tag[1]] != NULL && 1317130293Sscottl (li->queued[ecb->tag[1]] != ecb)) 1318130293Sscottl panic("ncr53c9x_dequeue: slot %d for lun %qx has %p " 1319130293Sscottl "instead of ecb %p\n", ecb->tag[1], 1320130293Sscottl (long long) lun, 1321130293Sscottl li->queued[ecb->tag[1]], ecb); 1322130293Sscottl#endif 1323130293Sscottl li->queued[ecb->tag[1]] = NULL; 1324130293Sscottl li->used--; 1325130293Sscottl } 1326130293Sscottl 1327130293Sscottl if ((ecb->flags & ECB_READY) != 0) { 1328130293Sscottl ecb->flags &= ~ECB_READY; 1329130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1330130293Sscottl } 1331130293Sscottl} 1332130293Sscottl 1333130293Sscottl/* 1334130293Sscottl * INTERRUPT/PROTOCOL ENGINE 1335130293Sscottl */ 1336130293Sscottl 1337130293Sscottl/* 1338130293Sscottl * Schedule an outgoing message by prioritizing it, and asserting 1339130293Sscottl * attention on the bus. We can only do this when we are the initiator 1340130293Sscottl * else there will be an illegal command interrupt. 1341130293Sscottl */ 1342130293Sscottl#define ncr53c9x_sched_msgout(m) \ 1343130293Sscottl do { \ 1344130293Sscottl NCR_MSGS(("ncr53c9x_sched_msgout %x %d", m, __LINE__)); \ 1345130293Sscottl NCRCMD(sc, NCRCMD_SETATN); \ 1346130293Sscottl sc->sc_flags |= NCR_ATN; \ 1347130293Sscottl sc->sc_msgpriq |= (m); \ 1348130293Sscottl } while (0) 1349130293Sscottl 1350130293Sscottlstatic void 1351130293Sscottlncr53c9x_flushfifo(struct ncr53c9x_softc *sc) 1352130293Sscottl{ 1353130293Sscottl NCR_TRACE(("[flushfifo] ")); 1354130293Sscottl 1355130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 1356130293Sscottl 1357130293Sscottl if (sc->sc_phase == COMMAND_PHASE || 1358130293Sscottl sc->sc_phase == MESSAGE_OUT_PHASE) 1359130293Sscottl DELAY(2); 1360130293Sscottl} 1361130293Sscottl 1362130293Sscottlstatic int 1363130293Sscottlncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how) 1364130293Sscottl{ 1365130293Sscottl int i, n; 1366130293Sscottl u_char *buf; 1367130293Sscottl 1368130293Sscottl switch(how) { 1369130293Sscottl case NCR_RDFIFO_START: 1370130293Sscottl buf = sc->sc_imess; 1371130293Sscottl sc->sc_imlen = 0; 1372130293Sscottl break; 1373130293Sscottl case NCR_RDFIFO_CONTINUE: 1374130293Sscottl buf = sc->sc_imess + sc->sc_imlen; 1375130293Sscottl break; 1376130293Sscottl default: 1377130293Sscottl panic("ncr53c9x_rdfifo: bad flag"); 1378130293Sscottl break; 1379130293Sscottl } 1380130293Sscottl 1381130293Sscottl /* 1382130293Sscottl * XXX buffer (sc_imess) size for message 1383130293Sscottl */ 1384130293Sscottl 1385130293Sscottl n = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF; 1386130293Sscottl 1387130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 1388130293Sscottl n *= 2; 1389130293Sscottl 1390130293Sscottl for (i = 0; i < n; i++) 1391130293Sscottl buf[i] = NCR_READ_REG(sc, NCR_FIFO); 1392130293Sscottl 1393130293Sscottl if (sc->sc_espstat2 & NCRFAS_STAT2_ISHUTTLE) { 1394130293Sscottl 1395130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, 0); 1396130293Sscottl buf[i++] = NCR_READ_REG(sc, NCR_FIFO); 1397130293Sscottl 1398130293Sscottl NCR_READ_REG(sc, NCR_FIFO); 1399130293Sscottl 1400130293Sscottl ncr53c9x_flushfifo(sc); 1401130293Sscottl } 1402130293Sscottl } else { 1403130293Sscottl for (i = 0; i < n; i++) 1404130293Sscottl buf[i] = NCR_READ_REG(sc, NCR_FIFO); 1405130293Sscottl } 1406130293Sscottl 1407130293Sscottl sc->sc_imlen += i; 1408130293Sscottl 1409130293Sscottl#if 0 1410130293Sscottl#ifdef NCR53C9X_DEBUG 1411130293Sscottl { 1412130293Sscottl int j; 1413130293Sscottl 1414130293Sscottl NCR_TRACE(("\n[rdfifo %s (%d):", 1415130293Sscottl (how == NCR_RDFIFO_START) ? "start" : "cont", 1416130293Sscottl (int)sc->sc_imlen)); 1417130293Sscottl if (ncr53c9x_debug & NCR_SHOWTRAC) { 1418130293Sscottl for (j = 0; j < sc->sc_imlen; j++) 1419130293Sscottl printf(" %02x", sc->sc_imess[j]); 1420130293Sscottl printf("]\n"); 1421130293Sscottl } 1422130293Sscottl } 1423130293Sscottl#endif 1424130293Sscottl#endif 1425130293Sscottl return sc->sc_imlen; 1426130293Sscottl} 1427130293Sscottl 1428130293Sscottlstatic void 1429130293Sscottlncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len) 1430130293Sscottl{ 1431130293Sscottl int i; 1432130293Sscottl 1433130293Sscottl#ifdef NCR53C9X_DEBUG 1434130293Sscottl NCR_MSGS(("[wrfifo(%d):", len)); 1435130293Sscottl if (ncr53c9x_debug & NCR_SHOWMSGS) { 1436130293Sscottl for (i = 0; i < len; i++) 1437130293Sscottl printf(" %02x", p[i]); 1438130293Sscottl printf("]\n"); 1439130293Sscottl } 1440130293Sscottl#endif 1441130293Sscottl 1442130293Sscottl for (i = 0; i < len; i++) { 1443130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, p[i]); 1444130293Sscottl 1445130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) 1446130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, 0); 1447130293Sscottl } 1448130293Sscottl} 1449130293Sscottl 1450130293Sscottlstatic int 1451130293Sscottlncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype, 1452130293Sscottl int tagid) 1453130293Sscottl{ 1454130293Sscottl u_char selid, target, lun; 1455130293Sscottl struct ncr53c9x_ecb *ecb = NULL; 1456130293Sscottl struct ncr53c9x_tinfo *ti; 1457130293Sscottl struct ncr53c9x_linfo *li; 1458130293Sscottl 1459130293Sscottl 1460130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 1461130293Sscottl target = sc->sc_selid; 1462130293Sscottl } else { 1463130293Sscottl /* 1464130293Sscottl * The SCSI chip made a snapshot of the data bus 1465130293Sscottl * while the reselection was being negotiated. 1466130293Sscottl * This enables us to determine which target did 1467130293Sscottl * the reselect. 1468130293Sscottl */ 1469130293Sscottl selid = sc->sc_selid & ~(1 << sc->sc_id); 1470130293Sscottl if (selid & (selid - 1)) { 1471130293Sscottl device_printf(sc->sc_dev, "reselect with invalid " 1472130293Sscottl "selid %02x; sending DEVICE RESET\n", selid); 1473130293Sscottl goto reset; 1474130293Sscottl } 1475130293Sscottl 1476130293Sscottl target = ffs(selid) - 1; 1477130293Sscottl } 1478130293Sscottl lun = message & 0x07; 1479130293Sscottl 1480130293Sscottl /* 1481130293Sscottl * Search wait queue for disconnected cmd 1482130293Sscottl * The list should be short, so I haven't bothered with 1483130293Sscottl * any more sophisticated structures than a simple 1484130293Sscottl * singly linked list. 1485130293Sscottl */ 1486130293Sscottl ti = &sc->sc_tinfo[target]; 1487130293Sscottl li = TINFO_LUN(ti, lun); 1488130293Sscottl 1489130293Sscottl /* 1490130293Sscottl * We can get as far as the LUN with the IDENTIFY 1491130293Sscottl * message. Check to see if we're running an 1492130293Sscottl * un-tagged command. Otherwise ack the IDENTIFY 1493130293Sscottl * and wait for a tag message. 1494130293Sscottl */ 1495130293Sscottl if (li != NULL) { 1496130293Sscottl if (li->untagged != NULL && li->busy) 1497130293Sscottl ecb = li->untagged; 1498130293Sscottl else if (tagtype != MSG_SIMPLE_Q_TAG) { 1499130293Sscottl /* Wait for tag to come by */ 1500130293Sscottl sc->sc_state = NCR_IDENTIFIED; 1501130293Sscottl return (0); 1502130293Sscottl } else if (tagtype) 1503130293Sscottl ecb = li->queued[tagid]; 1504130293Sscottl } 1505130293Sscottl if (ecb == NULL) { 1506130293Sscottl device_printf(sc->sc_dev, "reselect from target %d lun %d " 1507130293Sscottl "tag %x:%x with no nexus; sending ABORT\n", 1508130293Sscottl target, lun, tagtype, tagid); 1509130293Sscottl goto abort; 1510130293Sscottl } 1511130293Sscottl 1512130293Sscottl /* Make this nexus active again. */ 1513130293Sscottl sc->sc_state = NCR_CONNECTED; 1514130293Sscottl sc->sc_nexus = ecb; 1515130293Sscottl ncr53c9x_setsync(sc, ti); 1516130293Sscottl 1517130293Sscottl if (ecb->flags & ECB_RESET) 1518130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 1519130293Sscottl else if (ecb->flags & ECB_ABORT) 1520130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 1521130293Sscottl 1522130293Sscottl /* Do an implicit RESTORE POINTERS. */ 1523130293Sscottl sc->sc_dp = ecb->daddr; 1524130293Sscottl sc->sc_dleft = ecb->dleft; 1525130293Sscottl 1526130293Sscottl return (0); 1527130293Sscottl 1528130293Sscottlreset: 1529130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 1530130293Sscottl return (1); 1531130293Sscottl 1532130293Sscottlabort: 1533130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 1534130293Sscottl return (1); 1535130293Sscottl} 1536130293Sscottl 1537130293Sscottl/* From NetBSD. These should go into CAM at some point */ 1538130293Sscottl#define MSG_ISEXTENDED(m) ((m) == MSG_EXTENDED) 1539130293Sscottl#define MSG_IS1BYTE(m) \ 1540130293Sscottl ((!MSG_ISEXTENDED(m) && (m) < 0x20) || MSG_ISIDENTIFY(m)) 1541130293Sscottl#define MSG_IS2BYTE(m) (((m) & 0xf0) == 0x20) 1542130293Sscottl 1543130293Sscottlstatic inline int 1544130293Sscottl__verify_msg_format(u_char *p, int len) 1545130293Sscottl{ 1546130293Sscottl 1547130293Sscottl if (len == 1 && MSG_IS1BYTE(p[0])) 1548130293Sscottl return 1; 1549130293Sscottl if (len == 2 && MSG_IS2BYTE(p[0])) 1550130293Sscottl return 1; 1551130293Sscottl if (len >= 3 && MSG_ISEXTENDED(p[0]) && 1552130293Sscottl len == p[1] + 2) 1553130293Sscottl return 1; 1554130293Sscottl 1555130293Sscottl return 0; 1556130293Sscottl} 1557130293Sscottl 1558130293Sscottl/* 1559130293Sscottl * Get an incoming message as initiator. 1560130293Sscottl * 1561130293Sscottl * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a 1562130293Sscottl * byte in the FIFO 1563130293Sscottl */ 1564130293Sscottlstatic void 1565130293Sscottlncr53c9x_msgin(struct ncr53c9x_softc *sc) 1566130293Sscottl{ 1567130293Sscottl 1568130293Sscottl NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld)] ", (long)sc->sc_imlen)); 1569130293Sscottl 1570130293Sscottl if (sc->sc_imlen == 0) { 1571130293Sscottl device_printf(sc->sc_dev, "msgin: no msg byte available\n"); 1572130293Sscottl return; 1573130293Sscottl } 1574130293Sscottl 1575130293Sscottl /* 1576130293Sscottl * Prepare for a new message. A message should (according 1577130293Sscottl * to the SCSI standard) be transmitted in one single 1578130293Sscottl * MESSAGE_IN_PHASE. If we have been in some other phase, 1579130293Sscottl * then this is a new message. 1580130293Sscottl */ 1581130293Sscottl if (sc->sc_prevphase != MESSAGE_IN_PHASE && 1582130293Sscottl sc->sc_state != NCR_RESELECTED) { 1583130293Sscottl device_printf(sc->sc_dev, "phase change, dropping message, " 1584130293Sscottl "prev %d, state %d\n", sc->sc_prevphase, sc->sc_state); 1585130293Sscottl sc->sc_flags &= ~NCR_DROP_MSGI; 1586130293Sscottl sc->sc_imlen = 0; 1587130293Sscottl } 1588130293Sscottl 1589130293Sscottl /* 1590130293Sscottl * If we're going to reject the message, don't bother storing 1591130293Sscottl * the incoming bytes. But still, we need to ACK them. 1592130293Sscottl */ 1593130293Sscottl if ((sc->sc_flags & NCR_DROP_MSGI) != 0) { 1594130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 1595130293Sscottl printf("<dropping msg byte %x>", sc->sc_imess[sc->sc_imlen]); 1596130293Sscottl return; 1597130293Sscottl } 1598130293Sscottl 1599130293Sscottl if (sc->sc_imlen >= NCR_MAX_MSG_LEN) { 1600130293Sscottl ncr53c9x_sched_msgout(SEND_REJECT); 1601130293Sscottl sc->sc_flags |= NCR_DROP_MSGI; 1602130293Sscottl } else { 1603130293Sscottl u_char *pb; 1604130293Sscottl int plen; 1605130293Sscottl 1606130293Sscottl switch (sc->sc_state) { 1607130293Sscottl /* 1608130293Sscottl * if received message is the first of reselection 1609130293Sscottl * then first byte is selid, and then message 1610130293Sscottl */ 1611130293Sscottl case NCR_RESELECTED: 1612130293Sscottl pb = sc->sc_imess + 1; 1613130293Sscottl plen = sc->sc_imlen - 1; 1614130293Sscottl break; 1615130293Sscottl default: 1616130293Sscottl pb = sc->sc_imess; 1617130293Sscottl plen = sc->sc_imlen; 1618130293Sscottl break; 1619130293Sscottl } 1620130293Sscottl 1621130293Sscottl if (__verify_msg_format(pb, plen)) 1622130293Sscottl goto gotit; 1623130293Sscottl } 1624130293Sscottl 1625130293Sscottl /* Ack what we have so far */ 1626130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 1627130293Sscottl return; 1628130293Sscottl 1629130293Sscottlgotit: 1630130293Sscottl NCR_MSGS(("gotmsg(%x) state %d", sc->sc_imess[0], sc->sc_state)); 1631133039Strhodes /* We got a complete message, flush the imess, */ 1632130293Sscottl /* XXX nobody uses imlen below */ 1633130293Sscottl sc->sc_imlen = 0; 1634130293Sscottl /* 1635130293Sscottl * Now we should have a complete message (1 byte, 2 byte 1636130293Sscottl * and moderately long extended messages). We only handle 1637130293Sscottl * extended messages which total length is shorter than 1638130293Sscottl * NCR_MAX_MSG_LEN. Longer messages will be amputated. 1639130293Sscottl */ 1640130293Sscottl switch (sc->sc_state) { 1641130293Sscottl struct ncr53c9x_ecb *ecb; 1642130293Sscottl struct ncr53c9x_tinfo *ti; 1643130293Sscottl struct ncr53c9x_linfo *li; 1644130293Sscottl int lun; 1645130293Sscottl 1646130293Sscottl case NCR_CONNECTED: 1647130293Sscottl ecb = sc->sc_nexus; 1648130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1649130293Sscottl 1650130293Sscottl switch (sc->sc_imess[0]) { 1651130293Sscottl case MSG_CMDCOMPLETE: 1652130293Sscottl NCR_MSGS(("cmdcomplete ")); 1653130293Sscottl if (sc->sc_dleft < 0) { 1654130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 1655130293Sscottl printf("got %ld extra bytes\n", 1656130293Sscottl -(long)sc->sc_dleft); 1657130293Sscottl sc->sc_dleft = 0; 1658130293Sscottl } 1659130293Sscottl ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE) ? 1660130293Sscottl 0 : sc->sc_dleft; 1661130293Sscottl if ((ecb->flags & ECB_SENSE) == 0) 1662130293Sscottl ecb->ccb->csio.resid = ecb->dleft; 1663130293Sscottl sc->sc_state = NCR_CMDCOMPLETE; 1664130293Sscottl break; 1665130293Sscottl 1666130293Sscottl case MSG_MESSAGE_REJECT: 1667130293Sscottl NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout)); 1668130293Sscottl switch (sc->sc_msgout) { 1669130293Sscottl case SEND_TAG: 1670130293Sscottl /* 1671130293Sscottl * Target does not like tagged queuing. 1672130293Sscottl * - Flush the command queue 1673130293Sscottl * - Disable tagged queuing for the target 1674130293Sscottl * - Dequeue ecb from the queued array. 1675130293Sscottl */ 1676130293Sscottl device_printf(sc->sc_dev, "tagged queuing " 1677130293Sscottl "rejected: target %d\n", 1678130293Sscottl ecb->ccb->ccb_h.target_id); 1679130293Sscottl 1680130293Sscottl NCR_MSGS(("(rejected sent tag)")); 1681130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 1682130293Sscottl DELAY(1); 1683130293Sscottl ti->flags &= ~T_TAG; 1684130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1685130293Sscottl li = TINFO_LUN(ti, lun); 1686130293Sscottl if (ecb->tag[0] && 1687130293Sscottl li->queued[ecb->tag[1]] != NULL) { 1688130293Sscottl li->queued[ecb->tag[1]] = NULL; 1689130293Sscottl li->used--; 1690130293Sscottl } 1691130293Sscottl ecb->tag[0] = ecb->tag[1] = 0; 1692130293Sscottl li->untagged = ecb; 1693130293Sscottl li->busy = 1; 1694130293Sscottl break; 1695130293Sscottl 1696130293Sscottl case SEND_SDTR: 1697130293Sscottl device_printf(sc->sc_dev, "sync transfer " 1698130293Sscottl "rejected: target %d\n", 1699130293Sscottl ecb->ccb->ccb_h.target_id); 1700130293Sscottl 1701130293Sscottl sc->sc_flags &= ~NCR_SYNCHNEGO; 1702130293Sscottl ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); 1703130293Sscottl ncr53c9x_setsync(sc, ti); 1704130293Sscottl break; 1705130293Sscottl 1706130293Sscottl case SEND_WDTR: 1707130293Sscottl device_printf(sc->sc_dev, "wide transfer " 1708130293Sscottl "rejected: target %d\n", 1709130293Sscottl ecb->ccb->ccb_h.target_id); 1710130293Sscottl ti->flags &= ~(T_WIDE | T_WDTRSENT); 1711130293Sscottl ti->width = 0; 1712130293Sscottl break; 1713130293Sscottl 1714130293Sscottl case SEND_INIT_DET_ERR: 1715130293Sscottl goto abort; 1716130293Sscottl } 1717130293Sscottl break; 1718130293Sscottl 1719130293Sscottl case MSG_NOOP: 1720130293Sscottl NCR_MSGS(("noop ")); 1721130293Sscottl break; 1722130293Sscottl 1723130293Sscottl case MSG_HEAD_OF_Q_TAG: 1724130293Sscottl case MSG_SIMPLE_Q_TAG: 1725130293Sscottl case MSG_ORDERED_Q_TAG: 1726130293Sscottl NCR_MSGS(("TAG %x:%x", 1727130293Sscottl sc->sc_imess[0], sc->sc_imess[1])); 1728130293Sscottl break; 1729130293Sscottl 1730130293Sscottl case MSG_DISCONNECT: 1731130293Sscottl NCR_MSGS(("disconnect ")); 1732130293Sscottl ti->dconns++; 1733130293Sscottl sc->sc_state = NCR_DISCONNECT; 1734130293Sscottl 1735130293Sscottl /* 1736130293Sscottl * Mark the fact that all bytes have moved. The 1737130293Sscottl * target may not bother to do a SAVE POINTERS 1738130293Sscottl * at this stage. This flag will set the residual 1739130293Sscottl * count to zero on MSG COMPLETE. 1740130293Sscottl */ 1741130293Sscottl if (sc->sc_dleft == 0) 1742130293Sscottl ecb->flags |= ECB_TENTATIVE_DONE; 1743130293Sscottl 1744130293Sscottl break; 1745130293Sscottl 1746130293Sscottl case MSG_SAVEDATAPOINTER: 1747130293Sscottl NCR_MSGS(("save datapointer ")); 1748130293Sscottl ecb->daddr = sc->sc_dp; 1749130293Sscottl ecb->dleft = sc->sc_dleft; 1750130293Sscottl break; 1751130293Sscottl 1752130293Sscottl case MSG_RESTOREPOINTERS: 1753130293Sscottl NCR_MSGS(("restore datapointer ")); 1754130293Sscottl sc->sc_dp = ecb->daddr; 1755130293Sscottl sc->sc_dleft = ecb->dleft; 1756130293Sscottl break; 1757130293Sscottl 1758130293Sscottl case MSG_EXTENDED: 1759130293Sscottl NCR_MSGS(("extended(%x) ", sc->sc_imess[2])); 1760130293Sscottl switch (sc->sc_imess[2]) { 1761130293Sscottl case MSG_EXT_SDTR: 1762130293Sscottl NCR_MSGS(("SDTR period %d, offset %d ", 1763130293Sscottl sc->sc_imess[3], sc->sc_imess[4])); 1764130293Sscottl if (sc->sc_imess[1] != 3) 1765130293Sscottl goto reject; 1766130293Sscottl ti->period = sc->sc_imess[3]; 1767130293Sscottl ti->offset = sc->sc_imess[4]; 1768130293Sscottl ti->flags &= ~T_NEGOTIATE; 1769130293Sscottl if (sc->sc_minsync == 0 || 1770130293Sscottl ti->offset == 0 || 1771130293Sscottl ti->period > 124) { 1772130293Sscottl#if 0 1773130293Sscottl#ifdef NCR53C9X_DEBUG 1774130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 1775130293Sscottl printf("async mode\n"); 1776130293Sscottl#endif 1777130293Sscottl#endif 1778130293Sscottl ti->flags &= ~T_SYNCMODE; 1779130293Sscottl if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) { 1780130293Sscottl /* 1781130293Sscottl * target initiated negotiation 1782130293Sscottl */ 1783130293Sscottl ti->offset = 0; 1784130293Sscottl ncr53c9x_sched_msgout( 1785130293Sscottl SEND_SDTR); 1786130293Sscottl } 1787130293Sscottl } else { 1788130293Sscottl int p; 1789130293Sscottl 1790130293Sscottl p = ncr53c9x_stp2cpb(sc, ti->period); 1791130293Sscottl ti->period = ncr53c9x_cpb2stp(sc, p); 1792130293Sscottl if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) { 1793130293Sscottl /* 1794130293Sscottl * target initiated negotiation 1795130293Sscottl */ 1796130293Sscottl if (ti->period < 1797130293Sscottl sc->sc_minsync) 1798130293Sscottl ti->period = 1799130293Sscottl sc->sc_minsync; 1800130293Sscottl if (ti->offset > 15) 1801130293Sscottl ti->offset = 15; 1802130293Sscottl ti->flags &= ~T_SYNCMODE; 1803130293Sscottl ncr53c9x_sched_msgout( 1804130293Sscottl SEND_SDTR); 1805130293Sscottl } else { 1806130293Sscottl /* we are sync */ 1807130293Sscottl ti->flags |= T_SYNCMODE; 1808130293Sscottl } 1809130293Sscottl } 1810130293Sscottl sc->sc_flags &= ~NCR_SYNCHNEGO; 1811130293Sscottl ncr53c9x_setsync(sc, ti); 1812130293Sscottl break; 1813130293Sscottl 1814130293Sscottl case MSG_EXT_WDTR: 1815130293Sscottl#ifdef NCR53C9X_DEBUG 1816130293Sscottl device_printf(sc->sc_dev, "wide mode %d\n", 1817130293Sscottl sc->sc_imess[3]); 1818130293Sscottl#endif 1819130293Sscottl if (sc->sc_imess[3] == 1) { 1820130293Sscottl ti->cfg3 |= NCRFASCFG3_EWIDE; 1821130293Sscottl ncr53c9x_setsync(sc, ti); 1822130293Sscottl } else 1823130293Sscottl ti->width = 0; 1824130293Sscottl /* 1825130293Sscottl * Device started width negotiation. 1826130293Sscottl */ 1827130293Sscottl if (!(ti->flags & T_WDTRSENT)) 1828130293Sscottl ncr53c9x_sched_msgout(SEND_WDTR); 1829130293Sscottl ti->flags &= ~(T_WIDE | T_WDTRSENT); 1830130293Sscottl break; 1831130293Sscottl default: 1832130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 1833130293Sscottl printf("unrecognized MESSAGE EXTENDED;" 1834130293Sscottl " sending REJECT\n"); 1835130293Sscottl goto reject; 1836130293Sscottl } 1837130293Sscottl break; 1838130293Sscottl 1839130293Sscottl default: 1840130293Sscottl NCR_MSGS(("ident ")); 1841130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 1842130293Sscottl printf("unrecognized MESSAGE; sending REJECT\n"); 1843130293Sscottl reject: 1844130293Sscottl ncr53c9x_sched_msgout(SEND_REJECT); 1845130293Sscottl break; 1846130293Sscottl } 1847130293Sscottl break; 1848130293Sscottl 1849130293Sscottl case NCR_IDENTIFIED: 1850130293Sscottl /* 1851130293Sscottl * IDENTIFY message was received and queue tag is expected now 1852145202Smarius */ 1853130293Sscottl if ((sc->sc_imess[0] != MSG_SIMPLE_Q_TAG) || 1854130293Sscottl (sc->sc_msgify == 0)) { 1855130293Sscottl device_printf(sc->sc_dev, "TAG reselect without " 1856130293Sscottl "IDENTIFY; MSG %x; sending DEVICE RESET\n", 1857130293Sscottl sc->sc_imess[0]); 1858130293Sscottl goto reset; 1859130293Sscottl } 1860130293Sscottl (void) ncr53c9x_reselect(sc, sc->sc_msgify, 1861130293Sscottl sc->sc_imess[0], sc->sc_imess[1]); 1862130293Sscottl break; 1863130293Sscottl 1864130293Sscottl case NCR_RESELECTED: 1865130293Sscottl if (MSG_ISIDENTIFY(sc->sc_imess[1])) { 1866130293Sscottl sc->sc_msgify = sc->sc_imess[1]; 1867130293Sscottl } else { 1868130293Sscottl device_printf(sc->sc_dev, "reselect without IDENTIFY;" 1869130293Sscottl " MSG %x; sending DEVICE RESET\n", sc->sc_imess[1]); 1870130293Sscottl goto reset; 1871130293Sscottl } 1872130293Sscottl (void) ncr53c9x_reselect(sc, sc->sc_msgify, 0, 0); 1873130293Sscottl break; 1874130293Sscottl 1875130293Sscottl default: 1876130293Sscottl device_printf(sc->sc_dev, "unexpected MESSAGE IN; " 1877130293Sscottl "sending DEVICE RESET\n"); 1878130293Sscottl reset: 1879130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 1880130293Sscottl break; 1881130293Sscottl 1882130293Sscottl abort: 1883130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 1884130293Sscottl break; 1885130293Sscottl } 1886130293Sscottl 1887130293Sscottl /* if we have more messages to send set ATN */ 1888130293Sscottl if (sc->sc_msgpriq) 1889130293Sscottl NCRCMD(sc, NCRCMD_SETATN); 1890130293Sscottl 1891130293Sscottl /* Ack last message byte */ 1892130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 1893130293Sscottl 1894130293Sscottl /* Done, reset message pointer. */ 1895130293Sscottl sc->sc_flags &= ~NCR_DROP_MSGI; 1896130293Sscottl sc->sc_imlen = 0; 1897130293Sscottl} 1898130293Sscottl 1899130293Sscottl 1900130293Sscottl/* 1901130293Sscottl * Send the highest priority, scheduled message 1902130293Sscottl */ 1903130293Sscottlstatic void 1904130293Sscottlncr53c9x_msgout(struct ncr53c9x_softc *sc) 1905130293Sscottl{ 1906130293Sscottl struct ncr53c9x_tinfo *ti; 1907130293Sscottl struct ncr53c9x_ecb *ecb; 1908130293Sscottl size_t size; 1909130293Sscottl 1910130293Sscottl NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]", 1911130293Sscottl sc->sc_msgpriq, sc->sc_prevphase)); 1912130293Sscottl 1913130293Sscottl /* 1914130293Sscottl * XXX - the NCR_ATN flag is not in sync with the actual ATN 1915130293Sscottl * condition on the SCSI bus. The 53c9x chip 1916130293Sscottl * automatically turns off ATN before sending the 1917133039Strhodes * message byte. (See also the comment below in the 1918133039Strhodes * default case when picking out a message to send.) 1919130293Sscottl */ 1920130293Sscottl if (sc->sc_flags & NCR_ATN) { 1921130293Sscottl if (sc->sc_prevphase != MESSAGE_OUT_PHASE) { 1922130293Sscottl new: 1923130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 1924130293Sscottl/* DELAY(1); */ 1925130293Sscottl sc->sc_msgoutq = 0; 1926130293Sscottl sc->sc_omlen = 0; 1927130293Sscottl } 1928130293Sscottl } else { 1929130293Sscottl if (sc->sc_prevphase == MESSAGE_OUT_PHASE) { 1930130293Sscottl ncr53c9x_sched_msgout(sc->sc_msgoutq); 1931130293Sscottl goto new; 1932130293Sscottl } else { 1933130293Sscottl device_printf(sc->sc_dev, "at line %d: unexpected " 1934130293Sscottl "MESSAGE OUT phase\n", __LINE__); 1935130293Sscottl } 1936130293Sscottl } 1937130293Sscottl 1938130293Sscottl if (sc->sc_omlen == 0) { 1939130293Sscottl /* Pick up highest priority message */ 1940130293Sscottl sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; 1941130293Sscottl sc->sc_msgoutq |= sc->sc_msgout; 1942130293Sscottl sc->sc_msgpriq &= ~sc->sc_msgout; 1943130293Sscottl sc->sc_omlen = 1; /* "Default" message len */ 1944130293Sscottl switch (sc->sc_msgout) { 1945130293Sscottl case SEND_SDTR: 1946130293Sscottl ecb = sc->sc_nexus; 1947130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1948130293Sscottl sc->sc_omess[0] = MSG_EXTENDED; 1949130293Sscottl sc->sc_omess[1] = MSG_EXT_SDTR_LEN; 1950130293Sscottl sc->sc_omess[2] = MSG_EXT_SDTR; 1951130293Sscottl sc->sc_omess[3] = ti->period; 1952130293Sscottl sc->sc_omess[4] = ti->offset; 1953130293Sscottl sc->sc_omlen = 5; 1954130293Sscottl if ((sc->sc_flags & NCR_SYNCHNEGO) == 0) { 1955130293Sscottl ti->flags |= T_SYNCMODE; 1956130293Sscottl ncr53c9x_setsync(sc, ti); 1957130293Sscottl } 1958130293Sscottl break; 1959130293Sscottl case SEND_WDTR: 1960130293Sscottl ecb = sc->sc_nexus; 1961130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1962130293Sscottl sc->sc_omess[0] = MSG_EXTENDED; 1963130293Sscottl sc->sc_omess[1] = MSG_EXT_WDTR_LEN; 1964130293Sscottl sc->sc_omess[2] = MSG_EXT_WDTR; 1965130293Sscottl sc->sc_omess[3] = ti->width; 1966130293Sscottl sc->sc_omlen = 4; 1967130293Sscottl break; 1968130293Sscottl case SEND_IDENTIFY: 1969130293Sscottl if (sc->sc_state != NCR_CONNECTED) { 1970130293Sscottl device_printf(sc->sc_dev, "at line %d: no " 1971130293Sscottl "nexus\n", __LINE__); 1972130293Sscottl } 1973130293Sscottl ecb = sc->sc_nexus; 1974130293Sscottl sc->sc_omess[0] = 1975130293Sscottl MSG_IDENTIFY(ecb->ccb->ccb_h.target_lun, 0); 1976130293Sscottl break; 1977130293Sscottl case SEND_TAG: 1978130293Sscottl if (sc->sc_state != NCR_CONNECTED) { 1979130293Sscottl device_printf(sc->sc_dev, "at line %d: no " 1980130293Sscottl "nexus\n", __LINE__); 1981130293Sscottl } 1982130293Sscottl ecb = sc->sc_nexus; 1983130293Sscottl sc->sc_omess[0] = ecb->tag[0]; 1984130293Sscottl sc->sc_omess[1] = ecb->tag[1]; 1985130293Sscottl sc->sc_omlen = 2; 1986130293Sscottl break; 1987130293Sscottl case SEND_DEV_RESET: 1988130293Sscottl sc->sc_flags |= NCR_ABORTING; 1989130293Sscottl sc->sc_omess[0] = MSG_BUS_DEV_RESET; 1990130293Sscottl ecb = sc->sc_nexus; 1991130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1992130293Sscottl ti->flags &= ~T_SYNCMODE; 1993130293Sscottl if ((ti->flags & T_SYNCHOFF) == 0) 1994130293Sscottl /* We can re-start sync negotiation */ 1995130293Sscottl ti->flags |= T_NEGOTIATE; 1996130293Sscottl break; 1997130293Sscottl case SEND_PARITY_ERROR: 1998130293Sscottl sc->sc_omess[0] = MSG_PARITY_ERROR; 1999130293Sscottl break; 2000130293Sscottl case SEND_ABORT: 2001130293Sscottl sc->sc_flags |= NCR_ABORTING; 2002130293Sscottl sc->sc_omess[0] = MSG_ABORT; 2003130293Sscottl break; 2004130293Sscottl case SEND_INIT_DET_ERR: 2005130293Sscottl sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; 2006130293Sscottl break; 2007130293Sscottl case SEND_REJECT: 2008130293Sscottl sc->sc_omess[0] = MSG_MESSAGE_REJECT; 2009130293Sscottl break; 2010130293Sscottl default: 2011130293Sscottl /* 2012130293Sscottl * We normally do not get here, since the chip 2013130293Sscottl * automatically turns off ATN before the last 2014130293Sscottl * byte of a message is sent to the target. 2015130293Sscottl * However, if the target rejects our (multi-byte) 2016130293Sscottl * message early by switching to MSG IN phase 2017130293Sscottl * ATN remains on, so the target may return to 2018130293Sscottl * MSG OUT phase. If there are no scheduled messages 2019130293Sscottl * left we send a NO-OP. 2020130293Sscottl * 2021130293Sscottl * XXX - Note that this leaves no useful purpose for 2022130293Sscottl * the NCR_ATN flag. 2023130293Sscottl */ 2024130293Sscottl sc->sc_flags &= ~NCR_ATN; 2025130293Sscottl sc->sc_omess[0] = MSG_NOOP; 2026130293Sscottl break; 2027130293Sscottl } 2028130293Sscottl sc->sc_omp = sc->sc_omess; 2029130293Sscottl } 2030130293Sscottl 2031130293Sscottl#ifdef DEBUG 2032130293Sscottl if (ncr53c9x_debug & NCR_SHOWMSGS) { 2033130293Sscottl int i; 2034145202Smarius 2035130293Sscottl NCR_MSGS(("<msgout:")); 2036145202Smarius for (i = 0; i < sc->sc_omlen; i++) 2037130293Sscottl NCR_MSGS((" %02x", sc->sc_omess[i])); 2038130293Sscottl NCR_MSGS(("> ")); 2039130293Sscottl } 2040130293Sscottl#endif 2041130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 2042145202Smarius /* 2043130293Sscottl * XXX fifo size 2044130293Sscottl */ 2045130293Sscottl ncr53c9x_flushfifo(sc); 2046130293Sscottl ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen); 2047130293Sscottl NCRCMD(sc, NCRCMD_TRANS); 2048130293Sscottl } else { 2049130293Sscottl /* (re)send the message */ 2050130293Sscottl size = min(sc->sc_omlen, sc->sc_maxxfer); 2051130293Sscottl NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size); 2052130293Sscottl /* Program the SCSI counter */ 2053130293Sscottl NCR_SET_COUNT(sc, size); 2054130293Sscottl 2055130293Sscottl /* Load the count in and start the message-out transfer */ 2056130293Sscottl NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA); 2057130293Sscottl NCRCMD(sc, NCRCMD_TRANS|NCRCMD_DMA); 2058130293Sscottl NCRDMA_GO(sc); 2059130293Sscottl } 2060130293Sscottl} 2061130293Sscottl 2062130293Sscottl/* 2063130293Sscottl * This is the most critical part of the driver, and has to know 2064130293Sscottl * how to deal with *all* error conditions and phases from the SCSI 2065130293Sscottl * bus. If there are no errors and the DMA was active, then call the 2066130293Sscottl * DMA pseudo-interrupt handler. If this returns 1, then that was it 2067130293Sscottl * and we can return from here without further processing. 2068130293Sscottl * 2069130293Sscottl * Most of this needs verifying. 2070130293Sscottl */ 2071130293Sscottlvoid 2072130293Sscottlncr53c9x_intr(void *arg) 2073130293Sscottl{ 2074130293Sscottl struct ncr53c9x_softc *sc = arg; 2075130293Sscottl struct ncr53c9x_ecb *ecb; 2076130293Sscottl struct ncr53c9x_tinfo *ti; 2077130293Sscottl size_t size; 2078130293Sscottl int nfifo; 2079130293Sscottl 2080130293Sscottl NCR_INTS(("[ncr53c9x_intr: state %d]", sc->sc_state)); 2081130293Sscottl 2082130293Sscottl if (!NCRDMA_ISINTR(sc)) 2083130293Sscottl return; 2084130293Sscottl 2085130293Sscottl mtx_lock(&sc->sc_lock); 2086130293Sscottlagain: 2087130293Sscottl /* and what do the registers say... */ 2088130293Sscottl ncr53c9x_readregs(sc); 2089130293Sscottl 2090130293Sscottl /* 2091130293Sscottl * At the moment, only a SCSI Bus Reset or Illegal 2092130293Sscottl * Command are classed as errors. A disconnect is a 2093130293Sscottl * valid condition, and we let the code check is the 2094130293Sscottl * "NCR_BUSFREE_OK" flag was set before declaring it 2095130293Sscottl * and error. 2096130293Sscottl * 2097130293Sscottl * Also, the status register tells us about "Gross 2098130293Sscottl * Errors" and "Parity errors". Only the Gross Error 2099130293Sscottl * is really bad, and the parity errors are dealt 2100130293Sscottl * with later 2101130293Sscottl * 2102130293Sscottl * TODO 2103130293Sscottl * If there are too many parity error, go to slow 2104130293Sscottl * cable mode ? 2105130293Sscottl */ 2106130293Sscottl 2107130293Sscottl /* SCSI Reset */ 2108130293Sscottl if ((sc->sc_espintr & NCRINTR_SBR) != 0) { 2109130293Sscottl if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) != 0) { 2110130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2111130293Sscottl DELAY(1); 2112130293Sscottl } 2113130293Sscottl if (sc->sc_state != NCR_SBR) { 2114130293Sscottl device_printf(sc->sc_dev, "SCSI bus reset\n"); 2115130293Sscottl ncr53c9x_init(sc, 0); /* Restart everything */ 2116130293Sscottl goto out; 2117130293Sscottl } 2118130293Sscottl#if 0 2119130293Sscottl/*XXX*/ printf("<expected bus reset: " 2120130293Sscottl "[intr %x, stat %x, step %d]>\n", 2121130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2122130293Sscottl#endif 2123130293Sscottl if (sc->sc_nexus != NULL) 2124130293Sscottl panic("%s: nexus in reset state", 2125130293Sscottl device_get_nameunit(sc->sc_dev)); 2126130293Sscottl goto sched; 2127130293Sscottl } 2128130293Sscottl 2129130293Sscottl ecb = sc->sc_nexus; 2130130293Sscottl 2131130293Sscottl#define NCRINTR_ERR (NCRINTR_SBR|NCRINTR_ILL) 2132130293Sscottl if (sc->sc_espintr & NCRINTR_ERR || 2133130293Sscottl sc->sc_espstat & NCRSTAT_GE) { 2134130293Sscottl 2135130293Sscottl if ((sc->sc_espstat & NCRSTAT_GE) != 0) { 2136130293Sscottl /* Gross Error; no target ? */ 2137130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2138130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2139130293Sscottl DELAY(1); 2140130293Sscottl } 2141130293Sscottl if (sc->sc_state == NCR_CONNECTED || 2142130293Sscottl sc->sc_state == NCR_SELECTING) { 2143130293Sscottl ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2144130293Sscottl ncr53c9x_done(sc, ecb); 2145130293Sscottl } 2146130293Sscottl goto out; 2147130293Sscottl } 2148130293Sscottl 2149130293Sscottl if ((sc->sc_espintr & NCRINTR_ILL) != 0) { 2150130293Sscottl if ((sc->sc_flags & NCR_EXPECT_ILLCMD) != 0) { 2151130293Sscottl /* 2152130293Sscottl * Eat away "Illegal command" interrupt 2153130293Sscottl * on a ESP100 caused by a re-selection 2154130293Sscottl * while we were trying to select 2155130293Sscottl * another target. 2156130293Sscottl */ 2157130293Sscottl#ifdef DEBUG 2158130293Sscottl device_printf(sc->sc_dev, "ESP100 work-around " 2159130293Sscottl "activated\n"); 2160130293Sscottl#endif 2161130293Sscottl sc->sc_flags &= ~NCR_EXPECT_ILLCMD; 2162130293Sscottl goto out; 2163130293Sscottl } 2164130293Sscottl /* illegal command, out of sync ? */ 2165130293Sscottl device_printf(sc->sc_dev, "illegal command: 0x%x " 2166130293Sscottl "(state %d, phase %x, prevphase %x)\n", 2167130293Sscottl sc->sc_lastcmd, 2168130293Sscottl sc->sc_state, sc->sc_phase, sc->sc_prevphase); 2169130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2170130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2171130293Sscottl DELAY(1); 2172130293Sscottl } 2173130293Sscottl ncr53c9x_init(sc, 1); /* Restart everything */ 2174130293Sscottl goto out; 2175130293Sscottl } 2176130293Sscottl } 2177130293Sscottl sc->sc_flags &= ~NCR_EXPECT_ILLCMD; 2178130293Sscottl 2179130293Sscottl /* 2180130293Sscottl * Call if DMA is active. 2181130293Sscottl * 2182130293Sscottl * If DMA_INTR returns true, then maybe go 'round the loop 2183130293Sscottl * again in case there is no more DMA queued, but a phase 2184130293Sscottl * change is expected. 2185130293Sscottl */ 2186130293Sscottl if (NCRDMA_ISACTIVE(sc)) { 2187130293Sscottl int r = NCRDMA_INTR(sc); 2188130293Sscottl if (r == -1) { 2189130293Sscottl device_printf(sc->sc_dev, "DMA error; resetting\n"); 2190130293Sscottl ncr53c9x_init(sc, 1); 2191130293Sscottl goto out; 2192130293Sscottl } 2193130293Sscottl /* If DMA active here, then go back to work... */ 2194130293Sscottl if (NCRDMA_ISACTIVE(sc)) 2195130293Sscottl goto out; 2196130293Sscottl 2197130293Sscottl if ((sc->sc_espstat & NCRSTAT_TC) == 0) { 2198130293Sscottl /* 2199130293Sscottl * DMA not completed. If we can not find a 2200130293Sscottl * acceptable explanation, print a diagnostic. 2201130293Sscottl */ 2202130293Sscottl if (sc->sc_state == NCR_SELECTING) 2203130293Sscottl /* 2204130293Sscottl * This can happen if we are reselected 2205130293Sscottl * while using DMA to select a target. 2206130293Sscottl */ 2207130293Sscottl /*void*/; 2208130293Sscottl else if (sc->sc_prevphase == MESSAGE_OUT_PHASE) { 2209130293Sscottl /* 2210130293Sscottl * Our (multi-byte) message (eg SDTR) was 2211130293Sscottl * interrupted by the target to send 2212130293Sscottl * a MSG REJECT. 2213130293Sscottl * Print diagnostic if current phase 2214130293Sscottl * is not MESSAGE IN. 2215130293Sscottl */ 2216130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) 2217130293Sscottl device_printf(sc->sc_dev,"!TC on MSGOUT" 2218130293Sscottl " [intr %x, stat %x, step %d]" 2219130293Sscottl " prevphase %x, resid %lx\n", 2220130293Sscottl sc->sc_espintr, 2221130293Sscottl sc->sc_espstat, 2222130293Sscottl sc->sc_espstep, 2223130293Sscottl sc->sc_prevphase, 2224130293Sscottl (u_long)sc->sc_omlen); 2225130293Sscottl } else if (sc->sc_dleft == 0) { 2226130293Sscottl /* 2227130293Sscottl * The DMA operation was started for 2228130293Sscottl * a DATA transfer. Print a diagnostic 2229130293Sscottl * if the DMA counter and TC bit 2230130293Sscottl * appear to be out of sync. 2231145386Sscottl * 2232145386Sscottl * XXX This is fatal and usually means that 2233145386Sscottl * the DMA engine is hopelessly out of 2234145386Sscottl * sync with reality. A disk is likely 2235145386Sscottl * getting spammed at this point. 2236130293Sscottl */ 2237130293Sscottl device_printf(sc->sc_dev, "!TC on DATA XFER" 2238130293Sscottl " [intr %x, stat %x, step %d]" 2239130293Sscottl " prevphase %x, resid %x\n", 2240130293Sscottl sc->sc_espintr, 2241130293Sscottl sc->sc_espstat, 2242130293Sscottl sc->sc_espstep, 2243130293Sscottl sc->sc_prevphase, 2244130293Sscottl ecb ? ecb->dleft : -1); 2245145386Sscottl panic("esp: unrecoverable DMA error"); 2246130293Sscottl } 2247130293Sscottl } 2248130293Sscottl } 2249130293Sscottl 2250130293Sscottl /* 2251130293Sscottl * Check for less serious errors. 2252130293Sscottl */ 2253130293Sscottl if ((sc->sc_espstat & NCRSTAT_PE) != 0) { 2254130293Sscottl device_printf(sc->sc_dev, "SCSI bus parity error\n"); 2255130293Sscottl if (sc->sc_prevphase == MESSAGE_IN_PHASE) 2256130293Sscottl ncr53c9x_sched_msgout(SEND_PARITY_ERROR); 2257130293Sscottl else 2258130293Sscottl ncr53c9x_sched_msgout(SEND_INIT_DET_ERR); 2259130293Sscottl } 2260130293Sscottl 2261130293Sscottl if ((sc->sc_espintr & NCRINTR_DIS) != 0) { 2262130293Sscottl sc->sc_msgify = 0; 2263130293Sscottl NCR_INTS(("<DISC [intr %x, stat %x, step %d]>", 2264130293Sscottl sc->sc_espintr,sc->sc_espstat,sc->sc_espstep)); 2265130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2266130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2267130293Sscottl/* DELAY(1); */ 2268130293Sscottl } 2269130293Sscottl /* 2270130293Sscottl * This command must (apparently) be issued within 2271130293Sscottl * 250mS of a disconnect. So here you are... 2272130293Sscottl */ 2273130293Sscottl NCRCMD(sc, NCRCMD_ENSEL); 2274130293Sscottl 2275130293Sscottl switch (sc->sc_state) { 2276130293Sscottl case NCR_RESELECTED: 2277130293Sscottl goto sched; 2278130293Sscottl 2279130293Sscottl case NCR_SELECTING: 2280130293Sscottl { 2281130293Sscottl struct ncr53c9x_linfo *li; 2282130293Sscottl 2283130293Sscottl ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2284130293Sscottl 2285130293Sscottl /* Selection timeout -- discard all LUNs if empty */ 2286130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2287130293Sscottl li = LIST_FIRST(&ti->luns); 2288130293Sscottl while (li != NULL) { 2289130293Sscottl if (li->untagged == NULL && li->used == 0) { 2290130293Sscottl if (li->lun < NCR_NLUN) 2291130293Sscottl ti->lun[li->lun] = NULL; 2292130293Sscottl LIST_REMOVE(li, link); 2293130293Sscottl free(li, M_DEVBUF); 2294130293Sscottl /* 2295130293Sscottl * Restart the search at the beginning 2296130293Sscottl */ 2297130293Sscottl li = LIST_FIRST(&ti->luns); 2298130293Sscottl continue; 2299130293Sscottl } 2300130293Sscottl li = LIST_NEXT(li, link); 2301130293Sscottl } 2302130293Sscottl goto finish; 2303130293Sscottl } 2304130293Sscottl case NCR_CONNECTED: 2305130293Sscottl if ((sc->sc_flags & NCR_SYNCHNEGO) != 0) { 2306130293Sscottl#ifdef NCR53C9X_DEBUG 2307130293Sscottl if (ecb != NULL) 2308130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 2309130293Sscottl printf("sync nego not completed!\n"); 2310130293Sscottl#endif 2311130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2312130293Sscottl sc->sc_flags &= ~NCR_SYNCHNEGO; 2313130293Sscottl ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE); 2314130293Sscottl } 2315130293Sscottl 2316130293Sscottl /* it may be OK to disconnect */ 2317130293Sscottl if ((sc->sc_flags & NCR_ABORTING) == 0) { 2318130293Sscottl /* 2319130293Sscottl * Section 5.1.1 of the SCSI 2 spec 2320130293Sscottl * suggests issuing a REQUEST SENSE 2321130293Sscottl * following an unexpected disconnect. 2322130293Sscottl * Some devices go into a contingent 2323130293Sscottl * allegiance condition when 2324130293Sscottl * disconnecting, and this is necessary 2325130293Sscottl * to clean up their state. 2326130293Sscottl */ 2327130293Sscottl device_printf(sc->sc_dev, "unexpected " 2328130293Sscottl "disconnect [state %d, intr %x, stat %x, " 2329130293Sscottl "phase(c %x, p %x)]; ", sc->sc_state, 2330130293Sscottl sc->sc_espintr, sc->sc_espstat, 2331130293Sscottl sc->sc_phase, sc->sc_prevphase); 2332130293Sscottl 2333130293Sscottl if ((ecb->flags & ECB_SENSE) != 0) { 2334130293Sscottl printf("resetting\n"); 2335130293Sscottl goto reset; 2336130293Sscottl } 2337130293Sscottl printf("sending REQUEST SENSE\n"); 2338130424Sscottl untimeout(ncr53c9x_timeout, ecb, 2339130293Sscottl ecb->ccb->ccb_h.timeout_ch); 2340130293Sscottl ncr53c9x_sense(sc, ecb); 2341130293Sscottl goto out; 2342130293Sscottl } 2343130293Sscottl 2344130293Sscottl ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT; 2345130293Sscottl goto finish; 2346130293Sscottl 2347130293Sscottl case NCR_DISCONNECT: 2348130293Sscottl sc->sc_nexus = NULL; 2349130293Sscottl goto sched; 2350130293Sscottl 2351130293Sscottl case NCR_CMDCOMPLETE: 2352130293Sscottl ecb->ccb->ccb_h.status = CAM_REQ_CMP; 2353130293Sscottl goto finish; 2354130293Sscottl } 2355130293Sscottl } 2356130293Sscottl 2357130293Sscottl switch (sc->sc_state) { 2358130293Sscottl 2359130293Sscottl case NCR_SBR: 2360130293Sscottl device_printf(sc->sc_dev, "waiting for Bus Reset to happen\n"); 2361130293Sscottl goto out; 2362130293Sscottl 2363130293Sscottl case NCR_RESELECTED: 2364130293Sscottl /* 2365130293Sscottl * we must be continuing a message ? 2366130293Sscottl */ 2367130293Sscottl device_printf(sc->sc_dev, "unhandled reselect continuation, " 2368130293Sscottl "state %d, intr %02x\n", sc->sc_state, sc->sc_espintr); 2369130293Sscottl ncr53c9x_init(sc, 1); 2370130293Sscottl goto out; 2371130293Sscottl break; 2372130293Sscottl 2373130293Sscottl case NCR_IDENTIFIED: 2374130293Sscottl ecb = sc->sc_nexus; 2375130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) { 2376130293Sscottl int i = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF); 2377130293Sscottl /* 2378145202Smarius * Things are seriously screwed up. 2379130293Sscottl * Pull the brakes, i.e. reset 2380130293Sscottl */ 2381130293Sscottl device_printf(sc->sc_dev, "target didn't send tag: %d " 2382130293Sscottl "bytes in fifo\n", i); 2383130293Sscottl /* Drain and display fifo */ 2384130293Sscottl while (i-- > 0) 2385130293Sscottl printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO)); 2386130293Sscottl 2387130293Sscottl ncr53c9x_init(sc, 1); 2388130293Sscottl goto out; 2389130293Sscottl } else 2390130293Sscottl goto msgin; 2391130293Sscottl 2392130293Sscottl case NCR_IDLE: 2393130293Sscottl case NCR_SELECTING: 2394130293Sscottl ecb = sc->sc_nexus; 2395130293Sscottl if (sc->sc_espintr & NCRINTR_RESEL) { 2396130293Sscottl sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; 2397130293Sscottl sc->sc_flags = 0; 2398130293Sscottl /* 2399130293Sscottl * If we're trying to select a 2400130293Sscottl * target ourselves, push our command 2401130293Sscottl * back into the ready list. 2402130293Sscottl */ 2403130293Sscottl if (sc->sc_state == NCR_SELECTING) { 2404130293Sscottl NCR_INTS(("backoff selector ")); 2405130424Sscottl untimeout(ncr53c9x_timeout, ecb, 2406130293Sscottl ecb->ccb->ccb_h.timeout_ch); 2407130293Sscottl ncr53c9x_dequeue(sc, ecb); 2408130293Sscottl TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); 2409130293Sscottl ecb->flags |= ECB_READY; 2410130293Sscottl ecb = sc->sc_nexus = NULL; 2411130293Sscottl } 2412130293Sscottl sc->sc_state = NCR_RESELECTED; 2413130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) { 2414130293Sscottl /* 2415145202Smarius * Things are seriously screwed up. 2416130293Sscottl * Pull the brakes, i.e. reset 2417130293Sscottl */ 2418130293Sscottl device_printf(sc->sc_dev, "target didn't " 2419130293Sscottl "identify\n"); 2420130293Sscottl ncr53c9x_init(sc, 1); 2421130293Sscottl goto out; 2422130293Sscottl } 2423130293Sscottl /* 2424130293Sscottl * The C90 only inhibits FIFO writes until reselection 2425133039Strhodes * is complete instead of waiting until the interrupt 2426130293Sscottl * status register has been read. So, if the reselect 2427130293Sscottl * happens while we were entering command bytes (for 2428130293Sscottl * another target) some of those bytes can appear in 2429130293Sscottl * the FIFO here, after the interrupt is taken. 2430130293Sscottl * 2431130293Sscottl * To remedy this situation, pull the Selection ID 2432130293Sscottl * and Identify message from the FIFO directly, and 2433130293Sscottl * ignore any extraneous fifo contents. Also, set 2434130293Sscottl * a flag that allows one Illegal Command Interrupt 2435130293Sscottl * to occur which the chip also generates as a result 2436130293Sscottl * of writing to the FIFO during a reselect. 2437130293Sscottl */ 2438130293Sscottl if (sc->sc_rev == NCR_VARIANT_ESP100) { 2439130293Sscottl nfifo = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF; 2440130293Sscottl sc->sc_imess[0] = NCR_READ_REG(sc, NCR_FIFO); 2441130293Sscottl sc->sc_imess[1] = NCR_READ_REG(sc, NCR_FIFO); 2442130293Sscottl sc->sc_imlen = 2; 2443130293Sscottl if (nfifo != 2) { 2444130293Sscottl /* Flush the rest */ 2445130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2446130293Sscottl } 2447130293Sscottl sc->sc_flags |= NCR_EXPECT_ILLCMD; 2448130293Sscottl if (nfifo > 2) 2449130293Sscottl nfifo = 2; /* We fixed it.. */ 2450130293Sscottl } else 2451130293Sscottl nfifo = ncr53c9x_rdfifo(sc, NCR_RDFIFO_START); 2452130293Sscottl 2453130293Sscottl if (nfifo != 2) { 2454130293Sscottl device_printf(sc->sc_dev, "RESELECT: %d bytes " 2455130293Sscottl "in FIFO! [intr %x, stat %x, step %d, " 2456130293Sscottl "prevphase %x]\n", 2457130293Sscottl nfifo, 2458130293Sscottl sc->sc_espintr, 2459130293Sscottl sc->sc_espstat, 2460130293Sscottl sc->sc_espstep, 2461130293Sscottl sc->sc_prevphase); 2462130293Sscottl ncr53c9x_init(sc, 1); 2463130293Sscottl goto out; 2464130293Sscottl } 2465130293Sscottl sc->sc_selid = sc->sc_imess[0]; 2466130293Sscottl NCR_INTS(("selid=%02x ", sc->sc_selid)); 2467130293Sscottl 2468130293Sscottl /* Handle identify message */ 2469130293Sscottl ncr53c9x_msgin(sc); 2470130293Sscottl 2471130293Sscottl if (sc->sc_state != NCR_CONNECTED && 2472130293Sscottl sc->sc_state != NCR_IDENTIFIED) { 2473130293Sscottl /* IDENTIFY fail?! */ 2474130293Sscottl device_printf(sc->sc_dev, "identify failed, " 2475130293Sscottl "state %d, intr %02x\n", sc->sc_state, 2476130293Sscottl sc->sc_espintr); 2477130293Sscottl ncr53c9x_init(sc, 1); 2478130293Sscottl goto out; 2479130293Sscottl } 2480130293Sscottl goto shortcut; /* ie. next phase expected soon */ 2481130293Sscottl } 2482130293Sscottl 2483130293Sscottl#define NCRINTR_DONE (NCRINTR_FC|NCRINTR_BS) 2484130293Sscottl if ((sc->sc_espintr & NCRINTR_DONE) == NCRINTR_DONE) { 2485130293Sscottl /* 2486130293Sscottl * Arbitration won; examine the `step' register 2487130293Sscottl * to determine how far the selection could progress. 2488130293Sscottl */ 2489130293Sscottl ecb = sc->sc_nexus; 2490130293Sscottl if (ecb == NULL) 2491130293Sscottl panic("ncr53c9x: no nexus"); 2492130293Sscottl 2493130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2494130293Sscottl 2495130293Sscottl switch (sc->sc_espstep) { 2496130293Sscottl case 0: 2497130293Sscottl /* 2498130293Sscottl * The target did not respond with a 2499130293Sscottl * message out phase - probably an old 2500130293Sscottl * device that doesn't recognize ATN. 2501130293Sscottl * Clear ATN and just continue, the 2502130293Sscottl * target should be in the command 2503130293Sscottl * phase. 2504130293Sscottl * XXXX check for command phase? 2505130293Sscottl */ 2506130293Sscottl NCRCMD(sc, NCRCMD_RSTATN); 2507130293Sscottl break; 2508130293Sscottl case 1: 2509130293Sscottl if ((ti->flags & T_NEGOTIATE) == 0 && 2510130293Sscottl ecb->tag[0] == 0) { 2511130293Sscottl device_printf(sc->sc_dev, "step 1 & " 2512130293Sscottl "!NEG\n"); 2513130293Sscottl goto reset; 2514130293Sscottl } 2515130293Sscottl if (sc->sc_phase != MESSAGE_OUT_PHASE) { 2516130293Sscottl device_printf(sc->sc_dev, "!MSGOUT\n"); 2517130293Sscottl goto reset; 2518130293Sscottl } 2519130293Sscottl if (ti->flags & T_WIDE) { 2520130293Sscottl ti->flags |= T_WDTRSENT; 2521130293Sscottl ncr53c9x_sched_msgout(SEND_WDTR); 2522130293Sscottl } 2523130293Sscottl if (ti->flags & T_NEGOTIATE) { 2524130293Sscottl /* Start negotiating */ 2525130293Sscottl sc->sc_flags |= NCR_SYNCHNEGO; 2526130293Sscottl if (ecb->tag[0]) 2527130293Sscottl ncr53c9x_sched_msgout( 2528130293Sscottl SEND_TAG|SEND_SDTR); 2529130293Sscottl else 2530130293Sscottl ncr53c9x_sched_msgout( 2531130293Sscottl SEND_SDTR); 2532130293Sscottl } else { 2533130293Sscottl /* Could not do ATN3 so send TAG */ 2534130293Sscottl ncr53c9x_sched_msgout(SEND_TAG); 2535130293Sscottl } 2536130293Sscottl sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXXX */ 2537130293Sscottl break; 2538130293Sscottl case 3: 2539130293Sscottl /* 2540130293Sscottl * Grr, this is supposed to mean 2541130293Sscottl * "target left command phase prematurely". 2542130293Sscottl * It seems to happen regularly when 2543130293Sscottl * sync mode is on. 2544130293Sscottl * Look at FIFO to see if command went out. 2545130293Sscottl * (Timing problems?) 2546130293Sscottl */ 2547130293Sscottl if (sc->sc_features & NCR_F_DMASELECT) { 2548130293Sscottl if (sc->sc_cmdlen == 0) 2549130293Sscottl /* Hope for the best.. */ 2550130293Sscottl break; 2551130293Sscottl } else if ((NCR_READ_REG(sc, NCR_FFLAG) 2552130293Sscottl & NCRFIFO_FF) == 0) { 2553130293Sscottl /* Hope for the best.. */ 2554130293Sscottl break; 2555130293Sscottl } 2556130293Sscottl printf("(%s:%d:%d): selection failed;" 2557130293Sscottl " %d left in FIFO " 2558130293Sscottl "[intr %x, stat %x, step %d]\n", 2559130293Sscottl device_get_nameunit(sc->sc_dev), 2560130293Sscottl ecb->ccb->ccb_h.target_id, 2561130293Sscottl ecb->ccb->ccb_h.target_lun, 2562130293Sscottl NCR_READ_REG(sc, NCR_FFLAG) 2563130293Sscottl & NCRFIFO_FF, 2564130293Sscottl sc->sc_espintr, sc->sc_espstat, 2565130293Sscottl sc->sc_espstep); 2566130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2567130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 2568130293Sscottl goto out; 2569130293Sscottl case 2: 2570130293Sscottl /* Select stuck at Command Phase */ 2571130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2572130293Sscottl break; 2573130293Sscottl case 4: 2574130293Sscottl if (sc->sc_features & NCR_F_DMASELECT && 2575130293Sscottl sc->sc_cmdlen != 0) 2576130293Sscottl printf("(%s:%d:%d): select; " 2577130293Sscottl "%lu left in DMA buffer " 2578130293Sscottl "[intr %x, stat %x, step %d]\n", 2579130293Sscottl device_get_nameunit(sc->sc_dev), 2580130293Sscottl ecb->ccb->ccb_h.target_id, 2581130293Sscottl ecb->ccb->ccb_h.target_lun, 2582130293Sscottl (u_long)sc->sc_cmdlen, 2583130293Sscottl sc->sc_espintr, 2584130293Sscottl sc->sc_espstat, 2585130293Sscottl sc->sc_espstep); 2586130293Sscottl /* So far, everything went fine */ 2587130293Sscottl break; 2588130293Sscottl } 2589130293Sscottl 2590130293Sscottl sc->sc_prevphase = INVALID_PHASE; /* ?? */ 2591130293Sscottl /* Do an implicit RESTORE POINTERS. */ 2592130293Sscottl sc->sc_dp = ecb->daddr; 2593130293Sscottl sc->sc_dleft = ecb->dleft; 2594130293Sscottl sc->sc_state = NCR_CONNECTED; 2595130293Sscottl break; 2596130293Sscottl 2597130293Sscottl } else { 2598130293Sscottl 2599130293Sscottl device_printf(sc->sc_dev, "unexpected status after " 2600130293Sscottl "select: [intr %x, stat %x, step %x]\n", 2601130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2602130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2603130293Sscottl DELAY(1); 2604130293Sscottl goto reset; 2605130293Sscottl } 2606130293Sscottl if (sc->sc_state == NCR_IDLE) { 2607130293Sscottl device_printf(sc->sc_dev, "stray interrupt\n"); 2608130293Sscottl mtx_unlock(&sc->sc_lock); 2609130293Sscottl return; 2610130293Sscottl } 2611130293Sscottl break; 2612130293Sscottl 2613130293Sscottl case NCR_CONNECTED: 2614130293Sscottl if ((sc->sc_flags & NCR_ICCS) != 0) { 2615130293Sscottl /* "Initiate Command Complete Steps" in progress */ 2616130293Sscottl u_char msg; 2617130293Sscottl 2618130293Sscottl sc->sc_flags &= ~NCR_ICCS; 2619130293Sscottl 2620130293Sscottl if (!(sc->sc_espintr & NCRINTR_DONE)) { 2621130293Sscottl device_printf(sc->sc_dev, "ICCS: " 2622130293Sscottl ": [intr %x, stat %x, step %x]\n", 2623130293Sscottl sc->sc_espintr, sc->sc_espstat, 2624130293Sscottl sc->sc_espstep); 2625130293Sscottl } 2626130293Sscottl ncr53c9x_rdfifo(sc, NCR_RDFIFO_START); 2627130293Sscottl if (sc->sc_imlen < 2) 2628130293Sscottl device_printf(sc->sc_dev, "can't get status, " 2629130293Sscottl "only %d bytes\n", (int)sc->sc_imlen); 2630130293Sscottl ecb->stat = sc->sc_imess[sc->sc_imlen - 2]; 2631130293Sscottl msg = sc->sc_imess[sc->sc_imlen - 1]; 2632130293Sscottl NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg)); 2633130293Sscottl if (msg == MSG_CMDCOMPLETE) { 2634130293Sscottl ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE) 2635130293Sscottl ? 0 : sc->sc_dleft; 2636130293Sscottl if ((ecb->flags & ECB_SENSE) == 0) 2637130293Sscottl ecb->ccb->csio.resid = ecb->dleft; 2638130293Sscottl sc->sc_state = NCR_CMDCOMPLETE; 2639130293Sscottl } else 2640130293Sscottl device_printf(sc->sc_dev, "STATUS_PHASE: " 2641130293Sscottl "msg %d\n", msg); 2642130293Sscottl sc->sc_imlen = 0; 2643130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 2644130293Sscottl goto shortcut; /* ie. wait for disconnect */ 2645130293Sscottl } 2646130293Sscottl break; 2647130293Sscottl 2648130293Sscottl default: 2649130293Sscottl device_printf(sc->sc_dev, "invalid state: %d [intr %x, " 2650130293Sscottl "phase(c %x, p %x)]\n", sc->sc_state, 2651130293Sscottl sc->sc_espintr, sc->sc_phase, sc->sc_prevphase); 2652130293Sscottl goto reset; 2653130293Sscottl } 2654130293Sscottl 2655130293Sscottl /* 2656130293Sscottl * Driver is now in state NCR_CONNECTED, i.e. we 2657130293Sscottl * have a current command working the SCSI bus. 2658130293Sscottl */ 2659130293Sscottl if (sc->sc_state != NCR_CONNECTED || ecb == NULL) { 2660130293Sscottl panic("ncr53c9x: no nexus"); 2661130293Sscottl } 2662130293Sscottl 2663130293Sscottl switch (sc->sc_phase) { 2664130293Sscottl case MESSAGE_OUT_PHASE: 2665130293Sscottl NCR_PHASE(("MESSAGE_OUT_PHASE ")); 2666130293Sscottl ncr53c9x_msgout(sc); 2667130293Sscottl sc->sc_prevphase = MESSAGE_OUT_PHASE; 2668130293Sscottl break; 2669130293Sscottl 2670130293Sscottl case MESSAGE_IN_PHASE: 2671130293Sscottlmsgin: 2672130293Sscottl NCR_PHASE(("MESSAGE_IN_PHASE ")); 2673130293Sscottl if ((sc->sc_espintr & NCRINTR_BS) != 0) { 2674130293Sscottl if ((sc->sc_rev != NCR_VARIANT_FAS366) || 2675130293Sscottl !(sc->sc_espstat2 & NCRFAS_STAT2_EMPTY)) { 2676130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2677130293Sscottl } 2678130293Sscottl sc->sc_flags |= NCR_WAITI; 2679130293Sscottl NCRCMD(sc, NCRCMD_TRANS); 2680130293Sscottl } else if ((sc->sc_espintr & NCRINTR_FC) != 0) { 2681130293Sscottl if ((sc->sc_flags & NCR_WAITI) == 0) { 2682130293Sscottl device_printf(sc->sc_dev, "MSGIN: unexpected " 2683130293Sscottl "FC bit: [intr %x, stat %x, step %x]\n", 2684130293Sscottl sc->sc_espintr, sc->sc_espstat, 2685130293Sscottl sc->sc_espstep); 2686130293Sscottl } 2687130293Sscottl sc->sc_flags &= ~NCR_WAITI; 2688130293Sscottl ncr53c9x_rdfifo(sc, 2689145202Smarius (sc->sc_prevphase == sc->sc_phase) ? 2690130293Sscottl NCR_RDFIFO_CONTINUE : NCR_RDFIFO_START); 2691130293Sscottl ncr53c9x_msgin(sc); 2692130293Sscottl } else { 2693130293Sscottl device_printf(sc->sc_dev, "MSGIN: weird bits: " 2694130293Sscottl "[intr %x, stat %x, step %x]\n", 2695130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2696130293Sscottl } 2697130293Sscottl sc->sc_prevphase = MESSAGE_IN_PHASE; 2698130293Sscottl goto shortcut; /* i.e. expect data to be ready */ 2699130293Sscottl 2700130293Sscottl case COMMAND_PHASE: 2701130293Sscottl /* 2702130293Sscottl * Send the command block. Normally we don't see this 2703130293Sscottl * phase because the SEL_ATN command takes care of 2704130293Sscottl * all this. However, we end up here if either the 2705130293Sscottl * target or we wanted to exchange some more messages 2706130293Sscottl * first (e.g. to start negotiations). 2707130293Sscottl */ 2708130293Sscottl 2709130293Sscottl NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ", 2710130293Sscottl ecb->cmd.cmd.opcode, ecb->clen)); 2711130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2712130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2713130293Sscottl/* DELAY(1);*/ 2714130293Sscottl } 2715130293Sscottl if (sc->sc_features & NCR_F_DMASELECT) { 2716130293Sscottl /* setup DMA transfer for command */ 2717130293Sscottl size = ecb->clen; 2718130293Sscottl sc->sc_cmdlen = size; 2719130293Sscottl sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd; 2720130293Sscottl NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 2721130293Sscottl 0, &size); 2722130293Sscottl /* Program the SCSI counter */ 2723130293Sscottl NCR_SET_COUNT(sc, size); 2724130293Sscottl 2725130293Sscottl /* load the count in */ 2726130293Sscottl NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA); 2727130293Sscottl 2728130293Sscottl /* start the command transfer */ 2729130293Sscottl NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA); 2730130293Sscottl NCRDMA_GO(sc); 2731130293Sscottl } else { 2732130293Sscottl ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen); 2733130293Sscottl NCRCMD(sc, NCRCMD_TRANS); 2734130293Sscottl } 2735130293Sscottl sc->sc_prevphase = COMMAND_PHASE; 2736130293Sscottl break; 2737130293Sscottl 2738130293Sscottl case DATA_OUT_PHASE: 2739130293Sscottl NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft)); 2740130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2741130293Sscottl size = min(sc->sc_dleft, sc->sc_maxxfer); 2742130293Sscottl NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 0, &size); 2743130293Sscottl sc->sc_prevphase = DATA_OUT_PHASE; 2744130293Sscottl goto setup_xfer; 2745130293Sscottl 2746130293Sscottl case DATA_IN_PHASE: 2747130293Sscottl NCR_PHASE(("DATA_IN_PHASE ")); 2748130293Sscottl if (sc->sc_rev == NCR_VARIANT_ESP100) 2749130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2750130293Sscottl size = min(sc->sc_dleft, sc->sc_maxxfer); 2751130293Sscottl NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 1, &size); 2752130293Sscottl sc->sc_prevphase = DATA_IN_PHASE; 2753130293Sscottl setup_xfer: 2754130293Sscottl /* Target returned to data phase: wipe "done" memory */ 2755130293Sscottl ecb->flags &= ~ECB_TENTATIVE_DONE; 2756130293Sscottl 2757130293Sscottl /* Program the SCSI counter */ 2758130293Sscottl NCR_SET_COUNT(sc, size); 2759130293Sscottl 2760130293Sscottl /* load the count in */ 2761130293Sscottl NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA); 2762130293Sscottl 2763130293Sscottl /* 2764130293Sscottl * Note that if `size' is 0, we've already transceived 2765130293Sscottl * all the bytes we want but we're still in DATA PHASE. 2766130293Sscottl * Apparently, the device needs padding. Also, a 2767130293Sscottl * transfer size of 0 means "maximum" to the chip 2768130293Sscottl * DMA logic. 2769130293Sscottl */ 2770130293Sscottl NCRCMD(sc, 2771130293Sscottl (size == 0 ? NCRCMD_TRPAD : NCRCMD_TRANS) | NCRCMD_DMA); 2772130293Sscottl NCRDMA_GO(sc); 2773130293Sscottl goto out; 2774130293Sscottl 2775130293Sscottl case STATUS_PHASE: 2776130293Sscottl NCR_PHASE(("STATUS_PHASE ")); 2777130293Sscottl sc->sc_flags |= NCR_ICCS; 2778130293Sscottl NCRCMD(sc, NCRCMD_ICCS); 2779130293Sscottl sc->sc_prevphase = STATUS_PHASE; 2780130293Sscottl goto shortcut; /* i.e. expect status results soon */ 2781130293Sscottl 2782130293Sscottl case INVALID_PHASE: 2783130293Sscottl break; 2784130293Sscottl 2785130293Sscottl default: 2786130293Sscottl device_printf(sc->sc_dev, "unexpected bus phase; resetting\n"); 2787130293Sscottl goto reset; 2788130293Sscottl } 2789130293Sscottl 2790130293Sscottlout: 2791130293Sscottl mtx_unlock(&sc->sc_lock); 2792130293Sscottl return; 2793130293Sscottl 2794130293Sscottlreset: 2795130293Sscottl ncr53c9x_init(sc, 1); 2796130293Sscottl goto out; 2797130293Sscottl 2798130293Sscottlfinish: 2799130293Sscottl ncr53c9x_done(sc, ecb); 2800130293Sscottl goto out; 2801130293Sscottl 2802130293Sscottlsched: 2803130293Sscottl sc->sc_state = NCR_IDLE; 2804130293Sscottl ncr53c9x_sched(sc); 2805130293Sscottl goto out; 2806130293Sscottl 2807130293Sscottlshortcut: 2808130293Sscottl /* 2809130293Sscottl * The idea is that many of the SCSI operations take very little 2810130293Sscottl * time, and going away and getting interrupted is too high an 2811130293Sscottl * overhead to pay. For example, selecting, sending a message 2812130293Sscottl * and command and then doing some work can be done in one "pass". 2813130293Sscottl * 2814130293Sscottl * The delay is a heuristic. It is 2 when at 20MHz, 2 at 25MHz and 1 2815130293Sscottl * at 40MHz. This needs testing. 2816130293Sscottl */ 2817130293Sscottl { 2818130293Sscottl struct timeval wait, cur; 2819130293Sscottl 2820130293Sscottl microtime(&wait); 2821130293Sscottl wait.tv_usec += 50 / sc->sc_freq; 2822130293Sscottl if (wait.tv_usec > 1000000) { 2823130293Sscottl wait.tv_sec++; 2824130293Sscottl wait.tv_usec -= 1000000; 2825130293Sscottl } 2826130293Sscottl do { 2827130293Sscottl if (NCRDMA_ISINTR(sc)) 2828130293Sscottl goto again; 2829130293Sscottl microtime(&cur); 2830130293Sscottl } while (cur.tv_sec <= wait.tv_sec && 2831130293Sscottl cur.tv_usec <= wait.tv_usec); 2832130293Sscottl } 2833130293Sscottl goto out; 2834130293Sscottl} 2835130293Sscottl 2836130293Sscottlstatic void 2837130293Sscottlncr53c9x_abort(sc, ecb) 2838130293Sscottl struct ncr53c9x_softc *sc; 2839130293Sscottl struct ncr53c9x_ecb *ecb; 2840130293Sscottl{ 2841130293Sscottl 2842130293Sscottl /* 2 secs for the abort */ 2843130293Sscottl ecb->timeout = NCR_ABORT_TIMEOUT; 2844130293Sscottl ecb->flags |= ECB_ABORT; 2845130293Sscottl 2846130293Sscottl if (ecb == sc->sc_nexus) { 2847130293Sscottl /* 2848130293Sscottl * If we're still selecting, the message will be scheduled 2849130293Sscottl * after selection is complete. 2850130293Sscottl */ 2851130293Sscottl if (sc->sc_state == NCR_CONNECTED) 2852130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 2853130293Sscottl 2854130293Sscottl /* 2855130293Sscottl * Reschedule timeout. 2856130293Sscottl */ 2857130293Sscottl ecb->ccb->ccb_h.timeout_ch = 2858130424Sscottl timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout)); 2859130293Sscottl } else { 2860130293Sscottl /* 2861130293Sscottl * Just leave the command where it is. 2862130293Sscottl * XXX - what choice do we have but to reset the SCSI 2863130293Sscottl * eventually? 2864130293Sscottl */ 2865130293Sscottl if (sc->sc_state == NCR_IDLE) 2866130293Sscottl ncr53c9x_sched(sc); 2867130293Sscottl } 2868130293Sscottl} 2869130293Sscottl 2870130293Sscottlstatic void 2871130293Sscottlncr53c9x_timeout(void *arg) 2872130293Sscottl{ 2873130293Sscottl struct ncr53c9x_ecb *ecb = arg; 2874130293Sscottl union ccb *ccb = ecb->ccb; 2875130293Sscottl struct ncr53c9x_softc *sc = ecb->sc; 2876130293Sscottl struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 2877130293Sscottl 2878130293Sscottl xpt_print_path(ccb->ccb_h.path); 2879130293Sscottl device_printf(sc->sc_dev, "timed out [ecb %p (flags 0x%x, dleft %x, " 2880130293Sscottl "stat %x)], <state %d, nexus %p, phase(l %x, c %x, p %x), " 2881130293Sscottl "resid %lx, msg(q %x,o %x) %s>", 2882130293Sscottl ecb, ecb->flags, ecb->dleft, ecb->stat, 2883130293Sscottl sc->sc_state, sc->sc_nexus, 2884130293Sscottl NCR_READ_REG(sc, NCR_STAT), 2885130293Sscottl sc->sc_phase, sc->sc_prevphase, 2886130293Sscottl (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout, 2887130293Sscottl NCRDMA_ISACTIVE(sc) ? "DMA active" : ""); 2888130293Sscottl#if NCR53C9X_DEBUG > 1 2889130293Sscottl printf("TRACE: %s.", ecb->trace); 2890130293Sscottl#endif 2891130293Sscottl 2892130293Sscottl mtx_lock(&sc->sc_lock); 2893130293Sscottl 2894130293Sscottl if (ecb->flags & ECB_ABORT) { 2895130293Sscottl /* abort timed out */ 2896130293Sscottl printf(" AGAIN\n"); 2897130293Sscottl 2898130293Sscottl ncr53c9x_init(sc, 1); 2899130293Sscottl } else { 2900130293Sscottl /* abort the operation that has timed out */ 2901130293Sscottl printf("\n"); 2902130293Sscottl ccb->ccb_h.status = CAM_CMD_TIMEOUT; 2903130293Sscottl ncr53c9x_abort(sc, ecb); 2904130293Sscottl 2905130293Sscottl /* Disable sync mode if stuck in a data phase */ 2906130293Sscottl if (ecb == sc->sc_nexus && 2907130293Sscottl (ti->flags & T_SYNCMODE) != 0 && 2908130293Sscottl (sc->sc_phase & (MSGI|CDI)) == 0) { 2909130293Sscottl /* XXX ASYNC CALLBACK! */ 2910130293Sscottl xpt_print_path(ccb->ccb_h.path); 2911130293Sscottl printf("sync negotiation disabled\n"); 2912130293Sscottl sc->sc_cfflags |= 2913130293Sscottl (1 << ((ccb->ccb_h.target_id & 7) + 8)); 2914130293Sscottl } 2915130293Sscottl } 2916130293Sscottl 2917130293Sscottl mtx_unlock(&sc->sc_lock); 2918130293Sscottl} 2919130293Sscottl 2920130293Sscottlstatic void 2921130293Sscottlncr53c9x_watch(void *arg) 2922130293Sscottl{ 2923130293Sscottl struct ncr53c9x_softc *sc = (struct ncr53c9x_softc *)arg; 2924130293Sscottl struct ncr53c9x_tinfo *ti; 2925130293Sscottl struct ncr53c9x_linfo *li; 2926130293Sscottl int t; 2927130293Sscottl /* Delete any structures that have not been used in 10min. */ 2928130293Sscottl time_t old = time_second - (10 * 60); 2929130293Sscottl 2930130293Sscottl mtx_lock(&sc->sc_lock); 2931130293Sscottl for (t = 0; t < sc->sc_ntarg; t++) { 2932130293Sscottl ti = &sc->sc_tinfo[t]; 2933130293Sscottl li = LIST_FIRST(&ti->luns); 2934130293Sscottl while (li) { 2935130293Sscottl if (li->last_used < old && 2936130293Sscottl li->untagged == NULL && 2937130293Sscottl li->used == 0) { 2938130293Sscottl if (li->lun < NCR_NLUN) 2939130293Sscottl ti->lun[li->lun] = NULL; 2940130293Sscottl LIST_REMOVE(li, link); 2941130293Sscottl free(li, M_DEVBUF); 2942130293Sscottl /* Restart the search at the beginning */ 2943130293Sscottl li = LIST_FIRST(&ti->luns); 2944130293Sscottl continue; 2945130293Sscottl } 2946130293Sscottl li = LIST_NEXT(li, link); 2947130293Sscottl } 2948130293Sscottl } 2949130293Sscottl mtx_unlock(&sc->sc_lock); 2950130293Sscottl callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc); 2951130293Sscottl} 2952