1130293Sscottl/*- 2130293Sscottl * Copyright (c) 2004 Scott Long 3182876Smarius * Copyright (c) 2005, 2008 Marius Strobl <marius@FreeBSD.org> 4130293Sscottl * All rights reserved. 5130293Sscottl * 6130293Sscottl * Redistribution and use in source and binary forms, with or without 7130293Sscottl * modification, are permitted provided that the following conditions 8130293Sscottl * are met: 9130293Sscottl * 1. Redistributions of source code must retain the above copyright 10130293Sscottl * notice, this list of conditions and the following disclaimer. 11130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 12130293Sscottl * notice, this list of conditions and the following disclaimer in the 13130293Sscottl * documentation and/or other materials provided with the distribution. 14130293Sscottl * 15130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16130293Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17130293Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18130293Sscottl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19130293Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20130293Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21130293Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23130293Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24130293Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25130293Sscottl * SUCH DAMAGE. 26130293Sscottl * 27130293Sscottl */ 28130293Sscottl 29239089Smarius/* $NetBSD: ncr53c9x.c,v 1.145 2012/06/18 21:23:56 martin Exp $ */ 30130293Sscottl 31130293Sscottl/*- 32130293Sscottl * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc. 33130293Sscottl * All rights reserved. 34130293Sscottl * 35130293Sscottl * This code is derived from software contributed to The NetBSD Foundation 36130293Sscottl * by Charles M. Hannum. 37130293Sscottl * 38130293Sscottl * Redistribution and use in source and binary forms, with or without 39130293Sscottl * modification, are permitted provided that the following conditions 40130293Sscottl * are met: 41130293Sscottl * 1. Redistributions of source code must retain the above copyright 42130293Sscottl * notice, this list of conditions and the following disclaimer. 43130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 44130293Sscottl * notice, this list of conditions and the following disclaimer in the 45130293Sscottl * documentation and/or other materials provided with the distribution. 46130293Sscottl * 47130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 48130293Sscottl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 49130293Sscottl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 50130293Sscottl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 51130293Sscottl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 52130293Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 53130293Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 54130293Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 55130293Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 56130293Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 57130293Sscottl * POSSIBILITY OF SUCH DAMAGE. 58130293Sscottl */ 59130293Sscottl 60139749Simp/*- 61130293Sscottl * Copyright (c) 1994 Peter Galbavy 62130293Sscottl * Copyright (c) 1995 Paul Kranenburg 63130293Sscottl * All rights reserved. 64130293Sscottl * 65130293Sscottl * Redistribution and use in source and binary forms, with or without 66130293Sscottl * modification, are permitted provided that the following conditions 67130293Sscottl * are met: 68130293Sscottl * 1. Redistributions of source code must retain the above copyright 69130293Sscottl * notice, this list of conditions and the following disclaimer. 70130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright 71130293Sscottl * notice, this list of conditions and the following disclaimer in the 72130293Sscottl * documentation and/or other materials provided with the distribution. 73130293Sscottl * 3. All advertising materials mentioning features or use of this software 74130293Sscottl * must display the following acknowledgement: 75130293Sscottl * This product includes software developed by Peter Galbavy 76130293Sscottl * 4. The name of the author may not be used to endorse or promote products 77130293Sscottl * derived from this software without specific prior written permission. 78130293Sscottl * 79130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 80130293Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 81130293Sscottl * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 82130293Sscottl * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 83130293Sscottl * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 84130293Sscottl * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 85130293Sscottl * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 86130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 87130293Sscottl * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 88130293Sscottl * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 89130293Sscottl * POSSIBILITY OF SUCH DAMAGE. 90130293Sscottl */ 91130293Sscottl 92130293Sscottl/* 93130293Sscottl * Based on aic6360 by Jarle Greipsland 94130293Sscottl * 95130293Sscottl * Acknowledgements: Many of the algorithms used in this driver are 96133039Strhodes * inspired by the work of Julian Elischer (julian@FreeBSD.org) and 97130293Sscottl * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million! 98130293Sscottl */ 99130293Sscottl 100130293Sscottl#include <sys/cdefs.h> 101130293Sscottl__FBSDID("$FreeBSD$"); 102130293Sscottl 103130293Sscottl#include <sys/param.h> 104130293Sscottl#include <sys/systm.h> 105130293Sscottl#include <sys/bus.h> 106130293Sscottl#include <sys/kernel.h> 107130293Sscottl#include <sys/malloc.h> 108130293Sscottl#include <sys/lock.h> 109182876Smarius#include <sys/module.h> 110130293Sscottl#include <sys/mutex.h> 111130293Sscottl#include <sys/queue.h> 112130293Sscottl#include <sys/time.h> 113130293Sscottl#include <sys/callout.h> 114130293Sscottl 115130293Sscottl#include <cam/cam.h> 116130293Sscottl#include <cam/cam_ccb.h> 117130293Sscottl#include <cam/cam_debug.h> 118130293Sscottl#include <cam/cam_sim.h> 119130293Sscottl#include <cam/cam_xpt_sim.h> 120130293Sscottl#include <cam/scsi/scsi_all.h> 121130293Sscottl#include <cam/scsi/scsi_message.h> 122130293Sscottl 123130293Sscottl#include <dev/esp/ncr53c9xreg.h> 124130293Sscottl#include <dev/esp/ncr53c9xvar.h> 125130293Sscottl 126226947Smariusdevclass_t esp_devclass; 127226947Smarius 128182876SmariusMODULE_DEPEND(esp, cam, 1, 1, 1); 129182876Smarius 130182876Smarius#ifdef NCR53C9X_DEBUG 131226381Smariusint ncr53c9x_debug = 132180692Smarius NCR_SHOWMISC /* | NCR_SHOWPHASE | NCR_SHOWTRAC | NCR_SHOWCMDS */; 133130293Sscottl#endif 134130293Sscottl 135180692Smariusstatic void ncr53c9x_abort(struct ncr53c9x_softc *sc, 136180692Smarius struct ncr53c9x_ecb *ecb); 137182876Smariusstatic void ncr53c9x_action(struct cam_sim *sim, union ccb *ccb); 138182876Smariusstatic void ncr53c9x_async(void *cbarg, uint32_t code, 139182876Smarius struct cam_path *path, void *arg); 140182876Smariusstatic void ncr53c9x_callout(void *arg); 141182876Smariusstatic void ncr53c9x_clear(struct ncr53c9x_softc *sc, cam_status result); 142182876Smariusstatic void ncr53c9x_clear_target(struct ncr53c9x_softc *sc, int target, 143182876Smarius cam_status result); 144180692Smariusstatic void ncr53c9x_dequeue(struct ncr53c9x_softc *sc, 145180692Smarius struct ncr53c9x_ecb *ecb); 146180692Smariusstatic void ncr53c9x_done(struct ncr53c9x_softc *sc, 147180692Smarius struct ncr53c9x_ecb *ecb); 148180692Smariusstatic void ncr53c9x_free_ecb(struct ncr53c9x_softc *sc, 149180692Smarius struct ncr53c9x_ecb *ecb); 150180692Smariusstatic void ncr53c9x_msgin(struct ncr53c9x_softc *sc); 151180692Smariusstatic void ncr53c9x_msgout(struct ncr53c9x_softc *sc); 152182876Smariusstatic void ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset); 153182876Smariusstatic void ncr53c9x_intr1(struct ncr53c9x_softc *sc); 154180692Smariusstatic void ncr53c9x_poll(struct cam_sim *sim); 155180692Smariusstatic int ncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how); 156180692Smariusstatic int ncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, 157180692Smarius int tagtype, int tagid); 158182876Smariusstatic void ncr53c9x_reset(struct ncr53c9x_softc *sc); 159180692Smariusstatic void ncr53c9x_sense(struct ncr53c9x_softc *sc, 160180692Smarius struct ncr53c9x_ecb *ecb); 161180692Smariusstatic void ncr53c9x_sched(struct ncr53c9x_softc *sc); 162180692Smariusstatic void ncr53c9x_select(struct ncr53c9x_softc *sc, 163180692Smarius struct ncr53c9x_ecb *ecb); 164130293Sscottlstatic void ncr53c9x_watch(void *arg); 165226381Smariusstatic void ncr53c9x_wrfifo(struct ncr53c9x_softc *sc, uint8_t *p, 166180692Smarius int len); 167130293Sscottl 168180692Smariusstatic struct ncr53c9x_ecb *ncr53c9x_get_ecb(struct ncr53c9x_softc *sc); 169180692Smariusstatic struct ncr53c9x_linfo *ncr53c9x_lunsearch(struct ncr53c9x_tinfo *sc, 170180692Smarius int64_t lun); 171130293Sscottl 172180692Smariusstatic inline void ncr53c9x_readregs(struct ncr53c9x_softc *sc); 173180692Smariusstatic inline void ncr53c9x_setsync(struct ncr53c9x_softc *sc, 174180692Smarius struct ncr53c9x_tinfo *ti); 175180692Smariusstatic inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, 176180692Smarius int period); 177130293Sscottl 178180692Smarius#define NCR_RDFIFO_START 0 179180692Smarius#define NCR_RDFIFO_CONTINUE 1 180130293Sscottl 181180692Smarius#define NCR_SET_COUNT(sc, size) do { \ 182180692Smarius NCR_WRITE_REG((sc), NCR_TCL, (size)); \ 183130293Sscottl NCR_WRITE_REG((sc), NCR_TCM, (size) >> 8); \ 184226947Smarius if ((sc->sc_features & NCR_F_LARGEXFER) != 0) \ 185130293Sscottl NCR_WRITE_REG((sc), NCR_TCH, (size) >> 16); \ 186226381Smarius if (sc->sc_rev == NCR_VARIANT_FAS366) \ 187130293Sscottl NCR_WRITE_REG(sc, NCR_RCH, 0); \ 188226381Smarius} while (/* CONSTCOND */0) 189130293Sscottl 190130293Sscottl#ifndef mstohz 191180692Smarius#define mstohz(ms) \ 192180692Smarius (((ms) < 0x20000) ? \ 193130293Sscottl ((ms +0u) / 1000u) * hz : \ 194130293Sscottl ((ms +0u) * hz) /1000u) 195130293Sscottl#endif 196130293Sscottl 197130293Sscottl/* 198145202Smarius * Names for the NCR53c9x variants, corresponding to the variant tags 199130293Sscottl * in ncr53c9xvar.h. 200130293Sscottl */ 201130293Sscottlstatic const char *ncr53c9x_variant_names[] = { 202130293Sscottl "ESP100", 203130293Sscottl "ESP100A", 204130293Sscottl "ESP200", 205130293Sscottl "NCR53C94", 206130293Sscottl "NCR53C96", 207130293Sscottl "ESP406", 208130293Sscottl "FAS408", 209130293Sscottl "FAS216", 210130293Sscottl "AM53C974", 211130293Sscottl "FAS366/HME", 212130293Sscottl "NCR53C90 (86C01)", 213146392Smarius "FAS100A", 214146392Smarius "FAS236", 215130293Sscottl}; 216130293Sscottl 217130293Sscottl/* 218130293Sscottl * Search linked list for LUN info by LUN id. 219130293Sscottl */ 220130293Sscottlstatic struct ncr53c9x_linfo * 221130293Sscottlncr53c9x_lunsearch(struct ncr53c9x_tinfo *ti, int64_t lun) 222130293Sscottl{ 223130293Sscottl struct ncr53c9x_linfo *li; 224180692Smarius 225130293Sscottl LIST_FOREACH(li, &ti->luns, link) 226130293Sscottl if (li->lun == lun) 227130293Sscottl return (li); 228130293Sscottl return (NULL); 229130293Sscottl} 230130293Sscottl 231130293Sscottl/* 232133039Strhodes * Attach this instance, and then all the sub-devices. 233130293Sscottl */ 234130293Sscottlint 235130293Sscottlncr53c9x_attach(struct ncr53c9x_softc *sc) 236130293Sscottl{ 237130293Sscottl struct cam_devq *devq; 238130293Sscottl struct cam_sim *sim; 239130293Sscottl struct cam_path *path; 240130406Sscottl struct ncr53c9x_ecb *ecb; 241146392Smarius int error, i; 242130293Sscottl 243182876Smarius if (NCR_LOCK_INITIALIZED(sc) == 0) { 244182876Smarius device_printf(sc->sc_dev, "mutex not initialized\n"); 245182876Smarius return (ENXIO); 246182876Smarius } 247130293Sscottl 248182876Smarius callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0); 249182876Smarius 250130293Sscottl /* 251130293Sscottl * Note, the front-end has set us up to print the chip variation. 252130293Sscottl */ 253130293Sscottl if (sc->sc_rev >= NCR_VARIANT_MAX) { 254130293Sscottl device_printf(sc->sc_dev, "unknown variant %d, devices not " 255130293Sscottl "attached\n", sc->sc_rev); 256130293Sscottl return (EINVAL); 257130293Sscottl } 258130293Sscottl 259239089Smarius device_printf(sc->sc_dev, "%s, %d MHz, SCSI ID %d\n", 260130293Sscottl ncr53c9x_variant_names[sc->sc_rev], sc->sc_freq, sc->sc_id); 261130293Sscottl 262130293Sscottl sc->sc_ntarg = (sc->sc_rev == NCR_VARIANT_FAS366) ? 16 : 8; 263130293Sscottl 264130293Sscottl /* 265130293Sscottl * Allocate SCSI message buffers. 266130293Sscottl * Front-ends can override allocation to avoid alignment 267180692Smarius * handling in the DMA engines. Note that ncr53c9x_msgout() 268130293Sscottl * can request a 1 byte DMA transfer. 269130293Sscottl */ 270146392Smarius if (sc->sc_omess == NULL) { 271146392Smarius sc->sc_omess_self = 1; 272130293Sscottl sc->sc_omess = malloc(NCR_MAX_MSG_LEN, M_DEVBUF, M_NOWAIT); 273146392Smarius if (sc->sc_omess == NULL) { 274146392Smarius device_printf(sc->sc_dev, 275146392Smarius "cannot allocate MSGOUT buffer\n"); 276146392Smarius return (ENOMEM); 277146392Smarius } 278146392Smarius } else 279146392Smarius sc->sc_omess_self = 0; 280130293Sscottl 281146392Smarius if (sc->sc_imess == NULL) { 282146392Smarius sc->sc_imess_self = 1; 283130293Sscottl sc->sc_imess = malloc(NCR_MAX_MSG_LEN + 1, M_DEVBUF, M_NOWAIT); 284146392Smarius if (sc->sc_imess == NULL) { 285146392Smarius device_printf(sc->sc_dev, 286146392Smarius "cannot allocate MSGIN buffer\n"); 287146392Smarius error = ENOMEM; 288146392Smarius goto fail_omess; 289146392Smarius } 290146392Smarius } else 291146392Smarius sc->sc_imess_self = 0; 292130293Sscottl 293130293Sscottl sc->sc_tinfo = malloc(sc->sc_ntarg * sizeof(sc->sc_tinfo[0]), 294130293Sscottl M_DEVBUF, M_NOWAIT | M_ZERO); 295146392Smarius if (sc->sc_tinfo == NULL) { 296146392Smarius device_printf(sc->sc_dev, 297146392Smarius "cannot allocate target info buffer\n"); 298146392Smarius error = ENOMEM; 299146392Smarius goto fail_imess; 300130293Sscottl } 301130293Sscottl 302130293Sscottl /* 303130293Sscottl * Treat NCR53C90 with the 86C01 DMA chip exactly as ESP100 304130293Sscottl * from now on. 305130293Sscottl */ 306130293Sscottl if (sc->sc_rev == NCR_VARIANT_NCR53C90_86C01) 307130293Sscottl sc->sc_rev = NCR_VARIANT_ESP100; 308130293Sscottl 309130293Sscottl sc->sc_ccf = FREQTOCCF(sc->sc_freq); 310130293Sscottl 311180692Smarius /* The value *must not* be == 1. Make it 2. */ 312130293Sscottl if (sc->sc_ccf == 1) 313130293Sscottl sc->sc_ccf = 2; 314130293Sscottl 315130293Sscottl /* 316180692Smarius * The recommended timeout is 250ms. This register is loaded 317130293Sscottl * with a value calculated as follows, from the docs: 318130293Sscottl * 319228526Skevlo * (timeout period) x (CLK frequency) 320130293Sscottl * reg = ------------------------------------- 321130293Sscottl * 8192 x (Clock Conversion Factor) 322130293Sscottl * 323130293Sscottl * Since CCF has a linear relation to CLK, this generally computes 324130293Sscottl * to the constant of 153. 325130293Sscottl */ 326130293Sscottl sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf); 327130293Sscottl 328180692Smarius /* The CCF register only has 3 bits; 0 is actually 8. */ 329130293Sscottl sc->sc_ccf &= 7; 330130293Sscottl 331130293Sscottl /* 332180692Smarius * Register with CAM. 333130293Sscottl */ 334130293Sscottl devq = cam_simq_alloc(sc->sc_ntarg); 335146392Smarius if (devq == NULL) { 336146392Smarius device_printf(sc->sc_dev, "cannot allocate device queue\n"); 337146392Smarius error = ENOMEM; 338146392Smarius goto fail_tinfo; 339146392Smarius } 340130293Sscottl 341130293Sscottl sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc, 342182876Smarius device_get_unit(sc->sc_dev), &sc->sc_lock, 1, NCR_TAG_DEPTH, devq); 343130293Sscottl if (sim == NULL) { 344146392Smarius device_printf(sc->sc_dev, "cannot allocate SIM entry\n"); 345146392Smarius error = ENOMEM; 346146392Smarius goto fail_devq; 347130293Sscottl } 348182876Smarius 349182876Smarius NCR_LOCK(sc); 350182876Smarius 351170872Sscottl if (xpt_bus_register(sim, sc->sc_dev, 0) != CAM_SUCCESS) { 352146392Smarius device_printf(sc->sc_dev, "cannot register bus\n"); 353146392Smarius error = EIO; 354182876Smarius goto fail_lock; 355130293Sscottl } 356130293Sscottl 357130293Sscottl if (xpt_create_path(&path, NULL, cam_sim_path(sim), 358180692Smarius CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 359146392Smarius device_printf(sc->sc_dev, "cannot create path\n"); 360146392Smarius error = EIO; 361146392Smarius goto fail_bus; 362130293Sscottl } 363130293Sscottl 364182876Smarius if (xpt_register_async(AC_LOST_DEVICE, ncr53c9x_async, sim, path) != 365182876Smarius CAM_REQ_CMP) { 366182876Smarius device_printf(sc->sc_dev, "cannot register async handler\n"); 367182876Smarius error = EIO; 368182876Smarius goto fail_path; 369182876Smarius } 370182876Smarius 371130293Sscottl sc->sc_sim = sim; 372130293Sscottl sc->sc_path = path; 373130293Sscottl 374180692Smarius /* Reset state and bus. */ 375130293Sscottl#if 0 376130293Sscottl sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; 377180692Smarius#else 378180692Smarius sc->sc_cfflags = 0; 379130293Sscottl#endif 380130293Sscottl sc->sc_state = 0; 381130293Sscottl ncr53c9x_init(sc, 1); 382130293Sscottl 383130406Sscottl TAILQ_INIT(&sc->free_list); 384180692Smarius if ((sc->ecb_array = 385180692Smarius malloc(sizeof(struct ncr53c9x_ecb) * NCR_TAG_DEPTH, M_DEVBUF, 386180692Smarius M_NOWAIT | M_ZERO)) == NULL) { 387145202Smarius device_printf(sc->sc_dev, "cannot allocate ECB array\n"); 388146392Smarius error = ENOMEM; 389182876Smarius goto fail_async; 390130406Sscottl } 391130406Sscottl for (i = 0; i < NCR_TAG_DEPTH; i++) { 392130406Sscottl ecb = &sc->ecb_array[i]; 393130406Sscottl ecb->sc = sc; 394130406Sscottl ecb->tag_id = i; 395226947Smarius callout_init_mtx(&ecb->ch, &sc->sc_lock, 0); 396130406Sscottl TAILQ_INSERT_HEAD(&sc->free_list, ecb, free_links); 397130406Sscottl } 398130406Sscottl 399182876Smarius callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc); 400130293Sscottl 401182876Smarius NCR_UNLOCK(sc); 402182876Smarius 403130293Sscottl return (0); 404146392Smarius 405182876Smariusfail_async: 406182876Smarius xpt_register_async(0, ncr53c9x_async, sim, path); 407146392Smariusfail_path: 408146392Smarius xpt_free_path(path); 409146392Smariusfail_bus: 410146392Smarius xpt_bus_deregister(cam_sim_path(sim)); 411182876Smariusfail_lock: 412182876Smarius NCR_UNLOCK(sc); 413146392Smarius cam_sim_free(sim, TRUE); 414146392Smariusfail_devq: 415146392Smarius cam_simq_free(devq); 416146392Smariusfail_tinfo: 417146392Smarius free(sc->sc_tinfo, M_DEVBUF); 418146392Smariusfail_imess: 419146392Smarius if (sc->sc_imess_self) 420146392Smarius free(sc->sc_imess, M_DEVBUF); 421146392Smariusfail_omess: 422146392Smarius if (sc->sc_omess_self) 423146392Smarius free(sc->sc_omess, M_DEVBUF); 424146392Smarius return (error); 425130293Sscottl} 426130293Sscottl 427130293Sscottlint 428146392Smariusncr53c9x_detach(struct ncr53c9x_softc *sc) 429130293Sscottl{ 430182876Smarius struct ncr53c9x_linfo *li, *nextli; 431182876Smarius int t; 432130293Sscottl 433146392Smarius callout_drain(&sc->sc_watchdog); 434182876Smarius 435182876Smarius NCR_LOCK(sc); 436182876Smarius 437182876Smarius if (sc->sc_tinfo) { 438182876Smarius /* Cancel all commands. */ 439182876Smarius ncr53c9x_clear(sc, CAM_REQ_ABORTED); 440182876Smarius 441182876Smarius /* Free logical units. */ 442182876Smarius for (t = 0; t < sc->sc_ntarg; t++) { 443182876Smarius for (li = LIST_FIRST(&sc->sc_tinfo[t].luns); li; 444182876Smarius li = nextli) { 445182876Smarius nextli = LIST_NEXT(li, link); 446182876Smarius free(li, M_DEVBUF); 447182876Smarius } 448182876Smarius } 449182876Smarius } 450182876Smarius 451182876Smarius xpt_register_async(0, ncr53c9x_async, sc->sc_sim, sc->sc_path); 452146392Smarius xpt_free_path(sc->sc_path); 453146392Smarius xpt_bus_deregister(cam_sim_path(sc->sc_sim)); 454226947Smarius cam_sim_free(sc->sc_sim, TRUE); 455182876Smarius 456182876Smarius NCR_UNLOCK(sc); 457182876Smarius 458146392Smarius free(sc->ecb_array, M_DEVBUF); 459146392Smarius free(sc->sc_tinfo, M_DEVBUF); 460146392Smarius if (sc->sc_imess_self) 461146392Smarius free(sc->sc_imess, M_DEVBUF); 462146392Smarius if (sc->sc_omess_self) 463146392Smarius free(sc->sc_omess, M_DEVBUF); 464130293Sscottl 465146392Smarius return (0); 466130293Sscottl} 467130293Sscottl 468130293Sscottl/* 469180692Smarius * This is the generic ncr53c9x reset function. It does not reset the SCSI 470180692Smarius * bus, only this controller, but kills any on-going commands, and also stops 471130293Sscottl * and resets the DMA. 472130293Sscottl * 473130293Sscottl * After reset, registers are loaded with the defaults from the attach 474130293Sscottl * routine above. 475130293Sscottl */ 476182876Smariusstatic void 477130293Sscottlncr53c9x_reset(struct ncr53c9x_softc *sc) 478130293Sscottl{ 479130293Sscottl 480182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 481182876Smarius 482180692Smarius /* Reset DMA first. */ 483130293Sscottl NCRDMA_RESET(sc); 484130293Sscottl 485180692Smarius /* Reset SCSI chip. */ 486130293Sscottl NCRCMD(sc, NCRCMD_RSTCHIP); 487130293Sscottl NCRCMD(sc, NCRCMD_NOP); 488130293Sscottl DELAY(500); 489130293Sscottl 490180692Smarius /* Do these backwards, and fall through. */ 491130293Sscottl switch (sc->sc_rev) { 492130293Sscottl case NCR_VARIANT_ESP406: 493130293Sscottl case NCR_VARIANT_FAS408: 494130293Sscottl NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT); 495130293Sscottl NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4); 496180692Smarius /* FALLTHROUGH */ 497130293Sscottl case NCR_VARIANT_AM53C974: 498146392Smarius case NCR_VARIANT_FAS100A: 499130293Sscottl case NCR_VARIANT_FAS216: 500146392Smarius case NCR_VARIANT_FAS236: 501130293Sscottl case NCR_VARIANT_NCR53C94: 502130293Sscottl case NCR_VARIANT_NCR53C96: 503130293Sscottl case NCR_VARIANT_ESP200: 504130293Sscottl sc->sc_features |= NCR_F_HASCFG3; 505130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); 506180692Smarius /* FALLTHROUGH */ 507130293Sscottl case NCR_VARIANT_ESP100A: 508130293Sscottl sc->sc_features |= NCR_F_SELATN3; 509226947Smarius if ((sc->sc_cfg2 & NCRCFG2_FE) != 0) 510226947Smarius sc->sc_features |= NCR_F_LARGEXFER; 511130293Sscottl NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); 512180692Smarius /* FALLTHROUGH */ 513130293Sscottl case NCR_VARIANT_ESP100: 514130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 515130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 516130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 517130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 518130293Sscottl break; 519130293Sscottl 520130293Sscottl case NCR_VARIANT_FAS366: 521226947Smarius sc->sc_features |= NCR_F_HASCFG3 | NCR_F_FASTSCSI | 522226947Smarius NCR_F_SELATN3 | NCR_F_LARGEXFER; 523130293Sscottl sc->sc_cfg3 = NCRFASCFG3_FASTCLK | NCRFASCFG3_OBAUTO; 524182876Smarius if (sc->sc_id > 7) 525182876Smarius sc->sc_cfg3 |= NCRFASCFG3_IDBIT3; 526130293Sscottl sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI; 527130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3); 528182876Smarius sc->sc_cfg2 = NCRCFG2_HMEFE | NCRCFG2_HME32; 529130293Sscottl NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2); 530130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 531130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 532130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 533130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 534130293Sscottl break; 535130293Sscottl 536130293Sscottl default: 537180692Smarius device_printf(sc->sc_dev, 538180692Smarius "unknown revision code, assuming ESP100\n"); 539130293Sscottl NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1); 540130293Sscottl NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf); 541130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, 0); 542130293Sscottl NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout); 543130293Sscottl } 544130293Sscottl 545130293Sscottl if (sc->sc_rev == NCR_VARIANT_AM53C974) 546130293Sscottl NCR_WRITE_REG(sc, NCR_AMDCFG4, sc->sc_cfg4); 547130293Sscottl 548130293Sscottl#if 0 549226381Smarius device_printf(sc->sc_dev, "%s: revision %d\n", __func__, sc->sc_rev); 550226381Smarius device_printf(sc->sc_dev, "%s: cfg1 0x%x, cfg2 0x%x, cfg3 0x%x, ccf " 551226381Smarius "0x%x, timeout 0x%x\n", __func__, sc->sc_cfg1, sc->sc_cfg2, 552226381Smarius sc->sc_cfg3, sc->sc_ccf, sc->sc_timeout); 553130293Sscottl#endif 554130293Sscottl} 555130293Sscottl 556130293Sscottl/* 557182876Smarius * Clear all commands. 558130293Sscottl */ 559130293Sscottlstatic void 560182876Smariusncr53c9x_clear(struct ncr53c9x_softc *sc, cam_status result) 561130293Sscottl{ 562182876Smarius struct ncr53c9x_ecb *ecb; 563182876Smarius int r; 564130293Sscottl 565182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 566130293Sscottl 567182876Smarius /* Cancel any active commands. */ 568182876Smarius sc->sc_state = NCR_CLEANING; 569182876Smarius sc->sc_msgify = 0; 570226381Smarius ecb = sc->sc_nexus; 571226381Smarius if (ecb != NULL) { 572182876Smarius ecb->ccb->ccb_h.status = result; 573182876Smarius ncr53c9x_done(sc, ecb); 574182876Smarius } 575182876Smarius /* Cancel outstanding disconnected commands. */ 576182876Smarius for (r = 0; r < sc->sc_ntarg; r++) 577182876Smarius ncr53c9x_clear_target(sc, r, result); 578130293Sscottl} 579130293Sscottl 580130293Sscottl/* 581182876Smarius * Clear all commands for a specific target. 582182876Smarius */ 583182876Smariusstatic void 584182876Smariusncr53c9x_clear_target(struct ncr53c9x_softc *sc, int target, 585182876Smarius cam_status result) 586182876Smarius{ 587182876Smarius struct ncr53c9x_ecb *ecb; 588182876Smarius struct ncr53c9x_linfo *li; 589182876Smarius int i; 590182876Smarius 591182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 592182876Smarius 593182876Smarius /* Cancel outstanding disconnected commands on each LUN. */ 594182876Smarius LIST_FOREACH(li, &sc->sc_tinfo[target].luns, link) { 595226381Smarius ecb = li->untagged; 596226381Smarius if (ecb != NULL) { 597182876Smarius li->untagged = NULL; 598182876Smarius /* 599182876Smarius * XXX should we terminate a command 600182876Smarius * that never reached the disk? 601182876Smarius */ 602182876Smarius li->busy = 0; 603182876Smarius ecb->ccb->ccb_h.status = result; 604182876Smarius ncr53c9x_done(sc, ecb); 605182876Smarius } 606226381Smarius for (i = 0; i < NCR_TAG_DEPTH; i++) { 607226381Smarius ecb = li->queued[i]; 608226381Smarius if (ecb != NULL) { 609182876Smarius li->queued[i] = NULL; 610182876Smarius ecb->ccb->ccb_h.status = result; 611182876Smarius ncr53c9x_done(sc, ecb); 612182876Smarius } 613226381Smarius } 614182876Smarius li->used = 0; 615182876Smarius } 616182876Smarius} 617182876Smarius 618182876Smarius/* 619180692Smarius * Initialize ncr53c9x state machine. 620130293Sscottl */ 621182876Smariusstatic void 622130293Sscottlncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) 623130293Sscottl{ 624180692Smarius struct ncr53c9x_tinfo *ti; 625182876Smarius int r; 626130293Sscottl 627182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 628182876Smarius 629130293Sscottl NCR_MISC(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state)); 630130293Sscottl 631130293Sscottl if (sc->sc_state == 0) { 632130293Sscottl /* First time through; initialize. */ 633130293Sscottl 634130293Sscottl TAILQ_INIT(&sc->ready_list); 635130293Sscottl sc->sc_nexus = NULL; 636226381Smarius memset(sc->sc_tinfo, 0, sizeof(*sc->sc_tinfo)); 637130293Sscottl for (r = 0; r < sc->sc_ntarg; r++) { 638130293Sscottl LIST_INIT(&sc->sc_tinfo[r].luns); 639130293Sscottl } 640182876Smarius } else 641182876Smarius ncr53c9x_clear(sc, CAM_CMD_TIMEOUT); 642130293Sscottl 643130293Sscottl /* 644180692Smarius * Reset the chip to a known state. 645130293Sscottl */ 646130293Sscottl ncr53c9x_reset(sc); 647130293Sscottl 648146392Smarius sc->sc_flags = 0; 649146392Smarius sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; 650130293Sscottl sc->sc_phase = sc->sc_prevphase = INVALID_PHASE; 651146392Smarius 652182876Smarius /* 653182876Smarius * If we're the first time through, set the default parameters 654182876Smarius * for all targets. Otherwise we only clear their current transfer 655182876Smarius * settings so we'll renegotiate their goal settings with the next 656182876Smarius * command. 657182876Smarius */ 658182876Smarius if (sc->sc_state == 0) { 659182876Smarius for (r = 0; r < sc->sc_ntarg; r++) { 660182876Smarius ti = &sc->sc_tinfo[r]; 661130293Sscottl/* XXX - config flags per target: low bits: no reselect; high bits: no synch */ 662130293Sscottl 663182876Smarius ti->flags = ((sc->sc_minsync != 0 && 664182876Smarius (sc->sc_cfflags & (1 << ((r & 7) + 8))) == 0) ? 665182876Smarius 0 : T_SYNCHOFF) | 666182876Smarius ((sc->sc_cfflags & (1 << (r & 7))) == 0 ? 667182876Smarius 0 : T_RSELECTOFF); 668182876Smarius ti->curr.period = ti->goal.period = 0; 669182876Smarius ti->curr.offset = ti->goal.offset = 0; 670182876Smarius ti->curr.width = ti->goal.width = 671182876Smarius MSG_EXT_WDTR_BUS_8_BIT; 672182876Smarius } 673182876Smarius } else { 674182876Smarius for (r = 0; r < sc->sc_ntarg; r++) { 675182876Smarius ti = &sc->sc_tinfo[r]; 676182876Smarius ti->flags &= ~(T_SDTRSENT | T_WDTRSENT); 677182876Smarius ti->curr.period = 0; 678182876Smarius ti->curr.offset = 0; 679182876Smarius ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; 680182876Smarius } 681130293Sscottl } 682130293Sscottl 683130293Sscottl if (doreset) { 684130293Sscottl sc->sc_state = NCR_SBR; 685130293Sscottl NCRCMD(sc, NCRCMD_RSTSCSI); 686182876Smarius /* Give the bus a fighting chance to settle. */ 687182876Smarius DELAY(250000); 688130293Sscottl } else { 689130293Sscottl sc->sc_state = NCR_IDLE; 690130293Sscottl ncr53c9x_sched(sc); 691130293Sscottl } 692130293Sscottl} 693130293Sscottl 694130293Sscottl/* 695130293Sscottl * Read the NCR registers, and save their contents for later use. 696130293Sscottl * NCR_STAT, NCR_STEP & NCR_INTR are mostly zeroed out when reading 697130293Sscottl * NCR_INTR - so make sure it is the last read. 698130293Sscottl * 699130293Sscottl * I think that (from reading the docs) most bits in these registers 700180692Smarius * only make sense when the DMA CSR has an interrupt showing. Call only 701130293Sscottl * if an interrupt is pending. 702130293Sscottl */ 703180692Smariusstatic inline void 704130293Sscottlncr53c9x_readregs(struct ncr53c9x_softc *sc) 705130293Sscottl{ 706130293Sscottl 707182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 708182876Smarius 709130293Sscottl sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT); 710180692Smarius /* Only the step bits are of interest. */ 711130293Sscottl sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP) & NCRSTEP_MASK; 712130293Sscottl 713145202Smarius if (sc->sc_rev == NCR_VARIANT_FAS366) 714130293Sscottl sc->sc_espstat2 = NCR_READ_REG(sc, NCR_STAT2); 715130293Sscottl 716130293Sscottl sc->sc_espintr = NCR_READ_REG(sc, NCR_INTR); 717130293Sscottl 718130293Sscottl /* 719130293Sscottl * Determine the SCSI bus phase, return either a real SCSI bus phase 720130293Sscottl * or some pseudo phase we use to detect certain exceptions. 721130293Sscottl */ 722130293Sscottl sc->sc_phase = (sc->sc_espintr & NCRINTR_DIS) ? 723180692Smarius BUSFREE_PHASE : sc->sc_espstat & NCRSTAT_PHASE; 724130293Sscottl 725130293Sscottl NCR_INTS(("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] ", 726130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc->sc_espstat2)); 727130293Sscottl} 728130293Sscottl 729130293Sscottl/* 730130293Sscottl * Convert Synchronous Transfer Period to chip register Clock Per Byte value. 731130293Sscottl */ 732180692Smariusstatic inline int 733130293Sscottlncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period) 734130293Sscottl{ 735130293Sscottl int v; 736182876Smarius 737182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 738182876Smarius 739130293Sscottl v = (sc->sc_freq * period) / 250; 740130293Sscottl if (ncr53c9x_cpb2stp(sc, v) < period) 741180692Smarius /* Correct round-down error. */ 742130293Sscottl v++; 743130293Sscottl return (v); 744130293Sscottl} 745130293Sscottl 746180692Smariusstatic inline void 747130293Sscottlncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti) 748130293Sscottl{ 749226381Smarius uint8_t cfg3, syncoff, synctp; 750130293Sscottl 751182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 752182876Smarius 753182876Smarius cfg3 = sc->sc_cfg3; 754182876Smarius if (ti->curr.offset != 0) { 755182876Smarius syncoff = ti->curr.offset; 756182876Smarius synctp = ncr53c9x_stp2cpb(sc, ti->curr.period); 757130293Sscottl if (sc->sc_features & NCR_F_FASTSCSI) { 758130293Sscottl /* 759130293Sscottl * If the period is 200ns or less (ti->period <= 50), 760130293Sscottl * put the chip in Fast SCSI mode. 761130293Sscottl */ 762182876Smarius if (ti->curr.period <= 50) 763130293Sscottl /* 764130293Sscottl * There are (at least) 4 variations of the 765130293Sscottl * configuration 3 register. The drive attach 766130293Sscottl * routine sets the appropriate bit to put the 767130293Sscottl * chip into Fast SCSI mode so that it doesn't 768130293Sscottl * have to be figured out here each time. 769130293Sscottl */ 770130293Sscottl cfg3 |= sc->sc_cfg3_fscsi; 771130293Sscottl } 772130293Sscottl 773130293Sscottl /* 774130293Sscottl * Am53c974 requires different SYNCTP values when the 775130293Sscottl * FSCSI bit is off. 776130293Sscottl */ 777130293Sscottl if (sc->sc_rev == NCR_VARIANT_AM53C974 && 778130293Sscottl (cfg3 & NCRAMDCFG3_FSCSI) == 0) 779130293Sscottl synctp--; 780130293Sscottl } else { 781130293Sscottl syncoff = 0; 782130293Sscottl synctp = 0; 783130293Sscottl } 784130293Sscottl 785182876Smarius if (ti->curr.width != MSG_EXT_WDTR_BUS_8_BIT) { 786182876Smarius if (sc->sc_rev == NCR_VARIANT_FAS366) 787182876Smarius cfg3 |= NCRFASCFG3_EWIDE; 788182876Smarius } 789182876Smarius 790130293Sscottl if (sc->sc_features & NCR_F_HASCFG3) 791130293Sscottl NCR_WRITE_REG(sc, NCR_CFG3, cfg3); 792130293Sscottl 793130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCOFF, syncoff); 794130293Sscottl NCR_WRITE_REG(sc, NCR_SYNCTP, synctp); 795130293Sscottl} 796130293Sscottl 797130293Sscottl/* 798130293Sscottl * Send a command to a target, set the driver state to NCR_SELECTING 799130293Sscottl * and let the caller take care of the rest. 800130293Sscottl * 801130293Sscottl * Keeping this as a function allows me to say that this may be done 802130293Sscottl * by DMA instead of programmed I/O soon. 803130293Sscottl */ 804130293Sscottlstatic void 805130293Sscottlncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 806130293Sscottl{ 807130293Sscottl struct ncr53c9x_tinfo *ti; 808226381Smarius uint8_t *cmd; 809130293Sscottl size_t dmasize; 810226947Smarius int clen, error, selatn3, selatns; 811180692Smarius int lun = ecb->ccb->ccb_h.target_lun; 812180692Smarius int target = ecb->ccb->ccb_h.target_id; 813130293Sscottl 814182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 815182876Smarius 816226381Smarius NCR_TRACE(("[%s(t%d,l%d,cmd:%x,tag:%x,%x)] ", __func__, target, lun, 817226381Smarius ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1])); 818130293Sscottl 819130293Sscottl ti = &sc->sc_tinfo[target]; 820130293Sscottl sc->sc_state = NCR_SELECTING; 821130293Sscottl /* 822182876Smarius * Schedule the callout now, the first time we will go away 823130293Sscottl * expecting to come back due to an interrupt, because it is 824130293Sscottl * always possible that the interrupt may never happen. 825130293Sscottl */ 826182876Smarius callout_reset(&ecb->ch, mstohz(ecb->timeout), ncr53c9x_callout, ecb); 827130293Sscottl 828130293Sscottl /* 829130293Sscottl * The docs say the target register is never reset, and I 830180692Smarius * can't think of a better place to set it. 831130293Sscottl */ 832130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 833130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 834182876Smarius NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HMEXC32 | 835182876Smarius NCR_BUSID_HMEENCID); 836226381Smarius } else 837130293Sscottl NCR_WRITE_REG(sc, NCR_SELID, target); 838130293Sscottl 839182876Smarius /* 840182876Smarius * If we are requesting sense, force a renegotiation if we are 841182876Smarius * currently using anything different from asynchronous at 8 bit 842182876Smarius * as the target might have lost our transfer negotiations. 843182876Smarius */ 844182876Smarius if ((ecb->flags & ECB_SENSE) != 0 && (ti->curr.offset != 0 || 845182876Smarius ti->curr.width != MSG_EXT_WDTR_BUS_8_BIT)) { 846182876Smarius ti->curr.period = 0; 847182876Smarius ti->curr.offset = 0; 848182876Smarius ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; 849130293Sscottl } 850182876Smarius ncr53c9x_setsync(sc, ti); 851130293Sscottl 852130293Sscottl selatn3 = selatns = 0; 853130293Sscottl if (ecb->tag[0] != 0) { 854130293Sscottl if (sc->sc_features & NCR_F_SELATN3) 855180692Smarius /* Use SELATN3 to send tag messages. */ 856130293Sscottl selatn3 = 1; 857130293Sscottl else 858180692Smarius /* We don't have SELATN3; use SELATNS to send tags. */ 859130293Sscottl selatns = 1; 860130293Sscottl } 861130293Sscottl 862182876Smarius if (ti->curr.period != ti->goal.period || 863182876Smarius ti->curr.offset != ti->goal.offset || 864182876Smarius ti->curr.width != ti->goal.width) { 865180692Smarius /* We have to use SELATNS to send sync/wide messages. */ 866130293Sscottl selatn3 = 0; 867130293Sscottl selatns = 1; 868130293Sscottl } 869130293Sscottl 870226381Smarius cmd = (uint8_t *)&ecb->cmd.cmd; 871130293Sscottl 872130293Sscottl if (selatn3) { 873180692Smarius /* We'll use tags with SELATN3. */ 874130293Sscottl clen = ecb->clen + 3; 875130293Sscottl cmd -= 3; 876130293Sscottl cmd[0] = MSG_IDENTIFY(lun, 1); /* msg[0] */ 877130293Sscottl cmd[1] = ecb->tag[0]; /* msg[1] */ 878130293Sscottl cmd[2] = ecb->tag[1]; /* msg[2] */ 879130293Sscottl } else { 880180692Smarius /* We don't have tags, or will send messages with SELATNS. */ 881130293Sscottl clen = ecb->clen + 1; 882130293Sscottl cmd -= 1; 883180692Smarius cmd[0] = MSG_IDENTIFY(lun, (ti->flags & T_RSELECTOFF) == 0); 884130293Sscottl } 885130293Sscottl 886130293Sscottl if ((sc->sc_features & NCR_F_DMASELECT) && !selatns) { 887180692Smarius /* Setup DMA transfer for command. */ 888130293Sscottl dmasize = clen; 889130293Sscottl sc->sc_cmdlen = clen; 890130293Sscottl sc->sc_cmdp = cmd; 891226947Smarius error = NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, 892226947Smarius &dmasize); 893239089Smarius if (error != 0) 894226947Smarius goto cmd; 895226947Smarius 896180692Smarius /* Program the SCSI counter. */ 897130293Sscottl NCR_SET_COUNT(sc, dmasize); 898130293Sscottl 899180692Smarius /* Load the count in. */ 900226947Smarius NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); 901130293Sscottl 902180692Smarius /* And get the target's attention. */ 903130293Sscottl if (selatn3) { 904130293Sscottl sc->sc_msgout = SEND_TAG; 905130293Sscottl sc->sc_flags |= NCR_ATN; 906130293Sscottl NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA); 907130293Sscottl } else 908130293Sscottl NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA); 909130293Sscottl NCRDMA_GO(sc); 910130293Sscottl return; 911130293Sscottl } 912130293Sscottl 913226947Smariuscmd: 914130293Sscottl /* 915133039Strhodes * Who am I? This is where we tell the target that we are 916130293Sscottl * happy for it to disconnect etc. 917130293Sscottl */ 918130293Sscottl 919180692Smarius /* Now get the command into the FIFO. */ 920239089Smarius sc->sc_cmdlen = 0; 921130293Sscottl ncr53c9x_wrfifo(sc, cmd, clen); 922130293Sscottl 923180692Smarius /* And get the target's attention. */ 924130293Sscottl if (selatns) { 925130293Sscottl NCR_MSGS(("SELATNS \n")); 926180692Smarius /* Arbitrate, select and stop after IDENTIFY message. */ 927130293Sscottl NCRCMD(sc, NCRCMD_SELATNS); 928130293Sscottl } else if (selatn3) { 929130293Sscottl sc->sc_msgout = SEND_TAG; 930130293Sscottl sc->sc_flags |= NCR_ATN; 931130293Sscottl NCRCMD(sc, NCRCMD_SELATN3); 932130293Sscottl } else 933130293Sscottl NCRCMD(sc, NCRCMD_SELATN); 934130293Sscottl} 935130293Sscottl 936130293Sscottlstatic void 937130293Sscottlncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 938130293Sscottl{ 939130293Sscottl 940182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 941182876Smarius 942130293Sscottl ecb->flags = 0; 943130406Sscottl TAILQ_INSERT_TAIL(&sc->free_list, ecb, free_links); 944130293Sscottl} 945130293Sscottl 946130293Sscottlstatic struct ncr53c9x_ecb * 947130293Sscottlncr53c9x_get_ecb(struct ncr53c9x_softc *sc) 948130293Sscottl{ 949130293Sscottl struct ncr53c9x_ecb *ecb; 950130293Sscottl 951182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 952182876Smarius 953130406Sscottl ecb = TAILQ_FIRST(&sc->free_list); 954130293Sscottl if (ecb) { 955130406Sscottl if (ecb->flags != 0) 956226381Smarius panic("%s: ecb flags not cleared", __func__); 957130406Sscottl TAILQ_REMOVE(&sc->free_list, ecb, free_links); 958130406Sscottl ecb->flags = ECB_ALLOC; 959130406Sscottl bzero(&ecb->ccb, sizeof(struct ncr53c9x_ecb) - 960180692Smarius offsetof(struct ncr53c9x_ecb, ccb)); 961130293Sscottl } 962130293Sscottl return (ecb); 963130293Sscottl} 964130293Sscottl 965130293Sscottl/* 966133039Strhodes * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS: 967130293Sscottl */ 968130293Sscottl 969130293Sscottl/* 970180692Smarius * Start a SCSI-command. 971130293Sscottl * This function is called by the higher level SCSI-driver to queue/run 972130293Sscottl * SCSI-commands. 973130293Sscottl */ 974130293Sscottl 975182876Smariusstatic void 976130293Sscottlncr53c9x_action(struct cam_sim *sim, union ccb *ccb) 977130293Sscottl{ 978180692Smarius struct ccb_pathinq *cpi; 979180692Smarius struct ccb_scsiio *csio; 980180692Smarius struct ccb_trans_settings *cts; 981180692Smarius struct ccb_trans_settings_scsi *scsi; 982180692Smarius struct ccb_trans_settings_spi *spi; 983180692Smarius struct ncr53c9x_ecb *ecb; 984130293Sscottl struct ncr53c9x_softc *sc; 985180692Smarius struct ncr53c9x_tinfo *ti; 986180692Smarius int target; 987130293Sscottl 988182876Smarius sc = cam_sim_softc(sim); 989182876Smarius 990182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 991182876Smarius 992226381Smarius NCR_TRACE(("[%s %d]", __func__, ccb->ccb_h.func_code)); 993130293Sscottl 994130293Sscottl switch (ccb->ccb_h.func_code) { 995130293Sscottl case XPT_RESET_BUS: 996182876Smarius ncr53c9x_init(sc, 1); 997130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 998226947Smarius break; 999180692Smarius 1000130293Sscottl case XPT_CALC_GEOMETRY: 1001130349Sscottl cam_calc_geometry(&ccb->ccg, sc->sc_extended_geom); 1002226947Smarius break; 1003180692Smarius 1004130293Sscottl case XPT_PATH_INQ: 1005180692Smarius cpi = &ccb->cpi; 1006130293Sscottl cpi->version_num = 1; 1007180692Smarius cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE; 1008130293Sscottl cpi->hba_inquiry |= 1009130293Sscottl (sc->sc_rev == NCR_VARIANT_FAS366) ? PI_WIDE_16 : 0; 1010130293Sscottl cpi->target_sprt = 0; 1011130293Sscottl cpi->hba_misc = 0; 1012130293Sscottl cpi->hba_eng_cnt = 0; 1013130293Sscottl cpi->max_target = sc->sc_ntarg - 1; 1014182876Smarius cpi->max_lun = 7; 1015130293Sscottl cpi->initiator_id = sc->sc_id; 1016130293Sscottl strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 1017226947Smarius strncpy(cpi->hba_vid, "NCR", HBA_IDLEN); 1018130293Sscottl strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 1019130293Sscottl cpi->unit_number = cam_sim_unit(sim); 1020226947Smarius cpi->bus_id = 0; 1021226947Smarius cpi->base_transfer_speed = 3300; 1022226947Smarius cpi->protocol = PROTO_SCSI; 1023226947Smarius cpi->protocol_version = SCSI_REV_2; 1024163816Smjacob cpi->transport = XPORT_SPI; 1025163816Smjacob cpi->transport_version = 2; 1026226947Smarius cpi->maxio = sc->sc_maxxfer; 1027130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 1028226947Smarius break; 1029180692Smarius 1030130293Sscottl case XPT_GET_TRAN_SETTINGS: 1031180692Smarius cts = &ccb->cts; 1032180692Smarius ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 1033180692Smarius scsi = &cts->proto_specific.scsi; 1034180692Smarius spi = &cts->xport_specific.spi; 1035130293Sscottl 1036163816Smjacob cts->protocol = PROTO_SCSI; 1037163816Smjacob cts->protocol_version = SCSI_REV_2; 1038163816Smjacob cts->transport = XPORT_SPI; 1039163816Smjacob cts->transport_version = 2; 1040130293Sscottl 1041163816Smjacob if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 1042182876Smarius spi->sync_period = ti->curr.period; 1043182876Smarius spi->sync_offset = ti->curr.offset; 1044182876Smarius spi->bus_width = ti->curr.width; 1045163816Smjacob if ((ti->flags & T_TAG) != 0) { 1046163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 1047163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 1048163816Smjacob } else { 1049163816Smjacob spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 1050163816Smjacob scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 1051163816Smjacob } 1052163816Smjacob } else { 1053182876Smarius if ((ti->flags & T_SYNCHOFF) != 0) { 1054182876Smarius spi->sync_period = 0; 1055182876Smarius spi->sync_offset = 0; 1056182876Smarius } else { 1057182876Smarius spi->sync_period = sc->sc_minsync; 1058182876Smarius spi->sync_offset = sc->sc_maxoffset; 1059182876Smarius } 1060163816Smjacob spi->bus_width = sc->sc_maxwidth; 1061163816Smjacob spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 1062163816Smjacob scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 1063163816Smjacob } 1064163816Smjacob spi->valid = 1065163816Smjacob CTS_SPI_VALID_BUS_WIDTH | 1066163816Smjacob CTS_SPI_VALID_SYNC_RATE | 1067163816Smjacob CTS_SPI_VALID_SYNC_OFFSET | 1068163816Smjacob CTS_SPI_VALID_DISC; 1069163816Smjacob scsi->valid = CTS_SCSI_VALID_TQ; 1070130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 1071226947Smarius break; 1072180692Smarius 1073130293Sscottl case XPT_ABORT: 1074182876Smarius device_printf(sc->sc_dev, "XPT_ABORT called\n"); 1075130293Sscottl ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1076226947Smarius break; 1077180692Smarius 1078130293Sscottl case XPT_TERM_IO: 1079182876Smarius device_printf(sc->sc_dev, "XPT_TERM_IO called\n"); 1080130293Sscottl ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1081226947Smarius break; 1082180692Smarius 1083130293Sscottl case XPT_RESET_DEV: 1084130293Sscottl case XPT_SCSI_IO: 1085130293Sscottl if (ccb->ccb_h.target_id < 0 || 1086130293Sscottl ccb->ccb_h.target_id >= sc->sc_ntarg) { 1087130293Sscottl ccb->ccb_h.status = CAM_PATH_INVALID; 1088226947Smarius goto done; 1089130293Sscottl } 1090130293Sscottl /* Get an ECB to use. */ 1091130293Sscottl ecb = ncr53c9x_get_ecb(sc); 1092130293Sscottl /* 1093130293Sscottl * This should never happen as we track resources 1094130293Sscottl * in the mid-layer. 1095130293Sscottl */ 1096130293Sscottl if (ecb == NULL) { 1097130293Sscottl xpt_freeze_simq(sim, 1); 1098130293Sscottl ccb->ccb_h.status = CAM_REQUEUE_REQ; 1099182876Smarius device_printf(sc->sc_dev, "unable to allocate ecb\n"); 1100226947Smarius goto done; 1101130293Sscottl } 1102130293Sscottl 1103180692Smarius /* Initialize ecb. */ 1104130293Sscottl ecb->ccb = ccb; 1105130293Sscottl ecb->timeout = ccb->ccb_h.timeout; 1106130293Sscottl 1107130372Sscottl if (ccb->ccb_h.func_code == XPT_RESET_DEV) { 1108130293Sscottl ecb->flags |= ECB_RESET; 1109130293Sscottl ecb->clen = 0; 1110130293Sscottl ecb->dleft = 0; 1111130293Sscottl } else { 1112130293Sscottl csio = &ccb->csio; 1113130293Sscottl if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) 1114130293Sscottl bcopy(csio->cdb_io.cdb_ptr, &ecb->cmd.cmd, 1115180692Smarius csio->cdb_len); 1116130293Sscottl else 1117130293Sscottl bcopy(csio->cdb_io.cdb_bytes, &ecb->cmd.cmd, 1118180692Smarius csio->cdb_len); 1119130293Sscottl ecb->clen = csio->cdb_len; 1120130293Sscottl ecb->daddr = csio->data_ptr; 1121130293Sscottl ecb->dleft = csio->dxfer_len; 1122130293Sscottl } 1123130293Sscottl ecb->stat = 0; 1124130293Sscottl 1125130293Sscottl TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain); 1126130293Sscottl ecb->flags |= ECB_READY; 1127130293Sscottl if (sc->sc_state == NCR_IDLE) 1128130293Sscottl ncr53c9x_sched(sc); 1129226947Smarius return; 1130130293Sscottl 1131130293Sscottl case XPT_SET_TRAN_SETTINGS: 1132180692Smarius cts = &ccb->cts; 1133180692Smarius target = ccb->ccb_h.target_id; 1134180692Smarius ti = &sc->sc_tinfo[target]; 1135180692Smarius scsi = &cts->proto_specific.scsi; 1136180692Smarius spi = &cts->xport_specific.spi; 1137130293Sscottl 1138163816Smjacob if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 1139163816Smjacob if ((sc->sc_cfflags & (1<<((target & 7) + 16))) == 0 && 1140163816Smjacob (scsi->flags & CTS_SCSI_FLAGS_TAG_ENB)) { 1141163816Smjacob NCR_MISC(("%s: target %d: tagged queuing\n", 1142163816Smjacob device_get_nameunit(sc->sc_dev), target)); 1143163816Smjacob ti->flags |= T_TAG; 1144163816Smjacob } else 1145163816Smjacob ti->flags &= ~T_TAG; 1146163816Smjacob } 1147130293Sscottl 1148163816Smjacob if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { 1149182876Smarius NCR_MISC(("%s: target %d: wide negotiation\n", 1150182876Smarius device_get_nameunit(sc->sc_dev), target)); 1151182876Smarius ti->goal.width = spi->bus_width; 1152163816Smjacob } 1153163816Smjacob 1154163816Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) { 1155163816Smjacob NCR_MISC(("%s: target %d: sync period negotiation\n", 1156163816Smjacob device_get_nameunit(sc->sc_dev), target)); 1157182876Smarius ti->goal.period = spi->sync_period; 1158163816Smjacob } 1159163816Smjacob 1160163816Smjacob if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) { 1161163816Smjacob NCR_MISC(("%s: target %d: sync offset negotiation\n", 1162163816Smjacob device_get_nameunit(sc->sc_dev), target)); 1163182876Smarius ti->goal.offset = spi->sync_offset; 1164163816Smjacob } 1165130293Sscottl 1166130293Sscottl ccb->ccb_h.status = CAM_REQ_CMP; 1167226947Smarius break; 1168130293Sscottl 1169130293Sscottl default: 1170130293Sscottl device_printf(sc->sc_dev, "Unhandled function code %d\n", 1171180692Smarius ccb->ccb_h.func_code); 1172130293Sscottl ccb->ccb_h.status = CAM_PROVIDE_FAIL; 1173130293Sscottl } 1174226947Smarius 1175226947Smariusdone: 1176226947Smarius xpt_done(ccb); 1177130293Sscottl} 1178130293Sscottl 1179130293Sscottl/* 1180133039Strhodes * Used when interrupt driven I/O is not allowed, e.g. during boot. 1181130293Sscottl */ 1182130293Sscottlstatic void 1183130293Sscottlncr53c9x_poll(struct cam_sim *sim) 1184130293Sscottl{ 1185130293Sscottl struct ncr53c9x_softc *sc; 1186130293Sscottl 1187182876Smarius sc = cam_sim_softc(sim); 1188182876Smarius 1189182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1190182876Smarius 1191226381Smarius NCR_TRACE(("[%s] ", __func__)); 1192182876Smarius 1193182876Smarius if (NCRDMA_ISINTR(sc)) 1194182876Smarius ncr53c9x_intr1(sc); 1195182876Smarius} 1196182876Smarius 1197182876Smarius/* 1198182876Smarius * Asynchronous notification handler 1199182876Smarius */ 1200182876Smariusstatic void 1201182876Smariusncr53c9x_async(void *cbarg, uint32_t code, struct cam_path *path, void *arg) 1202182876Smarius{ 1203182876Smarius struct ncr53c9x_softc *sc; 1204182876Smarius struct ncr53c9x_tinfo *ti; 1205182876Smarius int target; 1206182876Smarius 1207182876Smarius sc = cam_sim_softc(cbarg); 1208182876Smarius 1209182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1210182876Smarius 1211182876Smarius switch (code) { 1212182876Smarius case AC_LOST_DEVICE: 1213182876Smarius target = xpt_path_target_id(path); 1214182876Smarius if (target < 0 || target >= sc->sc_ntarg) 1215182876Smarius break; 1216182876Smarius 1217182876Smarius /* Cancel outstanding disconnected commands. */ 1218182876Smarius ncr53c9x_clear_target(sc, target, CAM_REQ_ABORTED); 1219182876Smarius 1220182876Smarius /* Set the default parameters for the target. */ 1221182876Smarius ti = &sc->sc_tinfo[target]; 1222182876Smarius/* XXX - config flags per target: low bits: no reselect; high bits: no synch */ 1223182876Smarius ti->flags = ((sc->sc_minsync != 0 && 1224182876Smarius (sc->sc_cfflags & (1 << ((target & 7) + 8))) == 0) ? 1225182876Smarius 0 : T_SYNCHOFF) | 1226182876Smarius ((sc->sc_cfflags & (1 << (target & 7))) == 0 ? 1227182876Smarius 0 : T_RSELECTOFF); 1228182876Smarius ti->curr.period = ti->goal.period = 0; 1229182876Smarius ti->curr.offset = ti->goal.offset = 0; 1230182876Smarius ti->curr.width = ti->goal.width = MSG_EXT_WDTR_BUS_8_BIT; 1231182876Smarius break; 1232130293Sscottl } 1233130293Sscottl} 1234130293Sscottl 1235130293Sscottl/* 1236130293Sscottl * LOW LEVEL SCSI UTILITIES 1237130293Sscottl */ 1238130293Sscottl 1239130293Sscottl/* 1240180692Smarius * Schedule a SCSI operation. This has now been pulled out of the interrupt 1241182876Smarius * handler so that we may call it from ncr53c9x_action and ncr53c9x_done. 1242182876Smarius * This may save us an unnecessary interrupt just to get things going. 1243182876Smarius * Should only be called when state == NCR_IDLE and with sc_lock held. 1244130293Sscottl */ 1245130293Sscottlstatic void 1246130293Sscottlncr53c9x_sched(struct ncr53c9x_softc *sc) 1247130293Sscottl{ 1248130293Sscottl struct ncr53c9x_ecb *ecb; 1249180692Smarius struct ncr53c9x_linfo *li; 1250130293Sscottl struct ncr53c9x_tinfo *ti; 1251180692Smarius int lun, tag; 1252130293Sscottl 1253182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1254182876Smarius 1255226381Smarius NCR_TRACE(("[%s] ", __func__)); 1256180692Smarius 1257130293Sscottl if (sc->sc_state != NCR_IDLE) 1258226381Smarius panic("%s: not IDLE (state=%d)", __func__, sc->sc_state); 1259130293Sscottl 1260130293Sscottl /* 1261130293Sscottl * Find first ecb in ready queue that is for a target/lunit 1262130293Sscottl * combinations that is not busy. 1263130293Sscottl */ 1264182876Smarius TAILQ_FOREACH(ecb, &sc->ready_list, chain) { 1265130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1266130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1267130293Sscottl 1268130293Sscottl /* Select type of tag for this command */ 1269182876Smarius if ((ti->flags & (T_RSELECTOFF | T_TAG)) != T_TAG) 1270130293Sscottl tag = 0; 1271130293Sscottl else if ((ecb->flags & ECB_SENSE) != 0) 1272130293Sscottl tag = 0; 1273130406Sscottl else if ((ecb->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0) 1274130406Sscottl tag = 0; 1275130406Sscottl else if (ecb->ccb->csio.tag_action == CAM_TAG_ACTION_NONE) 1276130406Sscottl tag = 0; 1277130293Sscottl else 1278130293Sscottl tag = ecb->ccb->csio.tag_action; 1279130293Sscottl 1280130293Sscottl li = TINFO_LUN(ti, lun); 1281130293Sscottl if (li == NULL) { 1282130293Sscottl /* Initialize LUN info and add to list. */ 1283226381Smarius li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT | M_ZERO); 1284226381Smarius if (li == NULL) 1285130293Sscottl continue; 1286130293Sscottl li->lun = lun; 1287130293Sscottl 1288130293Sscottl LIST_INSERT_HEAD(&ti->luns, li, link); 1289130293Sscottl if (lun < NCR_NLUN) 1290130293Sscottl ti->lun[lun] = li; 1291130293Sscottl } 1292130293Sscottl li->last_used = time_second; 1293130293Sscottl if (tag == 0) { 1294180692Smarius /* Try to issue this as an untagged command. */ 1295130293Sscottl if (li->untagged == NULL) 1296130293Sscottl li->untagged = ecb; 1297130293Sscottl } 1298130293Sscottl if (li->untagged != NULL) { 1299130293Sscottl tag = 0; 1300130293Sscottl if ((li->busy != 1) && li->used == 0) { 1301180692Smarius /* 1302180692Smarius * We need to issue this untagged command 1303180692Smarius * now. 1304180692Smarius */ 1305130293Sscottl ecb = li->untagged; 1306130293Sscottl } else { 1307180692Smarius /* not ready, yet */ 1308130293Sscottl continue; 1309130293Sscottl } 1310130293Sscottl } 1311130293Sscottl ecb->tag[0] = tag; 1312130293Sscottl if (tag != 0) { 1313130406Sscottl li->queued[ecb->tag_id] = ecb; 1314130406Sscottl ecb->tag[1] = ecb->tag_id; 1315130293Sscottl li->used++; 1316130293Sscottl } 1317130293Sscottl if (li->untagged != NULL && (li->busy != 1)) { 1318130293Sscottl li->busy = 1; 1319130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1320130293Sscottl ecb->flags &= ~ECB_READY; 1321130293Sscottl sc->sc_nexus = ecb; 1322130293Sscottl ncr53c9x_select(sc, ecb); 1323130293Sscottl break; 1324130293Sscottl } 1325130293Sscottl if (li->untagged == NULL && tag != 0) { 1326130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1327130293Sscottl ecb->flags &= ~ECB_READY; 1328130293Sscottl sc->sc_nexus = ecb; 1329130293Sscottl ncr53c9x_select(sc, ecb); 1330130293Sscottl break; 1331227284Smarius } else 1332226381Smarius NCR_TRACE(("[%s %d:%d busy] \n", __func__, 1333130293Sscottl ecb->ccb->ccb_h.target_id, 1334130293Sscottl ecb->ccb->ccb_h.target_lun)); 1335130293Sscottl } 1336130293Sscottl} 1337130293Sscottl 1338130293Sscottlstatic void 1339130293Sscottlncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1340130293Sscottl{ 1341130293Sscottl union ccb *ccb = ecb->ccb; 1342180692Smarius struct ncr53c9x_linfo *li; 1343130293Sscottl struct ncr53c9x_tinfo *ti; 1344130293Sscottl struct scsi_request_sense *ss = (void *)&ecb->cmd.cmd; 1345130293Sscottl int lun; 1346130293Sscottl 1347182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1348182876Smarius 1349226381Smarius NCR_TRACE(("[%s] ", __func__)); 1350130293Sscottl 1351130293Sscottl lun = ccb->ccb_h.target_lun; 1352130293Sscottl ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 1353130293Sscottl 1354180692Smarius /* Next, setup a REQUEST SENSE command block. */ 1355130293Sscottl memset(ss, 0, sizeof(*ss)); 1356130293Sscottl ss->opcode = REQUEST_SENSE; 1357130293Sscottl ss->byte2 = ccb->ccb_h.target_lun << SCSI_CMD_LUN_SHIFT; 1358130293Sscottl ss->length = sizeof(struct scsi_sense_data); 1359130293Sscottl ecb->clen = sizeof(*ss); 1360226095Smarius memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data)); 1361226381Smarius ecb->daddr = (uint8_t *)&ccb->csio.sense_data; 1362130293Sscottl ecb->dleft = sizeof(struct scsi_sense_data); 1363130293Sscottl ecb->flags |= ECB_SENSE; 1364130293Sscottl ecb->timeout = NCR_SENSE_TIMEOUT; 1365130293Sscottl ti->senses++; 1366130293Sscottl li = TINFO_LUN(ti, lun); 1367130293Sscottl if (li->busy) 1368130293Sscottl li->busy = 0; 1369130293Sscottl ncr53c9x_dequeue(sc, ecb); 1370180692Smarius li->untagged = ecb; /* Must be executed first to fix C/A. */ 1371130293Sscottl li->busy = 2; 1372226381Smarius if (ecb == sc->sc_nexus) 1373130293Sscottl ncr53c9x_select(sc, ecb); 1374226381Smarius else { 1375130293Sscottl TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); 1376130293Sscottl ecb->flags |= ECB_READY; 1377130293Sscottl if (sc->sc_state == NCR_IDLE) 1378130293Sscottl ncr53c9x_sched(sc); 1379130293Sscottl } 1380130293Sscottl} 1381130293Sscottl 1382130293Sscottl/* 1383130293Sscottl * POST PROCESSING OF SCSI_CMD (usually current) 1384130293Sscottl */ 1385130293Sscottlstatic void 1386130293Sscottlncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1387130293Sscottl{ 1388130293Sscottl union ccb *ccb = ecb->ccb; 1389180692Smarius struct ncr53c9x_linfo *li; 1390130293Sscottl struct ncr53c9x_tinfo *ti; 1391226095Smarius int lun, sense_returned; 1392130293Sscottl 1393182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1394182876Smarius 1395226381Smarius NCR_TRACE(("[%s(status:%x)] ", __func__, ccb->ccb_h.status)); 1396130293Sscottl 1397130293Sscottl ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 1398130293Sscottl lun = ccb->ccb_h.target_lun; 1399180692Smarius li = TINFO_LUN(ti, lun); 1400130293Sscottl 1401182876Smarius callout_stop(&ecb->ch); 1402130293Sscottl 1403130293Sscottl /* 1404130293Sscottl * Now, if we've come here with no error code, i.e. we've kept the 1405182876Smarius * initial CAM_REQ_CMP, and the status code signals that we should 1406130293Sscottl * check sense, we'll need to set up a request sense cmd block and 1407130293Sscottl * push the command back into the ready queue *before* any other 1408130293Sscottl * commands for this target/lunit, else we lose the sense info. 1409130293Sscottl * We don't support chk sense conditions for the request sense cmd. 1410130293Sscottl */ 1411130293Sscottl if (ccb->ccb_h.status == CAM_REQ_CMP) { 1412182876Smarius ccb->csio.scsi_status = ecb->stat; 1413227284Smarius if ((ecb->flags & ECB_ABORT) != 0) 1414130293Sscottl ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1415227284Smarius else if ((ecb->flags & ECB_SENSE) != 0 && 1416227284Smarius (ecb->stat != SCSI_STATUS_CHECK_COND)) { 1417182876Smarius ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND; 1418182876Smarius ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | 1419182876Smarius CAM_AUTOSNS_VALID; 1420226095Smarius sense_returned = sizeof(ccb->csio.sense_data) - 1421226095Smarius ecb->dleft; 1422226095Smarius if (sense_returned < ccb->csio.sense_len) 1423226095Smarius ccb->csio.sense_resid = ccb->csio.sense_len - 1424226095Smarius sense_returned; 1425226095Smarius else 1426226095Smarius ccb->csio.sense_resid = 0; 1427130293Sscottl } else if (ecb->stat == SCSI_STATUS_CHECK_COND) { 1428130293Sscottl if ((ecb->flags & ECB_SENSE) != 0) 1429130293Sscottl ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 1430130293Sscottl else { 1431180692Smarius /* First, save the return values. */ 1432130293Sscottl ccb->csio.resid = ecb->dleft; 1433182876Smarius if ((ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 1434182876Smarius 0) { 1435182876Smarius ncr53c9x_sense(sc, ecb); 1436182876Smarius return; 1437182876Smarius } 1438182876Smarius ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 1439130293Sscottl } 1440227284Smarius } else 1441130293Sscottl ccb->csio.resid = ecb->dleft; 1442182876Smarius if (ecb->stat == SCSI_STATUS_QUEUE_FULL) 1443182876Smarius ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 1444182876Smarius else if (ecb->stat == SCSI_STATUS_BUSY) 1445182876Smarius ccb->ccb_h.status = CAM_SCSI_BUSY; 1446227284Smarius } else if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 1447227284Smarius ccb->ccb_h.status |= CAM_DEV_QFRZN; 1448227284Smarius xpt_freeze_devq(ccb->ccb_h.path, 1); 1449130293Sscottl } 1450130293Sscottl 1451130293Sscottl#ifdef NCR53C9X_DEBUG 1452226381Smarius if ((ncr53c9x_debug & NCR_SHOWTRAC) != 0) { 1453130293Sscottl if (ccb->csio.resid != 0) 1454130293Sscottl printf("resid=%d ", ccb->csio.resid); 1455182876Smarius if ((ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) 1456130293Sscottl printf("sense=0x%02x\n", 1457182876Smarius ccb->csio.sense_data.error_code); 1458130293Sscottl else 1459182876Smarius printf("status SCSI=0x%x CAM=0x%x\n", 1460182876Smarius ccb->csio.scsi_status, ccb->ccb_h.status); 1461130293Sscottl } 1462130293Sscottl#endif 1463130293Sscottl 1464130293Sscottl /* 1465130293Sscottl * Remove the ECB from whatever queue it's on. 1466130293Sscottl */ 1467130293Sscottl ncr53c9x_dequeue(sc, ecb); 1468130293Sscottl if (ecb == sc->sc_nexus) { 1469130293Sscottl sc->sc_nexus = NULL; 1470130293Sscottl if (sc->sc_state != NCR_CLEANING) { 1471130293Sscottl sc->sc_state = NCR_IDLE; 1472130293Sscottl ncr53c9x_sched(sc); 1473130293Sscottl } 1474130293Sscottl } 1475130293Sscottl 1476227284Smarius if ((ccb->ccb_h.status & CAM_SEL_TIMEOUT) != 0) { 1477180692Smarius /* Selection timeout -- discard this LUN if empty. */ 1478130293Sscottl if (li->untagged == NULL && li->used == 0) { 1479130293Sscottl if (lun < NCR_NLUN) 1480130293Sscottl ti->lun[lun] = NULL; 1481130293Sscottl LIST_REMOVE(li, link); 1482130293Sscottl free(li, M_DEVBUF); 1483130293Sscottl } 1484130293Sscottl } 1485130293Sscottl 1486130293Sscottl ncr53c9x_free_ecb(sc, ecb); 1487130293Sscottl ti->cmds++; 1488130293Sscottl xpt_done(ccb); 1489130293Sscottl} 1490130293Sscottl 1491130293Sscottlstatic void 1492130293Sscottlncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 1493130293Sscottl{ 1494180692Smarius struct ncr53c9x_linfo *li; 1495130293Sscottl struct ncr53c9x_tinfo *ti; 1496130293Sscottl int64_t lun; 1497130293Sscottl 1498182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1499182876Smarius 1500130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1501130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1502130293Sscottl li = TINFO_LUN(ti, lun); 1503130293Sscottl#ifdef DIAGNOSTIC 1504130293Sscottl if (li == NULL || li->lun != lun) 1505235822Sdelphij panic("%s: lun %llx for ecb %p does not exist", __func__, 1506180692Smarius (long long)lun, ecb); 1507130293Sscottl#endif 1508130293Sscottl if (li->untagged == ecb) { 1509130293Sscottl li->busy = 0; 1510130293Sscottl li->untagged = NULL; 1511130293Sscottl } 1512130293Sscottl if (ecb->tag[0] && li->queued[ecb->tag[1]] != NULL) { 1513130293Sscottl#ifdef DIAGNOSTIC 1514130293Sscottl if (li->queued[ecb->tag[1]] != NULL && 1515130293Sscottl (li->queued[ecb->tag[1]] != ecb)) 1516235822Sdelphij panic("%s: slot %d for lun %llx has %p instead of ecb " 1517226381Smarius "%p", __func__, ecb->tag[1], (long long)lun, 1518226381Smarius li->queued[ecb->tag[1]], ecb); 1519130293Sscottl#endif 1520130293Sscottl li->queued[ecb->tag[1]] = NULL; 1521130293Sscottl li->used--; 1522130293Sscottl } 1523182876Smarius ecb->tag[0] = ecb->tag[1] = 0; 1524130293Sscottl 1525130293Sscottl if ((ecb->flags & ECB_READY) != 0) { 1526130293Sscottl ecb->flags &= ~ECB_READY; 1527130293Sscottl TAILQ_REMOVE(&sc->ready_list, ecb, chain); 1528130293Sscottl } 1529130293Sscottl} 1530130293Sscottl 1531130293Sscottl/* 1532130293Sscottl * INTERRUPT/PROTOCOL ENGINE 1533130293Sscottl */ 1534130293Sscottl 1535130293Sscottl/* 1536130293Sscottl * Schedule an outgoing message by prioritizing it, and asserting 1537180692Smarius * attention on the bus. We can only do this when we are the initiator 1538130293Sscottl * else there will be an illegal command interrupt. 1539130293Sscottl */ 1540180692Smarius#define ncr53c9x_sched_msgout(m) do { \ 1541180692Smarius NCR_MSGS(("ncr53c9x_sched_msgout %x %d", m, __LINE__)); \ 1542180692Smarius NCRCMD(sc, NCRCMD_SETATN); \ 1543180692Smarius sc->sc_flags |= NCR_ATN; \ 1544180692Smarius sc->sc_msgpriq |= (m); \ 1545226381Smarius} while (/* CONSTCOND */0) 1546130293Sscottl 1547130293Sscottlstatic void 1548130293Sscottlncr53c9x_flushfifo(struct ncr53c9x_softc *sc) 1549130293Sscottl{ 1550182876Smarius 1551182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1552182876Smarius 1553226381Smarius NCR_TRACE(("[%s] ", __func__)); 1554130293Sscottl 1555130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 1556130293Sscottl 1557130293Sscottl if (sc->sc_phase == COMMAND_PHASE || 1558130293Sscottl sc->sc_phase == MESSAGE_OUT_PHASE) 1559130293Sscottl DELAY(2); 1560130293Sscottl} 1561130293Sscottl 1562130293Sscottlstatic int 1563130293Sscottlncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how) 1564130293Sscottl{ 1565130293Sscottl int i, n; 1566226381Smarius uint8_t *ibuf; 1567130293Sscottl 1568182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1569182876Smarius 1570180692Smarius switch (how) { 1571130293Sscottl case NCR_RDFIFO_START: 1572180692Smarius ibuf = sc->sc_imess; 1573130293Sscottl sc->sc_imlen = 0; 1574130293Sscottl break; 1575180692Smarius 1576130293Sscottl case NCR_RDFIFO_CONTINUE: 1577180692Smarius ibuf = sc->sc_imess + sc->sc_imlen; 1578130293Sscottl break; 1579180692Smarius 1580130293Sscottl default: 1581226381Smarius panic("%s: bad flag", __func__); 1582180692Smarius /* NOTREACHED */ 1583130293Sscottl } 1584130293Sscottl 1585130293Sscottl /* 1586130293Sscottl * XXX buffer (sc_imess) size for message 1587130293Sscottl */ 1588130293Sscottl 1589130293Sscottl n = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF; 1590130293Sscottl 1591130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) { 1592130293Sscottl n *= 2; 1593130293Sscottl 1594130293Sscottl for (i = 0; i < n; i++) 1595180692Smarius ibuf[i] = NCR_READ_REG(sc, NCR_FIFO); 1596130293Sscottl 1597130293Sscottl if (sc->sc_espstat2 & NCRFAS_STAT2_ISHUTTLE) { 1598130293Sscottl 1599130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, 0); 1600180692Smarius ibuf[i++] = NCR_READ_REG(sc, NCR_FIFO); 1601130293Sscottl 1602130293Sscottl NCR_READ_REG(sc, NCR_FIFO); 1603130293Sscottl 1604130293Sscottl ncr53c9x_flushfifo(sc); 1605130293Sscottl } 1606226381Smarius } else 1607130293Sscottl for (i = 0; i < n; i++) 1608180692Smarius ibuf[i] = NCR_READ_REG(sc, NCR_FIFO); 1609130293Sscottl 1610130293Sscottl sc->sc_imlen += i; 1611130293Sscottl 1612130293Sscottl#if 0 1613130293Sscottl#ifdef NCR53C9X_DEBUG 1614180692Smarius NCR_TRACE(("\n[rdfifo %s (%d):", 1615180692Smarius (how == NCR_RDFIFO_START) ? "start" : "cont", (int)sc->sc_imlen)); 1616226381Smarius if ((ncr53c9x_debug & NCR_SHOWTRAC) != 0) { 1617180692Smarius for (i = 0; i < sc->sc_imlen; i++) 1618180692Smarius printf(" %02x", sc->sc_imess[i]); 1619180692Smarius printf("]\n"); 1620130293Sscottl } 1621130293Sscottl#endif 1622130293Sscottl#endif 1623180692Smarius return (sc->sc_imlen); 1624130293Sscottl} 1625130293Sscottl 1626130293Sscottlstatic void 1627226381Smariusncr53c9x_wrfifo(struct ncr53c9x_softc *sc, uint8_t *p, int len) 1628130293Sscottl{ 1629130293Sscottl int i; 1630130293Sscottl 1631182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1632182876Smarius 1633130293Sscottl#ifdef NCR53C9X_DEBUG 1634130293Sscottl NCR_MSGS(("[wrfifo(%d):", len)); 1635226381Smarius if ((ncr53c9x_debug & NCR_SHOWMSGS) != 0) { 1636130293Sscottl for (i = 0; i < len; i++) 1637130293Sscottl printf(" %02x", p[i]); 1638130293Sscottl printf("]\n"); 1639130293Sscottl } 1640130293Sscottl#endif 1641130293Sscottl 1642130293Sscottl for (i = 0; i < len; i++) { 1643130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, p[i]); 1644130293Sscottl 1645130293Sscottl if (sc->sc_rev == NCR_VARIANT_FAS366) 1646130293Sscottl NCR_WRITE_REG(sc, NCR_FIFO, 0); 1647130293Sscottl } 1648130293Sscottl} 1649130293Sscottl 1650130293Sscottlstatic int 1651130293Sscottlncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype, 1652180692Smarius int tagid) 1653130293Sscottl{ 1654130293Sscottl struct ncr53c9x_ecb *ecb = NULL; 1655180692Smarius struct ncr53c9x_linfo *li; 1656130293Sscottl struct ncr53c9x_tinfo *ti; 1657226381Smarius uint8_t lun, selid, target; 1658130293Sscottl 1659182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1660130293Sscottl 1661226381Smarius if (sc->sc_rev == NCR_VARIANT_FAS366) 1662130293Sscottl target = sc->sc_selid; 1663226381Smarius else { 1664130293Sscottl /* 1665130293Sscottl * The SCSI chip made a snapshot of the data bus 1666130293Sscottl * while the reselection was being negotiated. 1667130293Sscottl * This enables us to determine which target did 1668130293Sscottl * the reselect. 1669130293Sscottl */ 1670130293Sscottl selid = sc->sc_selid & ~(1 << sc->sc_id); 1671130293Sscottl if (selid & (selid - 1)) { 1672130293Sscottl device_printf(sc->sc_dev, "reselect with invalid " 1673130293Sscottl "selid %02x; sending DEVICE RESET\n", selid); 1674130293Sscottl goto reset; 1675130293Sscottl } 1676130293Sscottl 1677130293Sscottl target = ffs(selid) - 1; 1678130293Sscottl } 1679130293Sscottl lun = message & 0x07; 1680130293Sscottl 1681130293Sscottl /* 1682180692Smarius * Search wait queue for disconnected command. 1683130293Sscottl * The list should be short, so I haven't bothered with 1684130293Sscottl * any more sophisticated structures than a simple 1685130293Sscottl * singly linked list. 1686130293Sscottl */ 1687130293Sscottl ti = &sc->sc_tinfo[target]; 1688130293Sscottl li = TINFO_LUN(ti, lun); 1689130293Sscottl 1690130293Sscottl /* 1691130293Sscottl * We can get as far as the LUN with the IDENTIFY 1692130293Sscottl * message. Check to see if we're running an 1693180692Smarius * untagged command. Otherwise ack the IDENTIFY 1694130293Sscottl * and wait for a tag message. 1695130293Sscottl */ 1696130293Sscottl if (li != NULL) { 1697130293Sscottl if (li->untagged != NULL && li->busy) 1698130293Sscottl ecb = li->untagged; 1699130293Sscottl else if (tagtype != MSG_SIMPLE_Q_TAG) { 1700180692Smarius /* Wait for tag to come by. */ 1701130293Sscottl sc->sc_state = NCR_IDENTIFIED; 1702130293Sscottl return (0); 1703130293Sscottl } else if (tagtype) 1704130293Sscottl ecb = li->queued[tagid]; 1705130293Sscottl } 1706130293Sscottl if (ecb == NULL) { 1707130293Sscottl device_printf(sc->sc_dev, "reselect from target %d lun %d " 1708130293Sscottl "tag %x:%x with no nexus; sending ABORT\n", 1709130293Sscottl target, lun, tagtype, tagid); 1710130293Sscottl goto abort; 1711130293Sscottl } 1712130293Sscottl 1713130293Sscottl /* Make this nexus active again. */ 1714130293Sscottl sc->sc_state = NCR_CONNECTED; 1715130293Sscottl sc->sc_nexus = ecb; 1716130293Sscottl ncr53c9x_setsync(sc, ti); 1717130293Sscottl 1718130293Sscottl if (ecb->flags & ECB_RESET) 1719130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 1720130293Sscottl else if (ecb->flags & ECB_ABORT) 1721130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 1722130293Sscottl 1723130293Sscottl /* Do an implicit RESTORE POINTERS. */ 1724130293Sscottl sc->sc_dp = ecb->daddr; 1725130293Sscottl sc->sc_dleft = ecb->dleft; 1726130293Sscottl 1727130293Sscottl return (0); 1728130293Sscottl 1729130293Sscottlreset: 1730130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 1731130293Sscottl return (1); 1732130293Sscottl 1733130293Sscottlabort: 1734130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 1735130293Sscottl return (1); 1736130293Sscottl} 1737130293Sscottl 1738180692Smarius/* From NetBSD; these should go into CAM at some point. */ 1739180692Smarius#define MSG_ISEXTENDED(m) ((m) == MSG_EXTENDED) 1740180692Smarius#define MSG_IS1BYTE(m) \ 1741130293Sscottl ((!MSG_ISEXTENDED(m) && (m) < 0x20) || MSG_ISIDENTIFY(m)) 1742180692Smarius#define MSG_IS2BYTE(m) (((m) & 0xf0) == 0x20) 1743130293Sscottl 1744130293Sscottlstatic inline int 1745226381Smarius__verify_msg_format(uint8_t *p, int len) 1746130293Sscottl{ 1747130293Sscottl 1748130293Sscottl if (len == 1 && MSG_IS1BYTE(p[0])) 1749180692Smarius return (1); 1750130293Sscottl if (len == 2 && MSG_IS2BYTE(p[0])) 1751180692Smarius return (1); 1752130293Sscottl if (len >= 3 && MSG_ISEXTENDED(p[0]) && 1753130293Sscottl len == p[1] + 2) 1754180692Smarius return (1); 1755130293Sscottl 1756180692Smarius return (0); 1757130293Sscottl} 1758130293Sscottl 1759130293Sscottl/* 1760130293Sscottl * Get an incoming message as initiator. 1761130293Sscottl * 1762130293Sscottl * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a 1763180692Smarius * byte in the FIFO. 1764130293Sscottl */ 1765130293Sscottlstatic void 1766130293Sscottlncr53c9x_msgin(struct ncr53c9x_softc *sc) 1767130293Sscottl{ 1768180692Smarius struct ncr53c9x_ecb *ecb; 1769180692Smarius struct ncr53c9x_linfo *li; 1770180692Smarius struct ncr53c9x_tinfo *ti; 1771226381Smarius uint8_t *pb; 1772239089Smarius int len, lun; 1773130293Sscottl 1774182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 1775182876Smarius 1776226381Smarius NCR_TRACE(("[%s(curmsglen:%ld)] ", __func__, (long)sc->sc_imlen)); 1777130293Sscottl 1778130293Sscottl if (sc->sc_imlen == 0) { 1779130293Sscottl device_printf(sc->sc_dev, "msgin: no msg byte available\n"); 1780130293Sscottl return; 1781130293Sscottl } 1782130293Sscottl 1783130293Sscottl /* 1784130293Sscottl * Prepare for a new message. A message should (according 1785130293Sscottl * to the SCSI standard) be transmitted in one single 1786180692Smarius * MESSAGE_IN_PHASE. If we have been in some other phase, 1787130293Sscottl * then this is a new message. 1788130293Sscottl */ 1789130293Sscottl if (sc->sc_prevphase != MESSAGE_IN_PHASE && 1790130293Sscottl sc->sc_state != NCR_RESELECTED) { 1791130293Sscottl device_printf(sc->sc_dev, "phase change, dropping message, " 1792130293Sscottl "prev %d, state %d\n", sc->sc_prevphase, sc->sc_state); 1793130293Sscottl sc->sc_flags &= ~NCR_DROP_MSGI; 1794130293Sscottl sc->sc_imlen = 0; 1795130293Sscottl } 1796130293Sscottl 1797130293Sscottl /* 1798130293Sscottl * If we're going to reject the message, don't bother storing 1799130293Sscottl * the incoming bytes. But still, we need to ACK them. 1800130293Sscottl */ 1801130293Sscottl if ((sc->sc_flags & NCR_DROP_MSGI) != 0) { 1802130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 1803182876Smarius device_printf(sc->sc_dev, "<dropping msg byte %x>", 1804182876Smarius sc->sc_imess[sc->sc_imlen]); 1805130293Sscottl return; 1806130293Sscottl } 1807130293Sscottl 1808130293Sscottl if (sc->sc_imlen >= NCR_MAX_MSG_LEN) { 1809130293Sscottl ncr53c9x_sched_msgout(SEND_REJECT); 1810130293Sscottl sc->sc_flags |= NCR_DROP_MSGI; 1811130293Sscottl } else { 1812130293Sscottl switch (sc->sc_state) { 1813130293Sscottl /* 1814130293Sscottl * if received message is the first of reselection 1815130293Sscottl * then first byte is selid, and then message 1816130293Sscottl */ 1817130293Sscottl case NCR_RESELECTED: 1818130293Sscottl pb = sc->sc_imess + 1; 1819239089Smarius len = sc->sc_imlen - 1; 1820130293Sscottl break; 1821180692Smarius 1822130293Sscottl default: 1823130293Sscottl pb = sc->sc_imess; 1824239089Smarius len = sc->sc_imlen; 1825130293Sscottl } 1826130293Sscottl 1827239089Smarius if (__verify_msg_format(pb, len)) 1828130293Sscottl goto gotit; 1829130293Sscottl } 1830130293Sscottl 1831180692Smarius /* Acknowledge what we have so far. */ 1832130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 1833130293Sscottl return; 1834130293Sscottl 1835130293Sscottlgotit: 1836130293Sscottl NCR_MSGS(("gotmsg(%x) state %d", sc->sc_imess[0], sc->sc_state)); 1837180692Smarius /* 1838180692Smarius * We got a complete message, flush the imess. 1839180692Smarius * XXX nobody uses imlen below. 1840180692Smarius */ 1841130293Sscottl sc->sc_imlen = 0; 1842130293Sscottl /* 1843130293Sscottl * Now we should have a complete message (1 byte, 2 byte 1844130293Sscottl * and moderately long extended messages). We only handle 1845130293Sscottl * extended messages which total length is shorter than 1846130293Sscottl * NCR_MAX_MSG_LEN. Longer messages will be amputated. 1847130293Sscottl */ 1848130293Sscottl switch (sc->sc_state) { 1849130293Sscottl case NCR_CONNECTED: 1850130293Sscottl ecb = sc->sc_nexus; 1851130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 1852130293Sscottl 1853130293Sscottl switch (sc->sc_imess[0]) { 1854130293Sscottl case MSG_CMDCOMPLETE: 1855130293Sscottl NCR_MSGS(("cmdcomplete ")); 1856130293Sscottl if (sc->sc_dleft < 0) { 1857130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 1858130293Sscottl printf("got %ld extra bytes\n", 1859130293Sscottl -(long)sc->sc_dleft); 1860130293Sscottl sc->sc_dleft = 0; 1861130293Sscottl } 1862130293Sscottl ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE) ? 1863130293Sscottl 0 : sc->sc_dleft; 1864130293Sscottl if ((ecb->flags & ECB_SENSE) == 0) 1865130293Sscottl ecb->ccb->csio.resid = ecb->dleft; 1866130293Sscottl sc->sc_state = NCR_CMDCOMPLETE; 1867130293Sscottl break; 1868130293Sscottl 1869130293Sscottl case MSG_MESSAGE_REJECT: 1870130293Sscottl NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout)); 1871130293Sscottl switch (sc->sc_msgout) { 1872130293Sscottl case SEND_TAG: 1873130293Sscottl /* 1874130293Sscottl * Target does not like tagged queuing. 1875130293Sscottl * - Flush the command queue 1876130293Sscottl * - Disable tagged queuing for the target 1877130293Sscottl * - Dequeue ecb from the queued array. 1878130293Sscottl */ 1879130293Sscottl device_printf(sc->sc_dev, "tagged queuing " 1880130293Sscottl "rejected: target %d\n", 1881130293Sscottl ecb->ccb->ccb_h.target_id); 1882130293Sscottl 1883130293Sscottl NCR_MSGS(("(rejected sent tag)")); 1884130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 1885130293Sscottl DELAY(1); 1886130293Sscottl ti->flags &= ~T_TAG; 1887130293Sscottl lun = ecb->ccb->ccb_h.target_lun; 1888130293Sscottl li = TINFO_LUN(ti, lun); 1889130293Sscottl if (ecb->tag[0] && 1890130293Sscottl li->queued[ecb->tag[1]] != NULL) { 1891130293Sscottl li->queued[ecb->tag[1]] = NULL; 1892130293Sscottl li->used--; 1893130293Sscottl } 1894130293Sscottl ecb->tag[0] = ecb->tag[1] = 0; 1895130293Sscottl li->untagged = ecb; 1896130293Sscottl li->busy = 1; 1897130293Sscottl break; 1898130293Sscottl 1899130293Sscottl case SEND_SDTR: 1900130293Sscottl device_printf(sc->sc_dev, "sync transfer " 1901130293Sscottl "rejected: target %d\n", 1902130293Sscottl ecb->ccb->ccb_h.target_id); 1903130293Sscottl 1904182876Smarius ti->flags &= ~T_SDTRSENT; 1905182876Smarius ti->curr.period = ti->goal.period = 0; 1906182876Smarius ti->curr.offset = ti->goal.offset = 0; 1907130293Sscottl ncr53c9x_setsync(sc, ti); 1908130293Sscottl break; 1909130293Sscottl 1910130293Sscottl case SEND_WDTR: 1911130293Sscottl device_printf(sc->sc_dev, "wide transfer " 1912130293Sscottl "rejected: target %d\n", 1913130293Sscottl ecb->ccb->ccb_h.target_id); 1914182876Smarius 1915182876Smarius ti->flags &= ~T_WDTRSENT; 1916182876Smarius ti->curr.width = ti->goal.width = 1917182876Smarius MSG_EXT_WDTR_BUS_8_BIT; 1918182876Smarius ncr53c9x_setsync(sc, ti); 1919130293Sscottl break; 1920130293Sscottl 1921130293Sscottl case SEND_INIT_DET_ERR: 1922130293Sscottl goto abort; 1923130293Sscottl } 1924130293Sscottl break; 1925130293Sscottl 1926130293Sscottl case MSG_NOOP: 1927130293Sscottl NCR_MSGS(("noop ")); 1928130293Sscottl break; 1929130293Sscottl 1930130293Sscottl case MSG_HEAD_OF_Q_TAG: 1931130293Sscottl case MSG_SIMPLE_Q_TAG: 1932130293Sscottl case MSG_ORDERED_Q_TAG: 1933130293Sscottl NCR_MSGS(("TAG %x:%x", 1934130293Sscottl sc->sc_imess[0], sc->sc_imess[1])); 1935130293Sscottl break; 1936130293Sscottl 1937130293Sscottl case MSG_DISCONNECT: 1938130293Sscottl NCR_MSGS(("disconnect ")); 1939130293Sscottl ti->dconns++; 1940130293Sscottl sc->sc_state = NCR_DISCONNECT; 1941130293Sscottl 1942130293Sscottl /* 1943180692Smarius * Mark the fact that all bytes have moved. The 1944130293Sscottl * target may not bother to do a SAVE POINTERS 1945180692Smarius * at this stage. This flag will set the residual 1946130293Sscottl * count to zero on MSG COMPLETE. 1947130293Sscottl */ 1948130293Sscottl if (sc->sc_dleft == 0) 1949130293Sscottl ecb->flags |= ECB_TENTATIVE_DONE; 1950130293Sscottl break; 1951130293Sscottl 1952130293Sscottl case MSG_SAVEDATAPOINTER: 1953130293Sscottl NCR_MSGS(("save datapointer ")); 1954130293Sscottl ecb->daddr = sc->sc_dp; 1955130293Sscottl ecb->dleft = sc->sc_dleft; 1956130293Sscottl break; 1957130293Sscottl 1958130293Sscottl case MSG_RESTOREPOINTERS: 1959130293Sscottl NCR_MSGS(("restore datapointer ")); 1960130293Sscottl sc->sc_dp = ecb->daddr; 1961130293Sscottl sc->sc_dleft = ecb->dleft; 1962130293Sscottl break; 1963130293Sscottl 1964239089Smarius case MSG_IGN_WIDE_RESIDUE: 1965239089Smarius NCR_MSGS(("ignore wide residue (%d bytes)", 1966239089Smarius sc->sc_imess[1])); 1967239089Smarius if (sc->sc_imess[1] != 1) { 1968239089Smarius xpt_print_path(ecb->ccb->ccb_h.path); 1969239089Smarius printf("unexpected MESSAGE IGNORE WIDE " 1970239089Smarius "RESIDUE (%d bytes); sending REJECT\n", 1971239089Smarius sc->sc_imess[1]); 1972239089Smarius goto reject; 1973239089Smarius } 1974239089Smarius /* 1975239089Smarius * If there was a last transfer of an even number of 1976239089Smarius * bytes, wipe the "done" memory and adjust by one 1977239089Smarius * byte (sc->sc_imess[1]). 1978239089Smarius */ 1979239089Smarius len = sc->sc_dleft - ecb->dleft; 1980239089Smarius if (len != 0 && (len & 1) == 0) { 1981239089Smarius ecb->flags &= ~ECB_TENTATIVE_DONE; 1982239089Smarius sc->sc_dp = (char *)sc->sc_dp - 1; 1983239089Smarius sc->sc_dleft--; 1984239089Smarius } 1985239089Smarius break; 1986239089Smarius 1987130293Sscottl case MSG_EXTENDED: 1988130293Sscottl NCR_MSGS(("extended(%x) ", sc->sc_imess[2])); 1989130293Sscottl switch (sc->sc_imess[2]) { 1990130293Sscottl case MSG_EXT_SDTR: 1991130293Sscottl NCR_MSGS(("SDTR period %d, offset %d ", 1992130293Sscottl sc->sc_imess[3], sc->sc_imess[4])); 1993130293Sscottl if (sc->sc_imess[1] != 3) 1994130293Sscottl goto reject; 1995182876Smarius ti->curr.period = sc->sc_imess[3]; 1996182876Smarius ti->curr.offset = sc->sc_imess[4]; 1997130293Sscottl if (sc->sc_minsync == 0 || 1998182876Smarius ti->curr.offset == 0 || 1999182876Smarius ti->curr.period > 124) { 2000130293Sscottl#if 0 2001130293Sscottl#ifdef NCR53C9X_DEBUG 2002130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 2003130293Sscottl printf("async mode\n"); 2004130293Sscottl#endif 2005130293Sscottl#endif 2006182876Smarius if ((ti->flags & T_SDTRSENT) == 0) { 2007130293Sscottl /* 2008130293Sscottl * target initiated negotiation 2009130293Sscottl */ 2010182876Smarius ti->curr.offset = 0; 2011130293Sscottl ncr53c9x_sched_msgout( 2012130293Sscottl SEND_SDTR); 2013130293Sscottl } 2014130293Sscottl } else { 2015182876Smarius ti->curr.period = 2016180692Smarius ncr53c9x_cpb2stp(sc, 2017180692Smarius ncr53c9x_stp2cpb(sc, 2018182876Smarius ti->curr.period)); 2019182876Smarius if ((ti->flags & T_SDTRSENT) == 0) { 2020130293Sscottl /* 2021130293Sscottl * target initiated negotiation 2022130293Sscottl */ 2023182876Smarius if (ti->curr.period < 2024182876Smarius sc->sc_minsync) 2025182876Smarius ti->curr.period = 2026130293Sscottl sc->sc_minsync; 2027182876Smarius if (ti->curr.offset > 2028182876Smarius sc->sc_maxoffset) 2029182876Smarius ti->curr.offset = 2030182876Smarius sc->sc_maxoffset; 2031130293Sscottl ncr53c9x_sched_msgout( 2032130293Sscottl SEND_SDTR); 2033130293Sscottl } 2034130293Sscottl } 2035182876Smarius ti->flags &= ~T_SDTRSENT; 2036182876Smarius ti->goal.period = ti->curr.period; 2037182876Smarius ti->goal.offset = ti->curr.offset; 2038130293Sscottl ncr53c9x_setsync(sc, ti); 2039130293Sscottl break; 2040130293Sscottl 2041130293Sscottl case MSG_EXT_WDTR: 2042182876Smarius NCR_MSGS(("wide mode %d ", sc->sc_imess[3])); 2043182876Smarius ti->curr.width = sc->sc_imess[3]; 2044130293Sscottl if (!(ti->flags & T_WDTRSENT)) 2045182876Smarius /* 2046182876Smarius * target initiated negotiation 2047182876Smarius */ 2048130293Sscottl ncr53c9x_sched_msgout(SEND_WDTR); 2049182876Smarius ti->flags &= ~T_WDTRSENT; 2050182876Smarius ti->goal.width = ti->curr.width; 2051182876Smarius ncr53c9x_setsync(sc, ti); 2052130293Sscottl break; 2053180692Smarius 2054130293Sscottl default: 2055130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 2056226947Smarius printf("unrecognized MESSAGE EXTENDED 0x%x;" 2057226947Smarius " sending REJECT\n", sc->sc_imess[2]); 2058130293Sscottl goto reject; 2059130293Sscottl } 2060130293Sscottl break; 2061130293Sscottl 2062130293Sscottl default: 2063130293Sscottl NCR_MSGS(("ident ")); 2064130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 2065226947Smarius printf("unrecognized MESSAGE 0x%x; sending REJECT\n", 2066226947Smarius sc->sc_imess[0]); 2067180692Smarius /* FALLTHROUGH */ 2068130293Sscottl reject: 2069130293Sscottl ncr53c9x_sched_msgout(SEND_REJECT); 2070130293Sscottl break; 2071130293Sscottl } 2072130293Sscottl break; 2073130293Sscottl 2074130293Sscottl case NCR_IDENTIFIED: 2075130293Sscottl /* 2076180692Smarius * IDENTIFY message was received and queue tag is expected 2077180692Smarius * now. 2078145202Smarius */ 2079130293Sscottl if ((sc->sc_imess[0] != MSG_SIMPLE_Q_TAG) || 2080130293Sscottl (sc->sc_msgify == 0)) { 2081130293Sscottl device_printf(sc->sc_dev, "TAG reselect without " 2082130293Sscottl "IDENTIFY; MSG %x; sending DEVICE RESET\n", 2083180692Smarius sc->sc_imess[0]); 2084130293Sscottl goto reset; 2085130293Sscottl } 2086226381Smarius (void)ncr53c9x_reselect(sc, sc->sc_msgify, 2087130293Sscottl sc->sc_imess[0], sc->sc_imess[1]); 2088130293Sscottl break; 2089130293Sscottl 2090130293Sscottl case NCR_RESELECTED: 2091226381Smarius if (MSG_ISIDENTIFY(sc->sc_imess[1])) 2092130293Sscottl sc->sc_msgify = sc->sc_imess[1]; 2093226381Smarius else { 2094130293Sscottl device_printf(sc->sc_dev, "reselect without IDENTIFY;" 2095130293Sscottl " MSG %x; sending DEVICE RESET\n", sc->sc_imess[1]); 2096130293Sscottl goto reset; 2097130293Sscottl } 2098226381Smarius (void)ncr53c9x_reselect(sc, sc->sc_msgify, 0, 0); 2099130293Sscottl break; 2100130293Sscottl 2101130293Sscottl default: 2102130293Sscottl device_printf(sc->sc_dev, "unexpected MESSAGE IN; " 2103130293Sscottl "sending DEVICE RESET\n"); 2104180692Smarius /* FALLTHROUGH */ 2105130293Sscottl reset: 2106130293Sscottl ncr53c9x_sched_msgout(SEND_DEV_RESET); 2107130293Sscottl break; 2108130293Sscottl 2109130293Sscottl abort: 2110130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 2111130293Sscottl } 2112130293Sscottl 2113180692Smarius /* If we have more messages to send set ATN. */ 2114182876Smarius if (sc->sc_msgpriq) { 2115130293Sscottl NCRCMD(sc, NCRCMD_SETATN); 2116182876Smarius sc->sc_flags |= NCR_ATN; 2117182876Smarius } 2118130293Sscottl 2119180692Smarius /* Acknowledge last message byte. */ 2120130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 2121130293Sscottl 2122130293Sscottl /* Done, reset message pointer. */ 2123130293Sscottl sc->sc_flags &= ~NCR_DROP_MSGI; 2124130293Sscottl sc->sc_imlen = 0; 2125130293Sscottl} 2126130293Sscottl 2127130293Sscottl/* 2128180692Smarius * Send the highest priority, scheduled message. 2129130293Sscottl */ 2130130293Sscottlstatic void 2131130293Sscottlncr53c9x_msgout(struct ncr53c9x_softc *sc) 2132130293Sscottl{ 2133130293Sscottl struct ncr53c9x_tinfo *ti; 2134130293Sscottl struct ncr53c9x_ecb *ecb; 2135130293Sscottl size_t size; 2136226947Smarius int error; 2137180692Smarius#ifdef NCR53C9X_DEBUG 2138180692Smarius int i; 2139180692Smarius#endif 2140130293Sscottl 2141182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 2142182876Smarius 2143226381Smarius NCR_TRACE(("[%s(priq:%x, prevphase:%x)]", __func__, sc->sc_msgpriq, 2144226381Smarius sc->sc_prevphase)); 2145130293Sscottl 2146130293Sscottl /* 2147130293Sscottl * XXX - the NCR_ATN flag is not in sync with the actual ATN 2148180692Smarius * condition on the SCSI bus. The 53c9x chip 2149130293Sscottl * automatically turns off ATN before sending the 2150133039Strhodes * message byte. (See also the comment below in the 2151133039Strhodes * default case when picking out a message to send.) 2152130293Sscottl */ 2153130293Sscottl if (sc->sc_flags & NCR_ATN) { 2154130293Sscottl if (sc->sc_prevphase != MESSAGE_OUT_PHASE) { 2155130293Sscottl new: 2156130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2157226381Smarius#if 0 2158226381Smarius DELAY(1); 2159226381Smarius#endif 2160130293Sscottl sc->sc_msgoutq = 0; 2161130293Sscottl sc->sc_omlen = 0; 2162130293Sscottl } 2163130293Sscottl } else { 2164130293Sscottl if (sc->sc_prevphase == MESSAGE_OUT_PHASE) { 2165130293Sscottl ncr53c9x_sched_msgout(sc->sc_msgoutq); 2166130293Sscottl goto new; 2167226381Smarius } else 2168130293Sscottl device_printf(sc->sc_dev, "at line %d: unexpected " 2169130293Sscottl "MESSAGE OUT phase\n", __LINE__); 2170130293Sscottl } 2171130293Sscottl 2172130293Sscottl if (sc->sc_omlen == 0) { 2173180692Smarius /* Pick up highest priority message. */ 2174130293Sscottl sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; 2175130293Sscottl sc->sc_msgoutq |= sc->sc_msgout; 2176130293Sscottl sc->sc_msgpriq &= ~sc->sc_msgout; 2177130293Sscottl sc->sc_omlen = 1; /* "Default" message len */ 2178130293Sscottl switch (sc->sc_msgout) { 2179130293Sscottl case SEND_SDTR: 2180130293Sscottl ecb = sc->sc_nexus; 2181130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2182130293Sscottl sc->sc_omess[0] = MSG_EXTENDED; 2183130293Sscottl sc->sc_omess[1] = MSG_EXT_SDTR_LEN; 2184130293Sscottl sc->sc_omess[2] = MSG_EXT_SDTR; 2185182876Smarius sc->sc_omess[3] = ti->goal.period; 2186182876Smarius sc->sc_omess[4] = ti->goal.offset; 2187130293Sscottl sc->sc_omlen = 5; 2188130293Sscottl break; 2189180692Smarius 2190130293Sscottl case SEND_WDTR: 2191130293Sscottl ecb = sc->sc_nexus; 2192130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2193130293Sscottl sc->sc_omess[0] = MSG_EXTENDED; 2194130293Sscottl sc->sc_omess[1] = MSG_EXT_WDTR_LEN; 2195130293Sscottl sc->sc_omess[2] = MSG_EXT_WDTR; 2196182876Smarius sc->sc_omess[3] = ti->goal.width; 2197130293Sscottl sc->sc_omlen = 4; 2198130293Sscottl break; 2199180692Smarius 2200180692Smarius case SEND_IDENTIFY: 2201226381Smarius if (sc->sc_state != NCR_CONNECTED) 2202180692Smarius device_printf(sc->sc_dev, "at line %d: no " 2203130293Sscottl "nexus\n", __LINE__); 2204180692Smarius ecb = sc->sc_nexus; 2205180692Smarius sc->sc_omess[0] = 2206180692Smarius MSG_IDENTIFY(ecb->ccb->ccb_h.target_lun, 0); 2207180692Smarius break; 2208180692Smarius 2209130293Sscottl case SEND_TAG: 2210226381Smarius if (sc->sc_state != NCR_CONNECTED) 2211130293Sscottl device_printf(sc->sc_dev, "at line %d: no " 2212130293Sscottl "nexus\n", __LINE__); 2213130293Sscottl ecb = sc->sc_nexus; 2214130293Sscottl sc->sc_omess[0] = ecb->tag[0]; 2215130293Sscottl sc->sc_omess[1] = ecb->tag[1]; 2216130293Sscottl sc->sc_omlen = 2; 2217130293Sscottl break; 2218180692Smarius 2219130293Sscottl case SEND_DEV_RESET: 2220130293Sscottl sc->sc_flags |= NCR_ABORTING; 2221130293Sscottl sc->sc_omess[0] = MSG_BUS_DEV_RESET; 2222130293Sscottl ecb = sc->sc_nexus; 2223130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2224182876Smarius ti->curr.period = 0; 2225182876Smarius ti->curr.offset = 0; 2226182876Smarius ti->curr.width = MSG_EXT_WDTR_BUS_8_BIT; 2227130293Sscottl break; 2228180692Smarius 2229130293Sscottl case SEND_PARITY_ERROR: 2230130293Sscottl sc->sc_omess[0] = MSG_PARITY_ERROR; 2231130293Sscottl break; 2232180692Smarius 2233130293Sscottl case SEND_ABORT: 2234130293Sscottl sc->sc_flags |= NCR_ABORTING; 2235130293Sscottl sc->sc_omess[0] = MSG_ABORT; 2236130293Sscottl break; 2237180692Smarius 2238130293Sscottl case SEND_INIT_DET_ERR: 2239130293Sscottl sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; 2240130293Sscottl break; 2241180692Smarius 2242130293Sscottl case SEND_REJECT: 2243130293Sscottl sc->sc_omess[0] = MSG_MESSAGE_REJECT; 2244130293Sscottl break; 2245180692Smarius 2246130293Sscottl default: 2247130293Sscottl /* 2248130293Sscottl * We normally do not get here, since the chip 2249130293Sscottl * automatically turns off ATN before the last 2250130293Sscottl * byte of a message is sent to the target. 2251130293Sscottl * However, if the target rejects our (multi-byte) 2252130293Sscottl * message early by switching to MSG IN phase 2253130293Sscottl * ATN remains on, so the target may return to 2254180692Smarius * MSG OUT phase. If there are no scheduled messages 2255130293Sscottl * left we send a NO-OP. 2256130293Sscottl * 2257130293Sscottl * XXX - Note that this leaves no useful purpose for 2258130293Sscottl * the NCR_ATN flag. 2259130293Sscottl */ 2260130293Sscottl sc->sc_flags &= ~NCR_ATN; 2261130293Sscottl sc->sc_omess[0] = MSG_NOOP; 2262130293Sscottl } 2263130293Sscottl sc->sc_omp = sc->sc_omess; 2264130293Sscottl } 2265130293Sscottl 2266180692Smarius#ifdef NCR53C9X_DEBUG 2267226381Smarius if ((ncr53c9x_debug & NCR_SHOWMSGS) != 0) { 2268130293Sscottl NCR_MSGS(("<msgout:")); 2269145202Smarius for (i = 0; i < sc->sc_omlen; i++) 2270130293Sscottl NCR_MSGS((" %02x", sc->sc_omess[i])); 2271130293Sscottl NCR_MSGS(("> ")); 2272130293Sscottl } 2273130293Sscottl#endif 2274226947Smarius 2275226947Smarius if (sc->sc_rev != NCR_VARIANT_FAS366) { 2276180692Smarius /* (Re)send the message. */ 2277182876Smarius size = ulmin(sc->sc_omlen, sc->sc_maxxfer); 2278226947Smarius error = NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size); 2279226947Smarius if (error != 0) 2280226947Smarius goto cmd; 2281226947Smarius 2282180692Smarius /* Program the SCSI counter. */ 2283130293Sscottl NCR_SET_COUNT(sc, size); 2284130293Sscottl 2285180692Smarius /* Load the count in and start the message-out transfer. */ 2286180692Smarius NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); 2287180692Smarius NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA); 2288130293Sscottl NCRDMA_GO(sc); 2289226947Smarius return; 2290130293Sscottl } 2291226947Smarius 2292226947Smariuscmd: 2293226947Smarius /* 2294226947Smarius * XXX FIFO size 2295226947Smarius */ 2296239089Smarius sc->sc_cmdlen = 0; 2297226947Smarius ncr53c9x_flushfifo(sc); 2298226947Smarius ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen); 2299226947Smarius NCRCMD(sc, NCRCMD_TRANS); 2300130293Sscottl} 2301130293Sscottl 2302182876Smariusvoid 2303182876Smariusncr53c9x_intr(void *arg) 2304182876Smarius{ 2305182876Smarius struct ncr53c9x_softc *sc = arg; 2306182876Smarius 2307182876Smarius if (!NCRDMA_ISINTR(sc)) 2308182876Smarius return; 2309182876Smarius 2310182876Smarius NCR_LOCK(sc); 2311182876Smarius 2312182876Smarius ncr53c9x_intr1(sc); 2313182876Smarius 2314182876Smarius NCR_UNLOCK(sc); 2315182876Smarius} 2316182876Smarius 2317130293Sscottl/* 2318130293Sscottl * This is the most critical part of the driver, and has to know 2319130293Sscottl * how to deal with *all* error conditions and phases from the SCSI 2320180692Smarius * bus. If there are no errors and the DMA was active, then call the 2321180692Smarius * DMA pseudo-interrupt handler. If this returns 1, then that was it 2322130293Sscottl * and we can return from here without further processing. 2323130293Sscottl * 2324130293Sscottl * Most of this needs verifying. 2325130293Sscottl */ 2326182876Smariusstatic void 2327182876Smariusncr53c9x_intr1(struct ncr53c9x_softc *sc) 2328130293Sscottl{ 2329130293Sscottl struct ncr53c9x_ecb *ecb; 2330180692Smarius struct ncr53c9x_linfo *li; 2331130293Sscottl struct ncr53c9x_tinfo *ti; 2332180692Smarius struct timeval cur, wait; 2333130293Sscottl size_t size; 2334226947Smarius int error, i, nfifo; 2335226381Smarius uint8_t msg; 2336130293Sscottl 2337182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 2338182876Smarius 2339130293Sscottl NCR_INTS(("[ncr53c9x_intr: state %d]", sc->sc_state)); 2340130293Sscottl 2341130293Sscottlagain: 2342130293Sscottl /* and what do the registers say... */ 2343130293Sscottl ncr53c9x_readregs(sc); 2344130293Sscottl 2345130293Sscottl /* 2346130293Sscottl * At the moment, only a SCSI Bus Reset or Illegal 2347180692Smarius * Command are classed as errors. A disconnect is a 2348130293Sscottl * valid condition, and we let the code check is the 2349130293Sscottl * "NCR_BUSFREE_OK" flag was set before declaring it 2350130293Sscottl * and error. 2351130293Sscottl * 2352130293Sscottl * Also, the status register tells us about "Gross 2353180692Smarius * Errors" and "Parity errors". Only the Gross Error 2354130293Sscottl * is really bad, and the parity errors are dealt 2355180692Smarius * with later. 2356130293Sscottl * 2357130293Sscottl * TODO 2358130293Sscottl * If there are too many parity error, go to slow 2359180692Smarius * cable mode? 2360130293Sscottl */ 2361130293Sscottl 2362130293Sscottl if ((sc->sc_espintr & NCRINTR_SBR) != 0) { 2363130293Sscottl if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) != 0) { 2364130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2365130293Sscottl DELAY(1); 2366130293Sscottl } 2367130293Sscottl if (sc->sc_state != NCR_SBR) { 2368130293Sscottl device_printf(sc->sc_dev, "SCSI bus reset\n"); 2369180692Smarius ncr53c9x_init(sc, 0); /* Restart everything. */ 2370182876Smarius return; 2371130293Sscottl } 2372130293Sscottl#if 0 2373182876Smarius/*XXX*/ device_printf(sc->sc_dev, "<expected bus reset: " 2374130293Sscottl "[intr %x, stat %x, step %d]>\n", 2375130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2376130293Sscottl#endif 2377130293Sscottl if (sc->sc_nexus != NULL) 2378130293Sscottl panic("%s: nexus in reset state", 2379130293Sscottl device_get_nameunit(sc->sc_dev)); 2380130293Sscottl goto sched; 2381130293Sscottl } 2382130293Sscottl 2383130293Sscottl ecb = sc->sc_nexus; 2384130293Sscottl 2385180692Smarius#define NCRINTR_ERR (NCRINTR_SBR | NCRINTR_ILL) 2386130293Sscottl if (sc->sc_espintr & NCRINTR_ERR || 2387130293Sscottl sc->sc_espstat & NCRSTAT_GE) { 2388130293Sscottl if ((sc->sc_espstat & NCRSTAT_GE) != 0) { 2389180692Smarius /* Gross Error; no target? */ 2390130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2391130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2392130293Sscottl DELAY(1); 2393130293Sscottl } 2394130293Sscottl if (sc->sc_state == NCR_CONNECTED || 2395130293Sscottl sc->sc_state == NCR_SELECTING) { 2396130293Sscottl ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2397130293Sscottl ncr53c9x_done(sc, ecb); 2398130293Sscottl } 2399182876Smarius return; 2400130293Sscottl } 2401130293Sscottl 2402130293Sscottl if ((sc->sc_espintr & NCRINTR_ILL) != 0) { 2403130293Sscottl if ((sc->sc_flags & NCR_EXPECT_ILLCMD) != 0) { 2404130293Sscottl /* 2405130293Sscottl * Eat away "Illegal command" interrupt 2406130293Sscottl * on a ESP100 caused by a re-selection 2407130293Sscottl * while we were trying to select 2408130293Sscottl * another target. 2409130293Sscottl */ 2410226381Smarius#ifdef NCR53C9X_DEBUG 2411130293Sscottl device_printf(sc->sc_dev, "ESP100 work-around " 2412130293Sscottl "activated\n"); 2413130293Sscottl#endif 2414130293Sscottl sc->sc_flags &= ~NCR_EXPECT_ILLCMD; 2415182876Smarius return; 2416130293Sscottl } 2417180692Smarius /* Illegal command, out of sync? */ 2418130293Sscottl device_printf(sc->sc_dev, "illegal command: 0x%x " 2419130293Sscottl "(state %d, phase %x, prevphase %x)\n", 2420130293Sscottl sc->sc_lastcmd, 2421130293Sscottl sc->sc_state, sc->sc_phase, sc->sc_prevphase); 2422130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2423130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2424130293Sscottl DELAY(1); 2425130293Sscottl } 2426182876Smarius goto reset; 2427130293Sscottl } 2428130293Sscottl } 2429130293Sscottl sc->sc_flags &= ~NCR_EXPECT_ILLCMD; 2430130293Sscottl 2431130293Sscottl /* 2432130293Sscottl * Call if DMA is active. 2433130293Sscottl * 2434130293Sscottl * If DMA_INTR returns true, then maybe go 'round the loop 2435130293Sscottl * again in case there is no more DMA queued, but a phase 2436130293Sscottl * change is expected. 2437130293Sscottl */ 2438130293Sscottl if (NCRDMA_ISACTIVE(sc)) { 2439180692Smarius if (NCRDMA_INTR(sc) == -1) { 2440130293Sscottl device_printf(sc->sc_dev, "DMA error; resetting\n"); 2441182876Smarius goto reset; 2442130293Sscottl } 2443130293Sscottl /* If DMA active here, then go back to work... */ 2444130293Sscottl if (NCRDMA_ISACTIVE(sc)) 2445182876Smarius return; 2446130293Sscottl 2447130293Sscottl if ((sc->sc_espstat & NCRSTAT_TC) == 0) { 2448130293Sscottl /* 2449130293Sscottl * DMA not completed. If we can not find a 2450130293Sscottl * acceptable explanation, print a diagnostic. 2451130293Sscottl */ 2452130293Sscottl if (sc->sc_state == NCR_SELECTING) 2453130293Sscottl /* 2454130293Sscottl * This can happen if we are reselected 2455130293Sscottl * while using DMA to select a target. 2456130293Sscottl */ 2457130293Sscottl /*void*/; 2458130293Sscottl else if (sc->sc_prevphase == MESSAGE_OUT_PHASE) { 2459130293Sscottl /* 2460130293Sscottl * Our (multi-byte) message (eg SDTR) was 2461130293Sscottl * interrupted by the target to send 2462130293Sscottl * a MSG REJECT. 2463130293Sscottl * Print diagnostic if current phase 2464130293Sscottl * is not MESSAGE IN. 2465130293Sscottl */ 2466130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) 2467130293Sscottl device_printf(sc->sc_dev,"!TC on MSGOUT" 2468130293Sscottl " [intr %x, stat %x, step %d]" 2469130293Sscottl " prevphase %x, resid %lx\n", 2470130293Sscottl sc->sc_espintr, 2471130293Sscottl sc->sc_espstat, 2472130293Sscottl sc->sc_espstep, 2473130293Sscottl sc->sc_prevphase, 2474130293Sscottl (u_long)sc->sc_omlen); 2475130293Sscottl } else if (sc->sc_dleft == 0) { 2476130293Sscottl /* 2477130293Sscottl * The DMA operation was started for 2478180692Smarius * a DATA transfer. Print a diagnostic 2479130293Sscottl * if the DMA counter and TC bit 2480130293Sscottl * appear to be out of sync. 2481145386Sscottl * 2482145386Sscottl * XXX This is fatal and usually means that 2483145386Sscottl * the DMA engine is hopelessly out of 2484145386Sscottl * sync with reality. A disk is likely 2485145386Sscottl * getting spammed at this point. 2486130293Sscottl */ 2487130293Sscottl device_printf(sc->sc_dev, "!TC on DATA XFER" 2488130293Sscottl " [intr %x, stat %x, step %d]" 2489130293Sscottl " prevphase %x, resid %x\n", 2490130293Sscottl sc->sc_espintr, 2491130293Sscottl sc->sc_espstat, 2492130293Sscottl sc->sc_espstep, 2493130293Sscottl sc->sc_prevphase, 2494130293Sscottl ecb ? ecb->dleft : -1); 2495182876Smarius goto reset; 2496130293Sscottl } 2497130293Sscottl } 2498130293Sscottl } 2499130293Sscottl 2500130293Sscottl /* 2501130293Sscottl * Check for less serious errors. 2502130293Sscottl */ 2503130293Sscottl if ((sc->sc_espstat & NCRSTAT_PE) != 0) { 2504130293Sscottl device_printf(sc->sc_dev, "SCSI bus parity error\n"); 2505130293Sscottl if (sc->sc_prevphase == MESSAGE_IN_PHASE) 2506130293Sscottl ncr53c9x_sched_msgout(SEND_PARITY_ERROR); 2507130293Sscottl else 2508130293Sscottl ncr53c9x_sched_msgout(SEND_INIT_DET_ERR); 2509130293Sscottl } 2510130293Sscottl 2511130293Sscottl if ((sc->sc_espintr & NCRINTR_DIS) != 0) { 2512130293Sscottl sc->sc_msgify = 0; 2513130293Sscottl NCR_INTS(("<DISC [intr %x, stat %x, step %d]>", 2514130293Sscottl sc->sc_espintr,sc->sc_espstat,sc->sc_espstep)); 2515130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2516130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2517226381Smarius#if 0 2518226381Smarius DELAY(1); 2519226381Smarius#endif 2520130293Sscottl } 2521130293Sscottl /* 2522130293Sscottl * This command must (apparently) be issued within 2523180692Smarius * 250mS of a disconnect. So here you are... 2524130293Sscottl */ 2525130293Sscottl NCRCMD(sc, NCRCMD_ENSEL); 2526130293Sscottl 2527130293Sscottl switch (sc->sc_state) { 2528130293Sscottl case NCR_RESELECTED: 2529130293Sscottl goto sched; 2530130293Sscottl 2531130293Sscottl case NCR_SELECTING: 2532130293Sscottl ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2533130293Sscottl 2534180692Smarius /* Selection timeout -- discard all LUNs if empty. */ 2535130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2536130293Sscottl li = LIST_FIRST(&ti->luns); 2537130293Sscottl while (li != NULL) { 2538130293Sscottl if (li->untagged == NULL && li->used == 0) { 2539130293Sscottl if (li->lun < NCR_NLUN) 2540130293Sscottl ti->lun[li->lun] = NULL; 2541130293Sscottl LIST_REMOVE(li, link); 2542130293Sscottl free(li, M_DEVBUF); 2543130293Sscottl /* 2544180692Smarius * Restart the search at the beginning. 2545130293Sscottl */ 2546130293Sscottl li = LIST_FIRST(&ti->luns); 2547130293Sscottl continue; 2548130293Sscottl } 2549130293Sscottl li = LIST_NEXT(li, link); 2550130293Sscottl } 2551130293Sscottl goto finish; 2552180692Smarius 2553130293Sscottl case NCR_CONNECTED: 2554182876Smarius if (ecb != NULL) { 2555182876Smarius ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2556182876Smarius if ((ti->flags & T_SDTRSENT) != 0) { 2557130293Sscottl xpt_print_path(ecb->ccb->ccb_h.path); 2558182876Smarius printf("sync nego not completed!\n"); 2559182876Smarius ti->flags &= ~T_SDTRSENT; 2560182876Smarius ti->curr.period = ti->goal.period = 0; 2561182876Smarius ti->curr.offset = ti->goal.offset = 0; 2562182876Smarius ncr53c9x_setsync(sc, ti); 2563182876Smarius } 2564182876Smarius if ((ti->flags & T_WDTRSENT) != 0) { 2565182876Smarius xpt_print_path(ecb->ccb->ccb_h.path); 2566182876Smarius printf("wide nego not completed!\n"); 2567182876Smarius ti->flags &= ~T_WDTRSENT; 2568182876Smarius ti->curr.width = ti->goal.width = 2569182876Smarius MSG_EXT_WDTR_BUS_8_BIT; 2570182876Smarius ncr53c9x_setsync(sc, ti); 2571182876Smarius } 2572130293Sscottl } 2573130293Sscottl 2574180692Smarius /* It may be OK to disconnect. */ 2575130293Sscottl if ((sc->sc_flags & NCR_ABORTING) == 0) { 2576130293Sscottl /* 2577130293Sscottl * Section 5.1.1 of the SCSI 2 spec 2578130293Sscottl * suggests issuing a REQUEST SENSE 2579130293Sscottl * following an unexpected disconnect. 2580130293Sscottl * Some devices go into a contingent 2581130293Sscottl * allegiance condition when 2582130293Sscottl * disconnecting, and this is necessary 2583130293Sscottl * to clean up their state. 2584130293Sscottl */ 2585130293Sscottl device_printf(sc->sc_dev, "unexpected " 2586130293Sscottl "disconnect [state %d, intr %x, stat %x, " 2587130293Sscottl "phase(c %x, p %x)]; ", sc->sc_state, 2588130293Sscottl sc->sc_espintr, sc->sc_espstat, 2589130293Sscottl sc->sc_phase, sc->sc_prevphase); 2590130293Sscottl 2591145535Sscottl /* 2592145535Sscottl * XXX This will cause a chip reset and will 2593145535Sscottl * prevent us from finding out the real 2594145535Sscottl * problem with the device. However, it's 2595220951Smarius * necessary until a way can be found to 2596145535Sscottl * safely cancel the DMA that is in 2597145535Sscottl * progress. 2598145535Sscottl */ 2599145535Sscottl if (1 || (ecb->flags & ECB_SENSE) != 0) { 2600130293Sscottl printf("resetting\n"); 2601130293Sscottl goto reset; 2602130293Sscottl } 2603130293Sscottl printf("sending REQUEST SENSE\n"); 2604182876Smarius callout_stop(&ecb->ch); 2605130293Sscottl ncr53c9x_sense(sc, ecb); 2606182876Smarius return; 2607182876Smarius } else if (ecb != NULL && 2608182876Smarius (ecb->flags & ECB_RESET) != 0) { 2609182876Smarius ecb->ccb->ccb_h.status = CAM_REQ_CMP; 2610182876Smarius goto finish; 2611130293Sscottl } 2612130293Sscottl 2613130293Sscottl ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT; 2614130293Sscottl goto finish; 2615130293Sscottl 2616130293Sscottl case NCR_DISCONNECT: 2617130293Sscottl sc->sc_nexus = NULL; 2618130293Sscottl goto sched; 2619130293Sscottl 2620130293Sscottl case NCR_CMDCOMPLETE: 2621130293Sscottl ecb->ccb->ccb_h.status = CAM_REQ_CMP; 2622130293Sscottl goto finish; 2623130293Sscottl } 2624130293Sscottl } 2625130293Sscottl 2626130293Sscottl switch (sc->sc_state) { 2627130293Sscottl case NCR_SBR: 2628130293Sscottl device_printf(sc->sc_dev, "waiting for Bus Reset to happen\n"); 2629182876Smarius return; 2630130293Sscottl 2631130293Sscottl case NCR_RESELECTED: 2632130293Sscottl /* 2633180692Smarius * We must be continuing a message? 2634130293Sscottl */ 2635130293Sscottl device_printf(sc->sc_dev, "unhandled reselect continuation, " 2636180692Smarius "state %d, intr %02x\n", sc->sc_state, sc->sc_espintr); 2637182876Smarius goto reset; 2638130293Sscottl break; 2639130293Sscottl 2640130293Sscottl case NCR_IDENTIFIED: 2641130293Sscottl ecb = sc->sc_nexus; 2642130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) { 2643180692Smarius i = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF; 2644180692Smarius /* 2645145202Smarius * Things are seriously screwed up. 2646180692Smarius * Pull the brakes, i.e. reset. 2647130293Sscottl */ 2648130293Sscottl device_printf(sc->sc_dev, "target didn't send tag: %d " 2649180692Smarius "bytes in FIFO\n", i); 2650180692Smarius /* Drain and display FIFO. */ 2651130293Sscottl while (i-- > 0) 2652130293Sscottl printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO)); 2653130293Sscottl 2654182876Smarius goto reset; 2655130293Sscottl } else 2656130293Sscottl goto msgin; 2657130293Sscottl 2658130293Sscottl case NCR_IDLE: 2659130293Sscottl case NCR_SELECTING: 2660130293Sscottl ecb = sc->sc_nexus; 2661130293Sscottl if (sc->sc_espintr & NCRINTR_RESEL) { 2662130293Sscottl sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; 2663130293Sscottl sc->sc_flags = 0; 2664130293Sscottl /* 2665130293Sscottl * If we're trying to select a 2666130293Sscottl * target ourselves, push our command 2667130293Sscottl * back into the ready list. 2668130293Sscottl */ 2669130293Sscottl if (sc->sc_state == NCR_SELECTING) { 2670130293Sscottl NCR_INTS(("backoff selector ")); 2671182876Smarius callout_stop(&ecb->ch); 2672130293Sscottl ncr53c9x_dequeue(sc, ecb); 2673130293Sscottl TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); 2674130293Sscottl ecb->flags |= ECB_READY; 2675130293Sscottl ecb = sc->sc_nexus = NULL; 2676130293Sscottl } 2677130293Sscottl sc->sc_state = NCR_RESELECTED; 2678130293Sscottl if (sc->sc_phase != MESSAGE_IN_PHASE) { 2679130293Sscottl /* 2680145202Smarius * Things are seriously screwed up. 2681130293Sscottl * Pull the brakes, i.e. reset 2682130293Sscottl */ 2683130293Sscottl device_printf(sc->sc_dev, "target didn't " 2684130293Sscottl "identify\n"); 2685182876Smarius goto reset; 2686130293Sscottl } 2687130293Sscottl /* 2688130293Sscottl * The C90 only inhibits FIFO writes until reselection 2689133039Strhodes * is complete instead of waiting until the interrupt 2690130293Sscottl * status register has been read. So, if the reselect 2691130293Sscottl * happens while we were entering command bytes (for 2692130293Sscottl * another target) some of those bytes can appear in 2693130293Sscottl * the FIFO here, after the interrupt is taken. 2694130293Sscottl * 2695130293Sscottl * To remedy this situation, pull the Selection ID 2696130293Sscottl * and Identify message from the FIFO directly, and 2697180692Smarius * ignore any extraneous FIFO contents. Also, set 2698130293Sscottl * a flag that allows one Illegal Command Interrupt 2699130293Sscottl * to occur which the chip also generates as a result 2700130293Sscottl * of writing to the FIFO during a reselect. 2701130293Sscottl */ 2702130293Sscottl if (sc->sc_rev == NCR_VARIANT_ESP100) { 2703180692Smarius nfifo = 2704180692Smarius NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF; 2705130293Sscottl sc->sc_imess[0] = NCR_READ_REG(sc, NCR_FIFO); 2706130293Sscottl sc->sc_imess[1] = NCR_READ_REG(sc, NCR_FIFO); 2707130293Sscottl sc->sc_imlen = 2; 2708130293Sscottl if (nfifo != 2) { 2709180692Smarius /* Flush the rest. */ 2710130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2711130293Sscottl } 2712130293Sscottl sc->sc_flags |= NCR_EXPECT_ILLCMD; 2713130293Sscottl if (nfifo > 2) 2714180692Smarius nfifo = 2; /* We fixed it... */ 2715130293Sscottl } else 2716130293Sscottl nfifo = ncr53c9x_rdfifo(sc, NCR_RDFIFO_START); 2717130293Sscottl 2718130293Sscottl if (nfifo != 2) { 2719130293Sscottl device_printf(sc->sc_dev, "RESELECT: %d bytes " 2720130293Sscottl "in FIFO! [intr %x, stat %x, step %d, " 2721130293Sscottl "prevphase %x]\n", 2722130293Sscottl nfifo, 2723130293Sscottl sc->sc_espintr, 2724130293Sscottl sc->sc_espstat, 2725130293Sscottl sc->sc_espstep, 2726130293Sscottl sc->sc_prevphase); 2727182876Smarius goto reset; 2728130293Sscottl } 2729130293Sscottl sc->sc_selid = sc->sc_imess[0]; 2730130293Sscottl NCR_INTS(("selid=%02x ", sc->sc_selid)); 2731130293Sscottl 2732180692Smarius /* Handle IDENTIFY message. */ 2733130293Sscottl ncr53c9x_msgin(sc); 2734130293Sscottl 2735130293Sscottl if (sc->sc_state != NCR_CONNECTED && 2736130293Sscottl sc->sc_state != NCR_IDENTIFIED) { 2737130293Sscottl /* IDENTIFY fail?! */ 2738130293Sscottl device_printf(sc->sc_dev, "identify failed, " 2739130293Sscottl "state %d, intr %02x\n", sc->sc_state, 2740130293Sscottl sc->sc_espintr); 2741182876Smarius goto reset; 2742130293Sscottl } 2743180692Smarius goto shortcut; /* i.e. next phase expected soon */ 2744130293Sscottl } 2745130293Sscottl 2746180692Smarius#define NCRINTR_DONE (NCRINTR_FC | NCRINTR_BS) 2747130293Sscottl if ((sc->sc_espintr & NCRINTR_DONE) == NCRINTR_DONE) { 2748130293Sscottl /* 2749130293Sscottl * Arbitration won; examine the `step' register 2750130293Sscottl * to determine how far the selection could progress. 2751130293Sscottl */ 2752146392Smarius if (ecb == NULL) { 2753146392Smarius /* 2754146392Smarius * When doing path inquiry during boot 2755146392Smarius * FAS100A trigger a stray interrupt which 2756146392Smarius * we just ignore instead of panicing. 2757146392Smarius */ 2758146392Smarius if (sc->sc_state == NCR_IDLE && 2759146392Smarius sc->sc_espstep == 0) 2760182876Smarius return; 2761226381Smarius panic("%s: no nexus", __func__); 2762146392Smarius } 2763130293Sscottl 2764130293Sscottl ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id]; 2765130293Sscottl 2766130293Sscottl switch (sc->sc_espstep) { 2767130293Sscottl case 0: 2768130293Sscottl /* 2769130293Sscottl * The target did not respond with a 2770130293Sscottl * message out phase - probably an old 2771130293Sscottl * device that doesn't recognize ATN. 2772130293Sscottl * Clear ATN and just continue, the 2773130293Sscottl * target should be in the command 2774130293Sscottl * phase. 2775180692Smarius * XXX check for command phase? 2776130293Sscottl */ 2777130293Sscottl NCRCMD(sc, NCRCMD_RSTATN); 2778130293Sscottl break; 2779180692Smarius 2780130293Sscottl case 1: 2781182876Smarius if (ti->curr.period == ti->goal.period && 2782182876Smarius ti->curr.offset == ti->goal.offset && 2783182876Smarius ti->curr.width == ti->goal.width && 2784130293Sscottl ecb->tag[0] == 0) { 2785182876Smarius device_printf(sc->sc_dev, "step 1 " 2786182876Smarius "and no negotiation to perform " 2787182876Smarius "or tag to send\n"); 2788130293Sscottl goto reset; 2789130293Sscottl } 2790130293Sscottl if (sc->sc_phase != MESSAGE_OUT_PHASE) { 2791182876Smarius device_printf(sc->sc_dev, "step 1 " 2792182876Smarius "but not in MESSAGE_OUT_PHASE\n"); 2793130293Sscottl goto reset; 2794130293Sscottl } 2795182876Smarius sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXX */ 2796182876Smarius if (ecb->flags & ECB_RESET) { 2797182876Smarius /* 2798182876Smarius * A DEVICE RESET was scheduled and 2799182876Smarius * ATNS used. As SEND_DEV_RESET has 2800182876Smarius * the highest priority, the target 2801182876Smarius * will reset and disconnect and we 2802182876Smarius * will end up in ncr53c9x_done w/o 2803182876Smarius * negotiating or sending a TAG. So 2804182876Smarius * we just break here in order to 2805182876Smarius * avoid warnings about negotiation 2806182876Smarius * not having completed. 2807182876Smarius */ 2808182876Smarius ncr53c9x_sched_msgout(SEND_DEV_RESET); 2809182876Smarius break; 2810130293Sscottl } 2811182876Smarius if (ti->curr.width != ti->goal.width) { 2812182876Smarius ti->flags |= T_WDTRSENT | T_SDTRSENT; 2813182876Smarius ncr53c9x_sched_msgout(SEND_WDTR | 2814182876Smarius SEND_SDTR); 2815182876Smarius } 2816182876Smarius if (ti->curr.period != ti->goal.period || 2817182876Smarius ti->curr.offset != ti->goal.offset) { 2818182876Smarius ti->flags |= T_SDTRSENT; 2819182876Smarius ncr53c9x_sched_msgout(SEND_SDTR); 2820182876Smarius } 2821182876Smarius if (ecb->tag[0] != 0) 2822180692Smarius /* Could not do ATN3 so send TAG. */ 2823130293Sscottl ncr53c9x_sched_msgout(SEND_TAG); 2824130293Sscottl break; 2825180692Smarius 2826130293Sscottl case 3: 2827130293Sscottl /* 2828130293Sscottl * Grr, this is supposed to mean 2829180692Smarius * "target left command phase prematurely". 2830130293Sscottl * It seems to happen regularly when 2831130293Sscottl * sync mode is on. 2832130293Sscottl * Look at FIFO to see if command went out. 2833130293Sscottl * (Timing problems?) 2834130293Sscottl */ 2835130293Sscottl if (sc->sc_features & NCR_F_DMASELECT) { 2836239089Smarius if (sc->sc_cmdlen == 0) { 2837180692Smarius /* Hope for the best... */ 2838130293Sscottl break; 2839239089Smarius } 2840226381Smarius } else if ((NCR_READ_REG(sc, NCR_FFLAG) & 2841226381Smarius NCRFIFO_FF) == 0) { 2842180692Smarius /* Hope for the best... */ 2843130293Sscottl break; 2844130293Sscottl } 2845182876Smarius xpt_print_path(ecb->ccb->ccb_h.path); 2846182876Smarius printf("selection failed; %d left in FIFO " 2847130293Sscottl "[intr %x, stat %x, step %d]\n", 2848180692Smarius NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF, 2849130293Sscottl sc->sc_espintr, sc->sc_espstat, 2850130293Sscottl sc->sc_espstep); 2851130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2852130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 2853182876Smarius return; 2854180692Smarius 2855130293Sscottl case 2: 2856180692Smarius /* Select stuck at Command Phase. */ 2857130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2858130293Sscottl break; 2859180692Smarius 2860130293Sscottl case 4: 2861130293Sscottl if (sc->sc_features & NCR_F_DMASELECT && 2862182876Smarius sc->sc_cmdlen != 0) { 2863182876Smarius xpt_print_path(ecb->ccb->ccb_h.path); 2864182876Smarius printf("select; %lu left in DMA buffer " 2865130293Sscottl "[intr %x, stat %x, step %d]\n", 2866130293Sscottl (u_long)sc->sc_cmdlen, 2867130293Sscottl sc->sc_espintr, 2868130293Sscottl sc->sc_espstat, 2869130293Sscottl sc->sc_espstep); 2870182876Smarius } 2871180692Smarius /* So far, everything went fine. */ 2872130293Sscottl break; 2873130293Sscottl } 2874130293Sscottl 2875180692Smarius sc->sc_prevphase = INVALID_PHASE; /* ??? */ 2876130293Sscottl /* Do an implicit RESTORE POINTERS. */ 2877130293Sscottl sc->sc_dp = ecb->daddr; 2878130293Sscottl sc->sc_dleft = ecb->dleft; 2879130293Sscottl sc->sc_state = NCR_CONNECTED; 2880130293Sscottl break; 2881130293Sscottl } else { 2882130293Sscottl device_printf(sc->sc_dev, "unexpected status after " 2883130293Sscottl "select: [intr %x, stat %x, step %x]\n", 2884130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2885130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2886130293Sscottl DELAY(1); 2887130293Sscottl goto reset; 2888130293Sscottl } 2889130293Sscottl if (sc->sc_state == NCR_IDLE) { 2890130293Sscottl device_printf(sc->sc_dev, "stray interrupt\n"); 2891182876Smarius return; 2892130293Sscottl } 2893130293Sscottl break; 2894130293Sscottl 2895130293Sscottl case NCR_CONNECTED: 2896130293Sscottl if ((sc->sc_flags & NCR_ICCS) != 0) { 2897130293Sscottl /* "Initiate Command Complete Steps" in progress */ 2898130293Sscottl sc->sc_flags &= ~NCR_ICCS; 2899130293Sscottl 2900226381Smarius if ((sc->sc_espintr & NCRINTR_DONE) == 0) { 2901130293Sscottl device_printf(sc->sc_dev, "ICCS: " 2902130293Sscottl ": [intr %x, stat %x, step %x]\n", 2903130293Sscottl sc->sc_espintr, sc->sc_espstat, 2904130293Sscottl sc->sc_espstep); 2905130293Sscottl } 2906130293Sscottl ncr53c9x_rdfifo(sc, NCR_RDFIFO_START); 2907130293Sscottl if (sc->sc_imlen < 2) 2908130293Sscottl device_printf(sc->sc_dev, "can't get status, " 2909130293Sscottl "only %d bytes\n", (int)sc->sc_imlen); 2910130293Sscottl ecb->stat = sc->sc_imess[sc->sc_imlen - 2]; 2911130293Sscottl msg = sc->sc_imess[sc->sc_imlen - 1]; 2912130293Sscottl NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg)); 2913130293Sscottl if (msg == MSG_CMDCOMPLETE) { 2914180692Smarius ecb->dleft = 2915180692Smarius (ecb->flags & ECB_TENTATIVE_DONE) ? 2916180692Smarius 0 : sc->sc_dleft; 2917130293Sscottl if ((ecb->flags & ECB_SENSE) == 0) 2918130293Sscottl ecb->ccb->csio.resid = ecb->dleft; 2919130293Sscottl sc->sc_state = NCR_CMDCOMPLETE; 2920130293Sscottl } else 2921130293Sscottl device_printf(sc->sc_dev, "STATUS_PHASE: " 2922130293Sscottl "msg %d\n", msg); 2923130293Sscottl sc->sc_imlen = 0; 2924130293Sscottl NCRCMD(sc, NCRCMD_MSGOK); 2925180692Smarius goto shortcut; /* i.e. wait for disconnect */ 2926130293Sscottl } 2927130293Sscottl break; 2928130293Sscottl 2929130293Sscottl default: 2930130293Sscottl device_printf(sc->sc_dev, "invalid state: %d [intr %x, " 2931130293Sscottl "phase(c %x, p %x)]\n", sc->sc_state, 2932130293Sscottl sc->sc_espintr, sc->sc_phase, sc->sc_prevphase); 2933130293Sscottl goto reset; 2934130293Sscottl } 2935130293Sscottl 2936130293Sscottl /* 2937130293Sscottl * Driver is now in state NCR_CONNECTED, i.e. we 2938130293Sscottl * have a current command working the SCSI bus. 2939130293Sscottl */ 2940226381Smarius if (sc->sc_state != NCR_CONNECTED || ecb == NULL) 2941226381Smarius panic("%s: no nexus", __func__); 2942130293Sscottl 2943130293Sscottl switch (sc->sc_phase) { 2944130293Sscottl case MESSAGE_OUT_PHASE: 2945130293Sscottl NCR_PHASE(("MESSAGE_OUT_PHASE ")); 2946130293Sscottl ncr53c9x_msgout(sc); 2947130293Sscottl sc->sc_prevphase = MESSAGE_OUT_PHASE; 2948130293Sscottl break; 2949130293Sscottl 2950130293Sscottl case MESSAGE_IN_PHASE: 2951130293Sscottlmsgin: 2952130293Sscottl NCR_PHASE(("MESSAGE_IN_PHASE ")); 2953130293Sscottl if ((sc->sc_espintr & NCRINTR_BS) != 0) { 2954130293Sscottl if ((sc->sc_rev != NCR_VARIANT_FAS366) || 2955226381Smarius (sc->sc_espstat2 & NCRFAS_STAT2_EMPTY) == 0) { 2956130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2957130293Sscottl } 2958130293Sscottl sc->sc_flags |= NCR_WAITI; 2959130293Sscottl NCRCMD(sc, NCRCMD_TRANS); 2960130293Sscottl } else if ((sc->sc_espintr & NCRINTR_FC) != 0) { 2961130293Sscottl if ((sc->sc_flags & NCR_WAITI) == 0) { 2962130293Sscottl device_printf(sc->sc_dev, "MSGIN: unexpected " 2963130293Sscottl "FC bit: [intr %x, stat %x, step %x]\n", 2964130293Sscottl sc->sc_espintr, sc->sc_espstat, 2965130293Sscottl sc->sc_espstep); 2966130293Sscottl } 2967130293Sscottl sc->sc_flags &= ~NCR_WAITI; 2968130293Sscottl ncr53c9x_rdfifo(sc, 2969145202Smarius (sc->sc_prevphase == sc->sc_phase) ? 2970130293Sscottl NCR_RDFIFO_CONTINUE : NCR_RDFIFO_START); 2971130293Sscottl ncr53c9x_msgin(sc); 2972226381Smarius } else 2973130293Sscottl device_printf(sc->sc_dev, "MSGIN: weird bits: " 2974130293Sscottl "[intr %x, stat %x, step %x]\n", 2975130293Sscottl sc->sc_espintr, sc->sc_espstat, sc->sc_espstep); 2976130293Sscottl sc->sc_prevphase = MESSAGE_IN_PHASE; 2977130293Sscottl goto shortcut; /* i.e. expect data to be ready */ 2978130293Sscottl 2979130293Sscottl case COMMAND_PHASE: 2980130293Sscottl /* 2981180692Smarius * Send the command block. Normally we don't see this 2982130293Sscottl * phase because the SEL_ATN command takes care of 2983180692Smarius * all this. However, we end up here if either the 2984130293Sscottl * target or we wanted to exchange some more messages 2985130293Sscottl * first (e.g. to start negotiations). 2986130293Sscottl */ 2987130293Sscottl 2988130293Sscottl NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ", 2989130293Sscottl ecb->cmd.cmd.opcode, ecb->clen)); 2990130293Sscottl if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) { 2991130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 2992226381Smarius#if 0 2993226381Smarius DELAY(1); 2994226381Smarius#endif 2995130293Sscottl } 2996182876Smarius /* 2997182876Smarius * If we have more messages to send, e.g. WDTR or SDTR 2998182876Smarius * after we've sent a TAG, set ATN so we'll go back to 2999182876Smarius * MESSAGE_OUT_PHASE. 3000182876Smarius */ 3001182876Smarius if (sc->sc_msgpriq) { 3002182876Smarius NCRCMD(sc, NCRCMD_SETATN); 3003182876Smarius sc->sc_flags |= NCR_ATN; 3004182876Smarius } 3005130293Sscottl if (sc->sc_features & NCR_F_DMASELECT) { 3006180692Smarius /* Setup DMA transfer for command. */ 3007130293Sscottl size = ecb->clen; 3008130293Sscottl sc->sc_cmdlen = size; 3009226381Smarius sc->sc_cmdp = (void *)&ecb->cmd.cmd; 3010226947Smarius error = NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 3011130293Sscottl 0, &size); 3012239089Smarius if (error != 0) 3013226947Smarius goto cmd; 3014226947Smarius 3015180692Smarius /* Program the SCSI counter. */ 3016130293Sscottl NCR_SET_COUNT(sc, size); 3017130293Sscottl 3018180692Smarius /* Load the count in. */ 3019180692Smarius NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); 3020130293Sscottl 3021180692Smarius /* Start the command transfer. */ 3022130293Sscottl NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA); 3023130293Sscottl NCRDMA_GO(sc); 3024226947Smarius sc->sc_prevphase = COMMAND_PHASE; 3025226947Smarius break; 3026130293Sscottl } 3027226947Smariuscmd: 3028239089Smarius sc->sc_cmdlen = 0; 3029226947Smarius ncr53c9x_wrfifo(sc, (uint8_t *)&ecb->cmd.cmd, ecb->clen); 3030226947Smarius NCRCMD(sc, NCRCMD_TRANS); 3031130293Sscottl sc->sc_prevphase = COMMAND_PHASE; 3032130293Sscottl break; 3033130293Sscottl 3034130293Sscottl case DATA_OUT_PHASE: 3035180692Smarius NCR_PHASE(("DATA_OUT_PHASE [%ld] ", (long)sc->sc_dleft)); 3036226947Smarius sc->sc_prevphase = DATA_OUT_PHASE; 3037130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 3038182876Smarius size = ulmin(sc->sc_dleft, sc->sc_maxxfer); 3039226947Smarius error = NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 0, &size); 3040130293Sscottl goto setup_xfer; 3041130293Sscottl 3042130293Sscottl case DATA_IN_PHASE: 3043130293Sscottl NCR_PHASE(("DATA_IN_PHASE ")); 3044226947Smarius sc->sc_prevphase = DATA_IN_PHASE; 3045130293Sscottl if (sc->sc_rev == NCR_VARIANT_ESP100) 3046130293Sscottl NCRCMD(sc, NCRCMD_FLUSH); 3047182876Smarius size = ulmin(sc->sc_dleft, sc->sc_maxxfer); 3048226947Smarius error = NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 1, &size); 3049226947Smariussetup_xfer: 3050226947Smarius if (error != 0) { 3051226947Smarius switch (error) { 3052226947Smarius case EFBIG: 3053226947Smarius ecb->ccb->ccb_h.status |= CAM_REQ_TOO_BIG; 3054226947Smarius break; 3055226947Smarius case EINPROGRESS: 3056226947Smarius panic("%s: cannot deal with deferred DMA", 3057226947Smarius __func__); 3058226947Smarius case EINVAL: 3059226947Smarius ecb->ccb->ccb_h.status |= CAM_REQ_INVALID; 3060226947Smarius break; 3061226947Smarius case ENOMEM: 3062226947Smarius ecb->ccb->ccb_h.status |= CAM_REQUEUE_REQ; 3063226947Smarius break; 3064226947Smarius default: 3065226947Smarius ecb->ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 3066226947Smarius } 3067226947Smarius goto finish; 3068226947Smarius } 3069226947Smarius 3070239089Smarius /* Target returned to data phase: wipe "done" memory. */ 3071130293Sscottl ecb->flags &= ~ECB_TENTATIVE_DONE; 3072130293Sscottl 3073180692Smarius /* Program the SCSI counter. */ 3074130293Sscottl NCR_SET_COUNT(sc, size); 3075130293Sscottl 3076180692Smarius /* Load the count in. */ 3077180692Smarius NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA); 3078130293Sscottl 3079130293Sscottl /* 3080130293Sscottl * Note that if `size' is 0, we've already transceived 3081130293Sscottl * all the bytes we want but we're still in DATA PHASE. 3082180692Smarius * Apparently, the device needs padding. Also, a 3083130293Sscottl * transfer size of 0 means "maximum" to the chip 3084130293Sscottl * DMA logic. 3085130293Sscottl */ 3086130293Sscottl NCRCMD(sc, 3087130293Sscottl (size == 0 ? NCRCMD_TRPAD : NCRCMD_TRANS) | NCRCMD_DMA); 3088130293Sscottl NCRDMA_GO(sc); 3089182876Smarius return; 3090130293Sscottl 3091130293Sscottl case STATUS_PHASE: 3092130293Sscottl NCR_PHASE(("STATUS_PHASE ")); 3093130293Sscottl sc->sc_flags |= NCR_ICCS; 3094130293Sscottl NCRCMD(sc, NCRCMD_ICCS); 3095130293Sscottl sc->sc_prevphase = STATUS_PHASE; 3096130293Sscottl goto shortcut; /* i.e. expect status results soon */ 3097130293Sscottl 3098130293Sscottl case INVALID_PHASE: 3099130293Sscottl break; 3100130293Sscottl 3101130293Sscottl default: 3102180692Smarius device_printf(sc->sc_dev, 3103180692Smarius "unexpected bus phase; resetting\n"); 3104130293Sscottl goto reset; 3105130293Sscottl } 3106130293Sscottl 3107130293Sscottl return; 3108130293Sscottl 3109130293Sscottlreset: 3110130293Sscottl ncr53c9x_init(sc, 1); 3111182876Smarius return; 3112130293Sscottl 3113130293Sscottlfinish: 3114130293Sscottl ncr53c9x_done(sc, ecb); 3115182876Smarius return; 3116130293Sscottl 3117130293Sscottlsched: 3118130293Sscottl sc->sc_state = NCR_IDLE; 3119130293Sscottl ncr53c9x_sched(sc); 3120182876Smarius return; 3121130293Sscottl 3122130293Sscottlshortcut: 3123130293Sscottl /* 3124130293Sscottl * The idea is that many of the SCSI operations take very little 3125130293Sscottl * time, and going away and getting interrupted is too high an 3126180692Smarius * overhead to pay. For example, selecting, sending a message 3127130293Sscottl * and command and then doing some work can be done in one "pass". 3128130293Sscottl * 3129239089Smarius * The delay is a heuristic. It is 2 when at 20 MHz, 2 at 25 MHz and 3130239089Smarius * 1 at 40 MHz. This needs testing. 3131130293Sscottl */ 3132180692Smarius microtime(&wait); 3133180692Smarius wait.tv_usec += 50 / sc->sc_freq; 3134180692Smarius if (wait.tv_usec > 1000000) { 3135180692Smarius wait.tv_sec++; 3136180692Smarius wait.tv_usec -= 1000000; 3137130293Sscottl } 3138180692Smarius do { 3139180692Smarius if (NCRDMA_ISINTR(sc)) 3140180692Smarius goto again; 3141180692Smarius microtime(&cur); 3142180692Smarius } while (cur.tv_sec <= wait.tv_sec && cur.tv_usec <= wait.tv_usec); 3143130293Sscottl} 3144130293Sscottl 3145130293Sscottlstatic void 3146180692Smariusncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) 3147130293Sscottl{ 3148130293Sscottl 3149182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 3150182876Smarius 3151130293Sscottl /* 2 secs for the abort */ 3152130293Sscottl ecb->timeout = NCR_ABORT_TIMEOUT; 3153130293Sscottl ecb->flags |= ECB_ABORT; 3154130293Sscottl 3155130293Sscottl if (ecb == sc->sc_nexus) { 3156130293Sscottl /* 3157130293Sscottl * If we're still selecting, the message will be scheduled 3158130293Sscottl * after selection is complete. 3159130293Sscottl */ 3160130293Sscottl if (sc->sc_state == NCR_CONNECTED) 3161130293Sscottl ncr53c9x_sched_msgout(SEND_ABORT); 3162130293Sscottl 3163130293Sscottl /* 3164182876Smarius * Reschedule callout. 3165130293Sscottl */ 3166182876Smarius callout_reset(&ecb->ch, mstohz(ecb->timeout), 3167182876Smarius ncr53c9x_callout, ecb); 3168130293Sscottl } else { 3169130293Sscottl /* 3170130293Sscottl * Just leave the command where it is. 3171130293Sscottl * XXX - what choice do we have but to reset the SCSI 3172130293Sscottl * eventually? 3173130293Sscottl */ 3174130293Sscottl if (sc->sc_state == NCR_IDLE) 3175130293Sscottl ncr53c9x_sched(sc); 3176130293Sscottl } 3177130293Sscottl} 3178130293Sscottl 3179130293Sscottlstatic void 3180182876Smariusncr53c9x_callout(void *arg) 3181130293Sscottl{ 3182130293Sscottl struct ncr53c9x_ecb *ecb = arg; 3183130293Sscottl union ccb *ccb = ecb->ccb; 3184130293Sscottl struct ncr53c9x_softc *sc = ecb->sc; 3185182876Smarius struct ncr53c9x_tinfo *ti; 3186130293Sscottl 3187182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 3188182876Smarius 3189182876Smarius ti = &sc->sc_tinfo[ccb->ccb_h.target_id]; 3190130293Sscottl xpt_print_path(ccb->ccb_h.path); 3191130293Sscottl device_printf(sc->sc_dev, "timed out [ecb %p (flags 0x%x, dleft %x, " 3192130293Sscottl "stat %x)], <state %d, nexus %p, phase(l %x, c %x, p %x), " 3193130293Sscottl "resid %lx, msg(q %x,o %x) %s>", 3194130293Sscottl ecb, ecb->flags, ecb->dleft, ecb->stat, 3195130293Sscottl sc->sc_state, sc->sc_nexus, 3196130293Sscottl NCR_READ_REG(sc, NCR_STAT), 3197130293Sscottl sc->sc_phase, sc->sc_prevphase, 3198130293Sscottl (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout, 3199130293Sscottl NCRDMA_ISACTIVE(sc) ? "DMA active" : ""); 3200153084Sru#if defined(NCR53C9X_DEBUG) && NCR53C9X_DEBUG > 1 3201130293Sscottl printf("TRACE: %s.", ecb->trace); 3202130293Sscottl#endif 3203130293Sscottl 3204130293Sscottl if (ecb->flags & ECB_ABORT) { 3205180692Smarius /* Abort timed out. */ 3206130293Sscottl printf(" AGAIN\n"); 3207130293Sscottl ncr53c9x_init(sc, 1); 3208130293Sscottl } else { 3209180692Smarius /* Abort the operation that has timed out. */ 3210130293Sscottl printf("\n"); 3211130293Sscottl ccb->ccb_h.status = CAM_CMD_TIMEOUT; 3212130293Sscottl ncr53c9x_abort(sc, ecb); 3213130293Sscottl 3214180692Smarius /* Disable sync mode if stuck in a data phase. */ 3215239089Smarius if (ecb == sc->sc_nexus && ti->curr.offset != 0 && 3216182876Smarius (sc->sc_phase & (MSGI | CDI)) == 0) { 3217130293Sscottl /* XXX ASYNC CALLBACK! */ 3218182876Smarius ti->goal.offset = 0; 3219130293Sscottl xpt_print_path(ccb->ccb_h.path); 3220130293Sscottl printf("sync negotiation disabled\n"); 3221130293Sscottl } 3222130293Sscottl } 3223130293Sscottl} 3224130293Sscottl 3225130293Sscottlstatic void 3226130293Sscottlncr53c9x_watch(void *arg) 3227130293Sscottl{ 3228226381Smarius struct ncr53c9x_softc *sc = arg; 3229180692Smarius struct ncr53c9x_linfo *li; 3230130293Sscottl struct ncr53c9x_tinfo *ti; 3231180692Smarius time_t old; 3232130293Sscottl int t; 3233180692Smarius 3234182876Smarius NCR_LOCK_ASSERT(sc, MA_OWNED); 3235182876Smarius 3236130293Sscottl /* Delete any structures that have not been used in 10min. */ 3237180692Smarius old = time_second - (10 * 60); 3238130293Sscottl 3239130293Sscottl for (t = 0; t < sc->sc_ntarg; t++) { 3240130293Sscottl ti = &sc->sc_tinfo[t]; 3241130293Sscottl li = LIST_FIRST(&ti->luns); 3242130293Sscottl while (li) { 3243130293Sscottl if (li->last_used < old && 3244130293Sscottl li->untagged == NULL && 3245130293Sscottl li->used == 0) { 3246130293Sscottl if (li->lun < NCR_NLUN) 3247130293Sscottl ti->lun[li->lun] = NULL; 3248130293Sscottl LIST_REMOVE(li, link); 3249130293Sscottl free(li, M_DEVBUF); 3250180692Smarius /* Restart the search at the beginning. */ 3251130293Sscottl li = LIST_FIRST(&ti->luns); 3252130293Sscottl continue; 3253130293Sscottl } 3254130293Sscottl li = LIST_NEXT(li, link); 3255130293Sscottl } 3256130293Sscottl } 3257130293Sscottl callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc); 3258130293Sscottl} 3259