| File: | dev/ic/ncr53c9x.c |
| Warning: | line 2145, column 4 Access to field 'xs' results in a dereference of a null pointer (loaded from variable 'ecb') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ncr53c9x.c,v 1.80 2022/04/16 19:19:59 naddy Exp $ */ | |||
| 2 | /* $NetBSD: ncr53c9x.c,v 1.56 2000/11/30 14:41:46 thorpej Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1996 Charles M. Hannum. All rights reserved. | |||
| 6 | * | |||
| 7 | * Redistribution and use in source and binary forms, with or without | |||
| 8 | * modification, are permitted provided that the following conditions | |||
| 9 | * are met: | |||
| 10 | * 1. Redistributions of source code must retain the above copyright | |||
| 11 | * notice, this list of conditions and the following disclaimer. | |||
| 12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 13 | * notice, this list of conditions and the following disclaimer in the | |||
| 14 | * documentation and/or other materials provided with the distribution. | |||
| 15 | * 3. All advertising materials mentioning features or use of this software | |||
| 16 | * must display the following acknowledgement: | |||
| 17 | * This product includes software developed by Charles M. Hannum. | |||
| 18 | * 4. The name of the author may not be used to endorse or promote products | |||
| 19 | * derived from this software without specific prior written permission. | |||
| 20 | * | |||
| 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 31 | */ | |||
| 32 | ||||
| 33 | /* | |||
| 34 | * Copyright (c) 1994 Peter Galbavy | |||
| 35 | * Copyright (c) 1995 Paul Kranenburg | |||
| 36 | * All rights reserved. | |||
| 37 | * | |||
| 38 | * Redistribution and use in source and binary forms, with or without | |||
| 39 | * modification, are permitted provided that the following conditions | |||
| 40 | * are met: | |||
| 41 | * 1. Redistributions of source code must retain the above copyright | |||
| 42 | * notice, this list of conditions and the following disclaimer. | |||
| 43 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 44 | * notice, this list of conditions and the following disclaimer in the | |||
| 45 | * documentation and/or other materials provided with the distribution. | |||
| 46 | * | |||
| 47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 48 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| 49 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| 50 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |||
| 51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| 52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||
| 53 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |||
| 55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |||
| 56 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 57 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 58 | */ | |||
| 59 | ||||
| 60 | /* | |||
| 61 | * Based on aic6360 by Jarle Greipsland | |||
| 62 | * | |||
| 63 | * Acknowledgements: Many of the algorithms used in this driver are | |||
| 64 | * inspired by the work of Julian Elischer (julian@tfs.com) and | |||
| 65 | * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million! | |||
| 66 | */ | |||
| 67 | ||||
| 68 | #include <sys/param.h> | |||
| 69 | #include <sys/systm.h> | |||
| 70 | #include <sys/kernel.h> | |||
| 71 | #include <sys/errno.h> | |||
| 72 | #include <sys/ioctl.h> | |||
| 73 | #include <sys/device.h> | |||
| 74 | #include <sys/malloc.h> | |||
| 75 | #include <sys/queue.h> | |||
| 76 | #include <sys/pool.h> | |||
| 77 | ||||
| 78 | #include <scsi/scsi_all.h> | |||
| 79 | #include <scsi/scsiconf.h> | |||
| 80 | #include <scsi/scsi_message.h> | |||
| 81 | ||||
| 82 | #include <machine/cpu.h> | |||
| 83 | ||||
| 84 | #include <dev/ic/ncr53c9xreg.h> | |||
| 85 | #include <dev/ic/ncr53c9xvar.h> | |||
| 86 | ||||
| 87 | #ifdef NCR53C9X_DEBUG1 | |||
| 88 | int ncr53c9x_debug = 0; /*NCR_SHOWPHASE|NCR_SHOWMISC|NCR_SHOWTRAC|NCR_SHOWCMDS;*/ | |||
| 89 | #endif | |||
| 90 | #ifdef DEBUG | |||
| 91 | int ncr53c9x_notag = 0; | |||
| 92 | #endif | |||
| 93 | ||||
| 94 | /*static*/ void ncr53c9x_readregs(struct ncr53c9x_softc *); | |||
| 95 | /*static*/ void ncr53c9x_select(struct ncr53c9x_softc *, | |||
| 96 | struct ncr53c9x_ecb *); | |||
| 97 | /*static*/ int ncr53c9x_reselect(struct ncr53c9x_softc *, int, int, int); | |||
| 98 | /*static*/ void ncr53c9x_scsi_reset(struct ncr53c9x_softc *); | |||
| 99 | /*static*/ int ncr53c9x_poll(struct ncr53c9x_softc *, | |||
| 100 | struct scsi_xfer *, int); | |||
| 101 | /*static*/ void ncr53c9x_sched(struct ncr53c9x_softc *); | |||
| 102 | /*static*/ void ncr53c9x_done(struct ncr53c9x_softc *, | |||
| 103 | struct ncr53c9x_ecb *); | |||
| 104 | /*static*/ void ncr53c9x_msgin(struct ncr53c9x_softc *); | |||
| 105 | /*static*/ void ncr53c9x_msgout(struct ncr53c9x_softc *); | |||
| 106 | /*static*/ void ncr53c9x_timeout(void *arg); | |||
| 107 | /*static*/ void ncr53c9x_abort(struct ncr53c9x_softc *, | |||
| 108 | struct ncr53c9x_ecb *); | |||
| 109 | /*static*/ void ncr53c9x_dequeue(struct ncr53c9x_softc *, | |||
| 110 | struct ncr53c9x_ecb *); | |||
| 111 | ||||
| 112 | void ncr53c9x_sense(struct ncr53c9x_softc *, | |||
| 113 | struct ncr53c9x_ecb *); | |||
| 114 | void ncr53c9x_free_ecb(void *, void *); | |||
| 115 | void *ncr53c9x_get_ecb(void *); | |||
| 116 | ||||
| 117 | static inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *, int); | |||
| 118 | static inline void ncr53c9x_setsync(struct ncr53c9x_softc *, | |||
| 119 | struct ncr53c9x_tinfo *); | |||
| 120 | static struct ncr53c9x_linfo *ncr53c9x_lunsearch(struct ncr53c9x_tinfo *, | |||
| 121 | int64_t lun); | |||
| 122 | ||||
| 123 | static void ncr53c9x_wrfifo(struct ncr53c9x_softc *, u_char *, int); | |||
| 124 | static int ncr53c9x_rdfifo(struct ncr53c9x_softc *, int); | |||
| 125 | #define NCR_RDFIFO_START0 0 | |||
| 126 | #define NCR_RDFIFO_CONTINUE1 1 | |||
| 127 | ||||
| 128 | #define NCR_SET_COUNT(sc, size)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (size))); (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x01 ), ((size) >> 8)); if ((sc->sc_cfg2 & 0x40) || ( sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg) (((sc)), (0x0e), ((size) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0)); } } while (0) do { \ | |||
| 129 | NCR_WRITE_REG((sc), NCR_TCL, (size))(*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ((size ))); \ | |||
| 130 | NCR_WRITE_REG((sc), NCR_TCM, (size) >> 8)(*((sc))->sc_glue->gl_write_reg)(((sc)), (0x01), ((size ) >> 8)); \ | |||
| 131 | if ((sc->sc_cfg2 & NCRCFG2_FE0x40) || \ | |||
| 132 | (sc->sc_rev == NCR_VARIANT_FAS3669)) { \ | |||
| 133 | NCR_WRITE_REG((sc), NCR_TCH, (size) >> 16)(*((sc))->sc_glue->gl_write_reg)(((sc)), (0x0e), ((size ) >> 16)); \ | |||
| 134 | } \ | |||
| 135 | if (sc->sc_rev == NCR_VARIANT_FAS3669) { \ | |||
| 136 | NCR_WRITE_REG(sc, NCR_RCH, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0)); \ | |||
| 137 | } \ | |||
| 138 | } while (0) | |||
| 139 | ||||
| 140 | static int ecb_pool_initialized = 0; | |||
| 141 | static struct scsi_iopool ecb_iopool; | |||
| 142 | static struct pool ecb_pool; | |||
| 143 | ||||
| 144 | struct cfdriver esp_cd = { | |||
| 145 | NULL((void *)0), "esp", DV_DULL | |||
| 146 | }; | |||
| 147 | ||||
| 148 | void ncr53c9x_scsi_cmd(struct scsi_xfer *); | |||
| 149 | int ncr53c9x_scsi_probe(struct scsi_link *); | |||
| 150 | void ncr53c9x_scsi_free(struct scsi_link *); | |||
| 151 | ||||
| 152 | const struct scsi_adapter ncr53c9x_switch = { | |||
| 153 | ncr53c9x_scsi_cmd, NULL((void *)0), ncr53c9x_scsi_probe, | |||
| 154 | ncr53c9x_scsi_free, NULL((void *)0) | |||
| 155 | }; | |||
| 156 | ||||
| 157 | /* | |||
| 158 | * Names for the NCR53c9x variants, corresponding to the variant tags | |||
| 159 | * in ncr53c9xvar.h. | |||
| 160 | */ | |||
| 161 | const char *ncr53c9x_variant_names[] = { | |||
| 162 | "ESP100", | |||
| 163 | "ESP100A", | |||
| 164 | "ESP200", | |||
| 165 | "NCR53C94", | |||
| 166 | "NCR53C96", | |||
| 167 | "ESP406", | |||
| 168 | "FAS408", | |||
| 169 | "FAS216", | |||
| 170 | "AM53C974", | |||
| 171 | "FAS366/HME", | |||
| 172 | }; | |||
| 173 | ||||
| 174 | /* | |||
| 175 | * Search linked list for LUN info by LUN id. | |||
| 176 | */ | |||
| 177 | static struct ncr53c9x_linfo * | |||
| 178 | ncr53c9x_lunsearch(struct ncr53c9x_tinfo *ti, int64_t lun) | |||
| 179 | { | |||
| 180 | struct ncr53c9x_linfo *li; | |||
| 181 | LIST_FOREACH(li, &ti->luns, link)for((li) = ((&ti->luns)->lh_first); (li)!= ((void * )0); (li) = ((li)->link.le_next)) | |||
| 182 | if (li->lun == lun) | |||
| 183 | return (li); | |||
| 184 | return (NULL((void *)0)); | |||
| 185 | } | |||
| 186 | ||||
| 187 | /* | |||
| 188 | * Attach this instance, and then all the sub-devices | |||
| 189 | */ | |||
| 190 | void | |||
| 191 | ncr53c9x_attach(struct ncr53c9x_softc *sc) | |||
| 192 | { | |||
| 193 | struct scsibus_attach_args saa; | |||
| 194 | ||||
| 195 | /* | |||
| 196 | * Allocate SCSI message buffers. | |||
| 197 | * Front-ends can override allocation to avoid alignment | |||
| 198 | * handling in the DMA engines. Note that ncr53c9x_msgout() | |||
| 199 | * can request a 1 byte DMA transfer. | |||
| 200 | */ | |||
| 201 | if (sc->sc_omess == NULL((void *)0)) | |||
| 202 | sc->sc_omess = malloc(NCR_MAX_MSG_LEN8, M_DEVBUF2, M_NOWAIT0x0002); | |||
| 203 | ||||
| 204 | if (sc->sc_imess == NULL((void *)0)) | |||
| 205 | sc->sc_imess = malloc(NCR_MAX_MSG_LEN8+1, M_DEVBUF2, M_NOWAIT0x0002); | |||
| 206 | ||||
| 207 | if (sc->sc_omess == NULL((void *)0) || sc->sc_imess == NULL((void *)0)) { | |||
| 208 | printf("out of memory\n"); | |||
| 209 | return; | |||
| 210 | } | |||
| 211 | ||||
| 212 | /* | |||
| 213 | * Note, the front-end has set us up to print the chip variation. | |||
| 214 | */ | |||
| 215 | if (sc->sc_rev >= NCR_VARIANT_MAX10) { | |||
| 216 | printf("\n%s: unknown variant %d, devices not attached\n", | |||
| 217 | sc->sc_dev.dv_xname, sc->sc_rev); | |||
| 218 | return; | |||
| 219 | } | |||
| 220 | ||||
| 221 | printf(": %s, %dMHz\n", ncr53c9x_variant_names[sc->sc_rev], | |||
| 222 | sc->sc_freq); | |||
| 223 | ||||
| 224 | sc->sc_ccf = FREQTOCCF(sc->sc_freq)(((sc->sc_freq + 4) / 5)); | |||
| 225 | ||||
| 226 | /* The value *must not* be == 1. Make it 2 */ | |||
| 227 | if (sc->sc_ccf == 1) | |||
| 228 | sc->sc_ccf = 2; | |||
| 229 | ||||
| 230 | /* | |||
| 231 | * The recommended timeout is 250ms. This register is loaded | |||
| 232 | * with a value calculated as follows, from the docs: | |||
| 233 | * | |||
| 234 | * (timeout period) x (CLK frequency) | |||
| 235 | * reg = ------------------------------------- | |||
| 236 | * 8192 x (Clock Conversion Factor) | |||
| 237 | * | |||
| 238 | * Since CCF has a linear relation to CLK, this generally computes | |||
| 239 | * to the constant of 153. | |||
| 240 | */ | |||
| 241 | sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf); | |||
| 242 | ||||
| 243 | /* CCF register only has 3 bits; 0 is actually 8 */ | |||
| 244 | sc->sc_ccf &= 7; | |||
| 245 | ||||
| 246 | /* Find how many targets we need to support */ | |||
| 247 | switch (sc->sc_rev) { | |||
| 248 | case NCR_VARIANT_FAS3669: | |||
| 249 | sc->sc_ntarg = 16; | |||
| 250 | break; | |||
| 251 | default: | |||
| 252 | sc->sc_ntarg = 8; | |||
| 253 | break; | |||
| 254 | } | |||
| 255 | ||||
| 256 | /* Reset state & bus */ | |||
| 257 | sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags; | |||
| 258 | sc->sc_state = 0; | |||
| 259 | ncr53c9x_init(sc, 1); | |||
| 260 | ||||
| 261 | saa.saa_adapter_softc = sc; | |||
| 262 | saa.saa_adapter_target = sc->sc_id; | |||
| 263 | saa.saa_adapter = &ncr53c9x_switch; | |||
| 264 | saa.saa_adapter_buswidth = sc->sc_ntarg; | |||
| 265 | saa.saa_luns = 8; | |||
| 266 | saa.saa_openings = 2; | |||
| 267 | saa.saa_pool = &ecb_iopool; | |||
| 268 | saa.saa_quirks = saa.saa_flags = 0; | |||
| 269 | saa.saa_wwpn = saa.saa_wwnn = 0; | |||
| 270 | ||||
| 271 | config_found(&sc->sc_dev, &saa, scsiprint)config_found_sm((&sc->sc_dev), (&saa), (scsiprint) , ((void *)0)); | |||
| 272 | } | |||
| 273 | ||||
| 274 | /* | |||
| 275 | * This is the generic ncr53c9x reset function. It does not reset the SCSI bus, | |||
| 276 | * only this controller, but kills any on-going commands, and also stops | |||
| 277 | * and resets the DMA. | |||
| 278 | * | |||
| 279 | * After reset, registers are loaded with the defaults from the attach | |||
| 280 | * routine above. | |||
| 281 | */ | |||
| 282 | void | |||
| 283 | ncr53c9x_reset(struct ncr53c9x_softc *sc) | |||
| 284 | { | |||
| 285 | ||||
| 286 | /* reset DMA first */ | |||
| 287 | NCRDMA_RESET(sc)(*(sc)->sc_glue->gl_dma_reset)((sc)); | |||
| 288 | ||||
| 289 | /* reset SCSI chip */ | |||
| 290 | NCRCMD(sc, NCRCMD_RSTCHIP)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x02, 290); sc->sc_lastcmd = 0x02; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x02)); } while (0); | |||
| 291 | NCRCMD(sc, NCRCMD_NOP)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00, 291); sc->sc_lastcmd = 0x00; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x00)); } while (0); | |||
| 292 | DELAY(500)(*delay_func)(500); | |||
| 293 | ||||
| 294 | /* do these backwards, and fall through */ | |||
| 295 | switch (sc->sc_rev) { | |||
| 296 | case NCR_VARIANT_ESP4065: | |||
| 297 | case NCR_VARIANT_FAS4086: | |||
| 298 | NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0d), (sc->sc_cfg5 | 0x04)); | |||
| 299 | NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0d), (sc->sc_cfg4 )); | |||
| 300 | case NCR_VARIANT_AM53C9748: | |||
| 301 | case NCR_VARIANT_FAS2167: | |||
| 302 | case NCR_VARIANT_NCR53C943: | |||
| 303 | case NCR_VARIANT_NCR53C964: | |||
| 304 | case NCR_VARIANT_ESP2002: | |||
| 305 | sc->sc_features |= NCR_F_HASCFG30x01; | |||
| 306 | NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0c), (sc->sc_cfg3 )); | |||
| 307 | case NCR_VARIANT_ESP100A1: | |||
| 308 | sc->sc_features |= NCR_F_SELATN30x08; | |||
| 309 | NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0b), (sc->sc_cfg2 )); | |||
| 310 | case NCR_VARIANT_ESP1000: | |||
| 311 | NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1)(*(sc)->sc_glue->gl_write_reg)((sc), (0x08), (sc->sc_cfg1 )); | |||
| 312 | NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf)(*(sc)->sc_glue->gl_write_reg)((sc), (0x09), (sc->sc_ccf )); | |||
| 313 | NCR_WRITE_REG(sc, NCR_SYNCOFF, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0x07), (0)); | |||
| 314 | NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout)(*(sc)->sc_glue->gl_write_reg)((sc), (0x05), (sc->sc_timeout )); | |||
| 315 | break; | |||
| 316 | case NCR_VARIANT_FAS3669: | |||
| 317 | sc->sc_features |= | |||
| 318 | NCR_F_SELATN30x08 | NCR_F_HASCFG30x01 | NCR_F_FASTSCSI0x02; | |||
| 319 | sc->sc_cfg3 = NCRFASCFG3_FASTCLK0x01 | NCRFASCFG3_OBAUTO0x80; | |||
| 320 | sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI0x02; | |||
| 321 | NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0c), (sc->sc_cfg3 )); | |||
| 322 | sc->sc_cfg2 = 0; /* NCRCFG2_HMEFE | NCRCFG2_HME32 */ | |||
| 323 | NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0b), (sc->sc_cfg2 )); | |||
| 324 | NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1)(*(sc)->sc_glue->gl_write_reg)((sc), (0x08), (sc->sc_cfg1 )); | |||
| 325 | NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf)(*(sc)->sc_glue->gl_write_reg)((sc), (0x09), (sc->sc_ccf )); | |||
| 326 | NCR_WRITE_REG(sc, NCR_SYNCOFF, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0x07), (0)); | |||
| 327 | NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout)(*(sc)->sc_glue->gl_write_reg)((sc), (0x05), (sc->sc_timeout )); | |||
| 328 | break; | |||
| 329 | default: | |||
| 330 | printf("%s: unknown revision code, assuming ESP100\n", | |||
| 331 | sc->sc_dev.dv_xname); | |||
| 332 | NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1)(*(sc)->sc_glue->gl_write_reg)((sc), (0x08), (sc->sc_cfg1 )); | |||
| 333 | NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf)(*(sc)->sc_glue->gl_write_reg)((sc), (0x09), (sc->sc_ccf )); | |||
| 334 | NCR_WRITE_REG(sc, NCR_SYNCOFF, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0x07), (0)); | |||
| 335 | NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout)(*(sc)->sc_glue->gl_write_reg)((sc), (0x05), (sc->sc_timeout )); | |||
| 336 | } | |||
| 337 | ||||
| 338 | if (sc->sc_rev == NCR_VARIANT_AM53C9748) | |||
| 339 | NCR_WRITE_REG(sc, NCR_AMDCFG4, sc->sc_cfg4)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0d), (sc->sc_cfg4 )); | |||
| 340 | ||||
| 341 | #if 0 | |||
| 342 | printf("%s: ncr53c9x_reset: revision %d\n", | |||
| 343 | sc->sc_dev.dv_xname, sc->sc_rev); | |||
| 344 | printf("%s: ncr53c9x_reset: cfg1 0x%x, cfg2 0x%x, cfg3 0x%x, ccf 0x%x, timeout 0x%x\n", | |||
| 345 | sc->sc_dev.dv_xname, | |||
| 346 | sc->sc_cfg1, sc->sc_cfg2, sc->sc_cfg3, | |||
| 347 | sc->sc_ccf, sc->sc_timeout); | |||
| 348 | #endif | |||
| 349 | } | |||
| 350 | ||||
| 351 | /* | |||
| 352 | * Reset the SCSI bus, but not the chip | |||
| 353 | */ | |||
| 354 | void | |||
| 355 | ncr53c9x_scsi_reset(struct ncr53c9x_softc *sc) | |||
| 356 | { | |||
| 357 | ||||
| 358 | (*sc->sc_glue->gl_dma_stop)(sc); | |||
| 359 | ||||
| 360 | printf("%s: resetting SCSI bus\n", sc->sc_dev.dv_xname); | |||
| 361 | NCRCMD(sc, NCRCMD_RSTSCSI)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x03, 361); sc->sc_lastcmd = 0x03; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x03)); } while (0); | |||
| 362 | } | |||
| 363 | ||||
| 364 | /* | |||
| 365 | * Initialize ncr53c9x state machine | |||
| 366 | */ | |||
| 367 | void | |||
| 368 | ncr53c9x_init(struct ncr53c9x_softc *sc, int doreset) | |||
| 369 | { | |||
| 370 | struct ncr53c9x_ecb *ecb; | |||
| 371 | struct ncr53c9x_linfo *li; | |||
| 372 | int r, i; | |||
| 373 | ||||
| 374 | NCR_TRACE(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state))do {if (ncr53c9x_debug & 0x10) printf ("[NCR_INIT(%d) %d] " , doreset, sc->sc_state);} while (0); | |||
| 375 | ||||
| 376 | if (!ecb_pool_initialized) { | |||
| 377 | /* All instances share this pool */ | |||
| 378 | pool_init(&ecb_pool, sizeof(struct ncr53c9x_ecb), 0, IPL_BIO0x3, | |||
| 379 | 0, "ncr53c9x_ecb", NULL((void *)0)); | |||
| 380 | scsi_iopool_init(&ecb_iopool, NULL((void *)0), | |||
| 381 | ncr53c9x_get_ecb, ncr53c9x_free_ecb); | |||
| 382 | ecb_pool_initialized = 1; | |||
| 383 | } | |||
| 384 | ||||
| 385 | if (sc->sc_state == 0) { | |||
| 386 | /* First time through; initialize. */ | |||
| 387 | ||||
| 388 | TAILQ_INIT(&sc->ready_list)do { (&sc->ready_list)->tqh_first = ((void *)0); (& sc->ready_list)->tqh_last = &(&sc->ready_list )->tqh_first; } while (0); | |||
| 389 | sc->sc_nexus = NULL((void *)0); | |||
| 390 | bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo))__builtin_bzero((sc->sc_tinfo), (sizeof(sc->sc_tinfo))); | |||
| 391 | for (r = 0; r < sc->sc_ntarg; r++) { | |||
| 392 | LIST_INIT(&sc->sc_tinfo[r].luns)do { ((&sc->sc_tinfo[r].luns)->lh_first) = ((void * )0); } while (0); | |||
| 393 | } | |||
| 394 | } else { | |||
| 395 | /* Cancel any active commands. */ | |||
| 396 | sc->sc_state = NCR_CLEANING8; | |||
| 397 | sc->sc_msgify = 0; | |||
| 398 | if ((ecb = sc->sc_nexus) != NULL((void *)0)) { | |||
| 399 | ecb->xs->error = XS_TIMEOUT4; | |||
| 400 | ncr53c9x_done(sc, ecb); | |||
| 401 | } | |||
| 402 | for (r = 0; r < sc->sc_ntarg; r++) { | |||
| 403 | LIST_FOREACH(li, &sc->sc_tinfo[r].luns, link)for((li) = ((&sc->sc_tinfo[r].luns)->lh_first); (li )!= ((void *)0); (li) = ((li)->link.le_next)) { | |||
| 404 | if ((ecb = li->untagged)) { | |||
| 405 | li->untagged = NULL((void *)0); | |||
| 406 | /* | |||
| 407 | * XXXXXXX | |||
| 408 | * Should we terminate a command | |||
| 409 | * that never reached the disk? | |||
| 410 | */ | |||
| 411 | li->busy = 0; | |||
| 412 | ecb->xs->error = XS_TIMEOUT4; | |||
| 413 | ncr53c9x_done(sc, ecb); | |||
| 414 | } | |||
| 415 | for (i = 0; i < 256; i++) | |||
| 416 | if ((ecb = li->queued[i])) { | |||
| 417 | li->queued[i] = NULL((void *)0); | |||
| 418 | ecb->xs->error = XS_TIMEOUT4; | |||
| 419 | ncr53c9x_done(sc, ecb); | |||
| 420 | } | |||
| 421 | li->used = 0; | |||
| 422 | } | |||
| 423 | } | |||
| 424 | } | |||
| 425 | ||||
| 426 | /* | |||
| 427 | * reset the chip to a known state | |||
| 428 | */ | |||
| 429 | ncr53c9x_reset(sc); | |||
| 430 | ||||
| 431 | sc->sc_phase = sc->sc_prevphase = INVALID_PHASE0x101; | |||
| 432 | for (r = 0; r < sc->sc_ntarg; r++) { | |||
| 433 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r]; | |||
| 434 | /* XXX - config flags per target: low bits: no reselect; high bits: no synch */ | |||
| 435 | ||||
| 436 | ti->flags = ((!(sc->sc_cfflags & (1 << (r + 16))) && | |||
| 437 | sc->sc_minsync) ? 0 : T_SYNCHOFF0x10) | | |||
| 438 | ((sc->sc_cfflags & (1 << r)) ? T_RSELECTOFF0x20 : 0) | | |||
| 439 | T_NEED_TO_RESET0x01; | |||
| 440 | #ifdef DEBUG | |||
| 441 | if (ncr53c9x_notag) | |||
| 442 | ti->flags &= ~T_TAG0x40; | |||
| 443 | #endif | |||
| 444 | ti->period = sc->sc_minsync; | |||
| 445 | ti->offset = 0; | |||
| 446 | ti->cfg3 = 0; | |||
| 447 | } | |||
| 448 | ||||
| 449 | if (doreset) { | |||
| 450 | sc->sc_state = NCR_SBR9; | |||
| 451 | NCRCMD(sc, NCRCMD_RSTSCSI)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x03, 451); sc->sc_lastcmd = 0x03; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x03)); } while (0); | |||
| 452 | /* | |||
| 453 | * XXX gross... | |||
| 454 | * On some systems, commands issued too close to a reset | |||
| 455 | * do not work correctly. We'll force a short delay on | |||
| 456 | * known-to-be-sensitive chips. | |||
| 457 | */ | |||
| 458 | switch (sc->sc_rev) { | |||
| 459 | case NCR_VARIANT_NCR53C943: | |||
| 460 | DELAY(600000)(*delay_func)(600000); /* 600ms */ | |||
| 461 | break; | |||
| 462 | case NCR_VARIANT_NCR53C964: | |||
| 463 | DELAY(100000)(*delay_func)(100000); /* 100ms */ | |||
| 464 | break; | |||
| 465 | } | |||
| 466 | } else { | |||
| 467 | sc->sc_state = NCR_IDLE1; | |||
| 468 | ncr53c9x_sched(sc); | |||
| 469 | } | |||
| 470 | } | |||
| 471 | ||||
| 472 | /* | |||
| 473 | * Read the NCR registers, and save their contents for later use. | |||
| 474 | * NCR_STAT, NCR_STEP & NCR_INTR are mostly zeroed out when reading | |||
| 475 | * NCR_INTR - so make sure it is the last read. | |||
| 476 | * | |||
| 477 | * I think that (from reading the docs) most bits in these registers | |||
| 478 | * only make sense when he DMA CSR has an interrupt showing. Call only | |||
| 479 | * if an interrupt is pending. | |||
| 480 | */ | |||
| 481 | __inline__ void | |||
| 482 | ncr53c9x_readregs(struct ncr53c9x_softc *sc) | |||
| 483 | { | |||
| 484 | ||||
| 485 | sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT)(*(sc)->sc_glue->gl_read_reg)((sc), (0x04)); | |||
| 486 | /* Only the stepo bits are of interest */ | |||
| 487 | sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP)(*(sc)->sc_glue->gl_read_reg)((sc), (0x06)) & NCRSTEP_MASK0x07; | |||
| 488 | ||||
| 489 | if (sc->sc_rev == NCR_VARIANT_FAS3669) | |||
| 490 | sc->sc_espstat2 = NCR_READ_REG(sc, NCR_STAT2)(*(sc)->sc_glue->gl_read_reg)((sc), (0x09)); | |||
| 491 | ||||
| 492 | sc->sc_espintr = NCR_READ_REG(sc, NCR_INTR)(*(sc)->sc_glue->gl_read_reg)((sc), (0x05)); | |||
| 493 | ||||
| 494 | if (sc->sc_glue->gl_clear_latched_intr != NULL((void *)0)) | |||
| 495 | (*sc->sc_glue->gl_clear_latched_intr)(sc); | |||
| 496 | ||||
| 497 | /* | |||
| 498 | * Determine the SCSI bus phase, return either a real SCSI bus phase | |||
| 499 | * or some pseudo phase we use to detect certain exceptions. | |||
| 500 | */ | |||
| 501 | ||||
| 502 | sc->sc_phase = (sc->sc_espintr & NCRINTR_DIS0x20) | |||
| 503 | ? /* Disconnected */ BUSFREE_PHASE0x100 | |||
| 504 | : sc->sc_espstat & NCRSTAT_PHASE0x07; | |||
| 505 | ||||
| 506 | NCR_MISC(("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] ",do {if (ncr53c9x_debug & 0x08) printf ("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] " , sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc ->sc_espstat2);} while (0) | |||
| 507 | sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc->sc_espstat2))do {if (ncr53c9x_debug & 0x08) printf ("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] " , sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc ->sc_espstat2);} while (0); | |||
| 508 | } | |||
| 509 | ||||
| 510 | /* | |||
| 511 | * Convert Synchronous Transfer Period to chip register Clock Per Byte value. | |||
| 512 | */ | |||
| 513 | static inline int | |||
| 514 | ncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period) | |||
| 515 | { | |||
| 516 | int v; | |||
| 517 | v = (sc->sc_freq * period) / 250; | |||
| 518 | if (ncr53c9x_cpb2stp(sc, v)((250 * (v)) / (sc)->sc_freq) < period) | |||
| 519 | /* Correct round-down error */ | |||
| 520 | v++; | |||
| 521 | return (v); | |||
| 522 | } | |||
| 523 | ||||
| 524 | static inline void | |||
| 525 | ncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti) | |||
| 526 | { | |||
| 527 | u_char syncoff, synctp; | |||
| 528 | u_char cfg3 = sc->sc_cfg3 | ti->cfg3; | |||
| 529 | ||||
| 530 | if (ti->flags & T_SYNCMODE0x08) { | |||
| 531 | syncoff = ti->offset; | |||
| 532 | synctp = ncr53c9x_stp2cpb(sc, ti->period); | |||
| 533 | if (sc->sc_features & NCR_F_FASTSCSI0x02) { | |||
| 534 | /* | |||
| 535 | * If the period is 200ns or less (ti->period <= 50), | |||
| 536 | * put the chip in Fast SCSI mode. | |||
| 537 | */ | |||
| 538 | if (ti->period <= 50) | |||
| 539 | /* | |||
| 540 | * There are (at least) 4 variations of the | |||
| 541 | * configuration 3 register. The drive attach | |||
| 542 | * routine sets the appropriate bit to put the | |||
| 543 | * chip into Fast SCSI mode so that it doesn't | |||
| 544 | * have to be figured out here each time. | |||
| 545 | */ | |||
| 546 | cfg3 |= (sc->sc_rev == NCR_VARIANT_AM53C9748) ? | |||
| 547 | NCRAMDCFG3_FSCSI0x10 : NCRCFG3_FSCSI0x02; | |||
| 548 | } | |||
| 549 | ||||
| 550 | /* | |||
| 551 | * Am53c974 requires different SYNCTP values when the | |||
| 552 | * FSCSI bit is off. | |||
| 553 | */ | |||
| 554 | if (sc->sc_rev == NCR_VARIANT_AM53C9748 && | |||
| 555 | (cfg3 & NCRAMDCFG3_FSCSI0x10) == 0) | |||
| 556 | synctp--; | |||
| 557 | } else { | |||
| 558 | syncoff = 0; | |||
| 559 | synctp = 0; | |||
| 560 | } | |||
| 561 | ||||
| 562 | if (sc->sc_features & NCR_F_HASCFG30x01) | |||
| 563 | NCR_WRITE_REG(sc, NCR_CFG3, cfg3)(*(sc)->sc_glue->gl_write_reg)((sc), (0x0c), (cfg3)); | |||
| 564 | ||||
| 565 | NCR_WRITE_REG(sc, NCR_SYNCOFF, syncoff)(*(sc)->sc_glue->gl_write_reg)((sc), (0x07), (syncoff)); | |||
| 566 | NCR_WRITE_REG(sc, NCR_SYNCTP, synctp)(*(sc)->sc_glue->gl_write_reg)((sc), (0x06), (synctp)); | |||
| 567 | } | |||
| 568 | ||||
| 569 | /* | |||
| 570 | * Send a command to a target, set the driver state to NCR_SELECTING | |||
| 571 | * and let the caller take care of the rest. | |||
| 572 | * | |||
| 573 | * Keeping this as a function allows me to say that this may be done | |||
| 574 | * by DMA instead of programmed I/O soon. | |||
| 575 | */ | |||
| 576 | void | |||
| 577 | ncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) | |||
| 578 | { | |||
| 579 | struct scsi_link *sc_link = ecb->xs->sc_link; | |||
| 580 | int target = sc_link->target; | |||
| 581 | int lun = sc_link->lun; | |||
| 582 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[target]; | |||
| 583 | int tiflags = ti->flags; | |||
| 584 | u_char *cmd; | |||
| 585 | int clen; | |||
| 586 | int selatn3, selatns; | |||
| 587 | size_t dmasize; | |||
| 588 | ||||
| 589 | NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x,tag%x,%x)] ",do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_select(t%d,l%d,cmd:%x,tag%x,%x)] " , target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb-> tag[1]);} while (0) | |||
| 590 | target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1]))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_select(t%d,l%d,cmd:%x,tag%x,%x)] " , target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb-> tag[1]);} while (0); | |||
| 591 | ||||
| 592 | sc->sc_state = NCR_SELECTING2; | |||
| 593 | /* | |||
| 594 | * Schedule the timeout now, the first time we will go away | |||
| 595 | * expecting to come back due to an interrupt, because it is | |||
| 596 | * always possible that the interrupt may never happen. | |||
| 597 | */ | |||
| 598 | if ((ecb->xs->flags & SCSI_POLL0x00002) == 0) { | |||
| 599 | int timeout = ecb->timeout; | |||
| 600 | ||||
| 601 | if (timeout > 1000000) | |||
| 602 | timeout = (timeout / 1000) * hz; | |||
| 603 | else | |||
| 604 | timeout = (timeout * hz) / 1000; | |||
| 605 | timeout_add(&ecb->to, timeout); | |||
| 606 | } | |||
| 607 | ||||
| 608 | /* | |||
| 609 | * The docs say the target register is never reset, and I | |||
| 610 | * can't think of a better place to set it | |||
| 611 | */ | |||
| 612 | if (sc->sc_rev == NCR_VARIANT_FAS3669) { | |||
| 613 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 613); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 614 | NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HME)(*(sc)->sc_glue->gl_write_reg)((sc), (0x04), (target | 0x10 )); | |||
| 615 | } else { | |||
| 616 | NCR_WRITE_REG(sc, NCR_SELID, target)(*(sc)->sc_glue->gl_write_reg)((sc), (0x04), (target)); | |||
| 617 | } | |||
| 618 | ncr53c9x_setsync(sc, ti); | |||
| 619 | ||||
| 620 | if ((ecb->flags & ECB_SENSE0x04) != 0) { | |||
| 621 | /* | |||
| 622 | * For REQUEST SENSE, we should not send an IDENTIFY or | |||
| 623 | * otherwise mangle the target. There should be no MESSAGE IN | |||
| 624 | * phase. | |||
| 625 | */ | |||
| 626 | if (sc->sc_features & NCR_F_DMASELECT0x04) { | |||
| 627 | /* setup DMA transfer for command */ | |||
| 628 | dmasize = clen = ecb->clen; | |||
| 629 | sc->sc_cmdlen = clen; | |||
| 630 | sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd; | |||
| 631 | ||||
| 632 | NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0,(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_cmdp ), (&sc->sc_cmdlen), (0), (&dmasize)) | |||
| 633 | &dmasize)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_cmdp ), (&sc->sc_cmdlen), (0), (&dmasize)); | |||
| 634 | /* Program the SCSI counter */ | |||
| 635 | NCR_SET_COUNT(sc, dmasize)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (dmasize))); (*((sc))->sc_glue->gl_write_reg)(((sc)), ( 0x01), ((dmasize) >> 8)); if ((sc->sc_cfg2 & 0x40 ) || (sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg )(((sc)), (0x0e), ((dmasize) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0 )); } } while (0); | |||
| 636 | ||||
| 637 | if (sc->sc_rev != NCR_VARIANT_FAS3669) | |||
| 638 | NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00|0x80, 638); sc->sc_lastcmd = 0x00|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x00|0x80) ); } while (0); | |||
| 639 | ||||
| 640 | /* And get the targets attention */ | |||
| 641 | NCRCMD(sc, NCRCMD_SELNATN | NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x41 | 0x80, 641); sc->sc_lastcmd = 0x41 | 0x80 ; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x41 | 0x80 )); } while (0); | |||
| 642 | NCRDMA_GO(sc)(*(sc)->sc_glue->gl_dma_go)((sc)); | |||
| 643 | } else { | |||
| 644 | ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen); | |||
| 645 | sc->sc_cmdlen = 0; | |||
| 646 | NCRCMD(sc, NCRCMD_SELNATN)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x41, 646); sc->sc_lastcmd = 0x41; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x41)); } while (0); | |||
| 647 | } | |||
| 648 | return; | |||
| 649 | } | |||
| 650 | ||||
| 651 | selatn3 = selatns = 0; | |||
| 652 | if (ecb->tag[0] != 0) { | |||
| 653 | if (sc->sc_features & NCR_F_SELATN30x08) | |||
| 654 | /* use SELATN3 to send tag messages */ | |||
| 655 | selatn3 = 1; | |||
| 656 | else | |||
| 657 | /* We don't have SELATN3; use SELATNS to send tags */ | |||
| 658 | selatns = 1; | |||
| 659 | } | |||
| 660 | ||||
| 661 | if (ti->flags & T_NEGOTIATE0x02) { | |||
| 662 | /* We have to use SELATNS to send sync/wide messages */ | |||
| 663 | selatn3 = 0; | |||
| 664 | selatns = 1; | |||
| 665 | } | |||
| 666 | ||||
| 667 | cmd = (u_char *)&ecb->cmd.cmd; | |||
| 668 | ||||
| 669 | if (selatn3) { | |||
| 670 | /* We'll use tags with SELATN3 */ | |||
| 671 | clen = ecb->clen + 3; | |||
| 672 | cmd -= 3; | |||
| 673 | cmd[0] = MSG_IDENTIFY(lun, 1)(((1) ? 0xc0 : 0x80) | (lun)); /* msg[0] */ | |||
| 674 | cmd[1] = ecb->tag[0]; /* msg[1] */ | |||
| 675 | cmd[2] = ecb->tag[1]; /* msg[2] */ | |||
| 676 | } else { | |||
| 677 | /* We don't have tags, or will send messages with SELATNS */ | |||
| 678 | clen = ecb->clen + 1; | |||
| 679 | cmd -= 1; | |||
| 680 | cmd[0] = MSG_IDENTIFY(lun, (tiflags & T_RSELECTOFF) == 0)((((tiflags & 0x20) == 0) ? 0xc0 : 0x80) | (lun)); | |||
| 681 | } | |||
| 682 | ||||
| 683 | if ((sc->sc_features & NCR_F_DMASELECT0x04) && !selatns) { | |||
| 684 | ||||
| 685 | /* setup DMA transfer for command */ | |||
| 686 | dmasize = clen; | |||
| 687 | sc->sc_cmdlen = clen; | |||
| 688 | sc->sc_cmdp = cmd; | |||
| 689 | ||||
| 690 | NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_cmdp ), (&sc->sc_cmdlen), (0), (&dmasize)); | |||
| 691 | /* Program the SCSI counter */ | |||
| 692 | NCR_SET_COUNT(sc, dmasize)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (dmasize))); (*((sc))->sc_glue->gl_write_reg)(((sc)), ( 0x01), ((dmasize) >> 8)); if ((sc->sc_cfg2 & 0x40 ) || (sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg )(((sc)), (0x0e), ((dmasize) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0 )); } } while (0); | |||
| 693 | ||||
| 694 | /* load the count in */ | |||
| 695 | /* if (sc->sc_rev != NCR_VARIANT_FAS366) */ | |||
| 696 | NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00|0x80, 696); sc->sc_lastcmd = 0x00|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x00|0x80) ); } while (0); | |||
| 697 | ||||
| 698 | /* And get the targets attention */ | |||
| 699 | if (selatn3) { | |||
| 700 | sc->sc_msgout = SEND_TAG0x0100; | |||
| 701 | sc->sc_flags |= NCR_ATN0x40; | |||
| 702 | NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x46 | 0x80, 702); sc->sc_lastcmd = 0x46 | 0x80 ; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x46 | 0x80 )); } while (0); | |||
| 703 | } else | |||
| 704 | NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x42 | 0x80, 704); sc->sc_lastcmd = 0x42 | 0x80 ; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x42 | 0x80 )); } while (0); | |||
| 705 | NCRDMA_GO(sc)(*(sc)->sc_glue->gl_dma_go)((sc)); | |||
| 706 | return; | |||
| 707 | } | |||
| 708 | ||||
| 709 | /* | |||
| 710 | * Who am I. This is where we tell the target that we are | |||
| 711 | * happy for it to disconnect etc. | |||
| 712 | */ | |||
| 713 | ||||
| 714 | /* Now get the command into the FIFO */ | |||
| 715 | sc->sc_cmdlen = 0; | |||
| 716 | ncr53c9x_wrfifo(sc, cmd, clen); | |||
| 717 | ||||
| 718 | /* And get the targets attention */ | |||
| 719 | if (selatns) { | |||
| 720 | NCR_MISC(("SELATNS \n"))do {if (ncr53c9x_debug & 0x08) printf ("SELATNS \n");} while (0); | |||
| 721 | /* Arbitrate, select and stop after IDENTIFY message */ | |||
| 722 | NCRCMD(sc, NCRCMD_SELATNS)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x43, 722); sc->sc_lastcmd = 0x43; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x43)); } while (0); | |||
| 723 | } else if (selatn3) { | |||
| 724 | sc->sc_msgout = SEND_TAG0x0100; | |||
| 725 | sc->sc_flags |= NCR_ATN0x40; | |||
| 726 | NCRCMD(sc, NCRCMD_SELATN3)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x46, 726); sc->sc_lastcmd = 0x46; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x46)); } while (0); | |||
| 727 | } else | |||
| 728 | NCRCMD(sc, NCRCMD_SELATN)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x42, 728); sc->sc_lastcmd = 0x42; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x42)); } while (0); | |||
| 729 | } | |||
| 730 | ||||
| 731 | /* | |||
| 732 | * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS | |||
| 733 | */ | |||
| 734 | ||||
| 735 | void * | |||
| 736 | ncr53c9x_get_ecb(void *null) | |||
| 737 | { | |||
| 738 | struct ncr53c9x_ecb *ecb; | |||
| 739 | ||||
| 740 | ecb = pool_get(&ecb_pool, M_NOWAIT0x0002|M_ZERO0x0008); | |||
| 741 | if (ecb == NULL((void *)0)) | |||
| 742 | return (NULL((void *)0)); | |||
| 743 | ||||
| 744 | timeout_set(&ecb->to, ncr53c9x_timeout, ecb); | |||
| 745 | ecb->flags |= ECB_ALLOC0x01; | |||
| 746 | ||||
| 747 | return (ecb); | |||
| 748 | } | |||
| 749 | ||||
| 750 | void | |||
| 751 | ncr53c9x_free_ecb(void *null, void *ecb) | |||
| 752 | { | |||
| 753 | pool_put(&ecb_pool, ecb); | |||
| 754 | } | |||
| 755 | ||||
| 756 | int | |||
| 757 | ncr53c9x_scsi_probe(struct scsi_link *sc_link) | |||
| 758 | { | |||
| 759 | struct ncr53c9x_softc *sc = sc_link->bus->sb_adapter_softc; | |||
| 760 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target]; | |||
| 761 | struct ncr53c9x_linfo *li; | |||
| 762 | int64_t lun = sc_link->lun; | |||
| 763 | int s; | |||
| 764 | ||||
| 765 | /* Initialize LUN info and add to list. */ | |||
| 766 | li = malloc(sizeof(*li), M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 767 | if (li == NULL((void *)0)) | |||
| 768 | return (ENOMEM12); | |||
| 769 | ||||
| 770 | li->last_used = getuptime(); | |||
| 771 | li->lun = lun; | |||
| 772 | ||||
| 773 | s = splbio()splraise(0x3); | |||
| 774 | LIST_INSERT_HEAD(&ti->luns, li, link)do { if (((li)->link.le_next = (&ti->luns)->lh_first ) != ((void *)0)) (&ti->luns)->lh_first->link.le_prev = &(li)->link.le_next; (&ti->luns)->lh_first = (li); (li)->link.le_prev = &(&ti->luns)-> lh_first; } while (0); | |||
| 775 | if (lun < NCR_NLUN8) | |||
| 776 | ti->lun[lun] = li; | |||
| 777 | splx(s)spllower(s); | |||
| 778 | ||||
| 779 | return (0); | |||
| 780 | ||||
| 781 | } | |||
| 782 | ||||
| 783 | void | |||
| 784 | ncr53c9x_scsi_free(struct scsi_link *sc_link) | |||
| 785 | { | |||
| 786 | struct ncr53c9x_softc *sc = sc_link->bus->sb_adapter_softc; | |||
| 787 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target]; | |||
| 788 | struct ncr53c9x_linfo *li; | |||
| 789 | int64_t lun = sc_link->lun; | |||
| 790 | int s; | |||
| 791 | ||||
| 792 | s = splbio()splraise(0x3); | |||
| 793 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 794 | ||||
| 795 | LIST_REMOVE(li, link)do { if ((li)->link.le_next != ((void *)0)) (li)->link. le_next->link.le_prev = (li)->link.le_prev; *(li)->link .le_prev = (li)->link.le_next; ((li)->link.le_prev) = ( (void *)-1); ((li)->link.le_next) = ((void *)-1); } while ( 0); | |||
| 796 | if (lun < NCR_NLUN8) | |||
| 797 | ti->lun[lun] = NULL((void *)0); | |||
| 798 | splx(s)spllower(s); | |||
| 799 | ||||
| 800 | free(li, M_DEVBUF2, 0); | |||
| 801 | } | |||
| 802 | ||||
| 803 | /* | |||
| 804 | * Start a SCSI-command | |||
| 805 | * This function is called by the higher level SCSI-driver to queue/run | |||
| 806 | * SCSI-commands. | |||
| 807 | */ | |||
| 808 | void | |||
| 809 | ncr53c9x_scsi_cmd(struct scsi_xfer *xs) | |||
| 810 | { | |||
| 811 | struct scsi_link *sc_link = xs->sc_link; | |||
| 812 | struct ncr53c9x_softc *sc = sc_link->bus->sb_adapter_softc; | |||
| 813 | struct ncr53c9x_ecb *ecb; | |||
| 814 | struct ncr53c9x_tinfo *ti; | |||
| 815 | struct ncr53c9x_linfo *li; | |||
| 816 | int64_t lun = sc_link->lun; | |||
| 817 | int s, flags; | |||
| 818 | ||||
| 819 | NCR_TRACE(("[ncr53c9x_scsi_cmd] "))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_scsi_cmd] " );} while (0); | |||
| 820 | NCR_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd.opcode, xs->cmdlen,do {if (ncr53c9x_debug & 0x04) printf ("[0x%x, %d]->%d " , (int)xs->cmd.opcode, xs->cmdlen, sc_link->target); } while (0) | |||
| 821 | sc_link->target))do {if (ncr53c9x_debug & 0x04) printf ("[0x%x, %d]->%d " , (int)xs->cmd.opcode, xs->cmdlen, sc_link->target); } while (0); | |||
| 822 | ||||
| 823 | /* | |||
| 824 | * Commands larger than 12 bytes seem to confuse the chip | |||
| 825 | * (at least on FAS366 flavours). | |||
| 826 | */ | |||
| 827 | if (xs->cmdlen > 12) { | |||
| 828 | memset(&xs->sense, 0, sizeof(xs->sense))__builtin_memset((&xs->sense), (0), (sizeof(xs->sense ))); | |||
| 829 | /* sense data borrowed from gdt(4) */ | |||
| 830 | xs->sense.error_code = SSD_ERRCODE_VALID0x80 | SSD_ERRCODE_CURRENT0x70; | |||
| 831 | xs->sense.flags = SKEY_ILLEGAL_REQUEST0x05; | |||
| 832 | xs->sense.add_sense_code = 0x20; /* illcmd */ | |||
| 833 | xs->error = XS_SENSE1; | |||
| 834 | scsi_done(xs); | |||
| 835 | return; | |||
| 836 | } | |||
| 837 | ||||
| 838 | flags = xs->flags; | |||
| 839 | ti = &sc->sc_tinfo[sc_link->target]; | |||
| 840 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 841 | ||||
| 842 | /* Initialize ecb */ | |||
| 843 | ecb = xs->io; | |||
| 844 | ecb->xs = xs; | |||
| 845 | ecb->timeout = xs->timeout; | |||
| 846 | ||||
| 847 | if (flags & SCSI_RESET0x00200) { | |||
| 848 | ecb->flags |= ECB_RESET0x80; | |||
| 849 | ecb->clen = 0; | |||
| 850 | ecb->dleft = 0; | |||
| 851 | } else { | |||
| 852 | bcopy(&xs->cmd, &ecb->cmd.cmd, xs->cmdlen); | |||
| 853 | ecb->clen = xs->cmdlen; | |||
| 854 | ecb->daddr = xs->data; | |||
| 855 | ecb->dleft = xs->datalen; | |||
| 856 | } | |||
| 857 | ecb->stat = 0; | |||
| 858 | ||||
| 859 | s = splbio()splraise(0x3); | |||
| 860 | ||||
| 861 | TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain)do { (ecb)->chain.tqe_next = ((void *)0); (ecb)->chain. tqe_prev = (&sc->ready_list)->tqh_last; *(&sc-> ready_list)->tqh_last = (ecb); (&sc->ready_list)-> tqh_last = &(ecb)->chain.tqe_next; } while (0); | |||
| 862 | ecb->flags |= ECB_READY0x02; | |||
| 863 | if (sc->sc_state == NCR_IDLE1) | |||
| 864 | ncr53c9x_sched(sc); | |||
| 865 | ||||
| 866 | splx(s)spllower(s); | |||
| 867 | ||||
| 868 | if ((flags & SCSI_POLL0x00002) == 0) | |||
| 869 | return; | |||
| 870 | ||||
| 871 | /* Not allowed to use interrupts, use polling instead */ | |||
| 872 | if (ncr53c9x_poll(sc, xs, ecb->timeout)) { | |||
| 873 | ncr53c9x_timeout(ecb); | |||
| 874 | if (ncr53c9x_poll(sc, xs, ecb->timeout)) | |||
| 875 | ncr53c9x_timeout(ecb); | |||
| 876 | } | |||
| 877 | } | |||
| 878 | ||||
| 879 | /* | |||
| 880 | * Used when interrupt driven I/O isn't allowed, e.g. during boot. | |||
| 881 | */ | |||
| 882 | int | |||
| 883 | ncr53c9x_poll(struct ncr53c9x_softc *sc, struct scsi_xfer *xs, int count) | |||
| 884 | { | |||
| 885 | int s; | |||
| 886 | ||||
| 887 | NCR_TRACE(("[ncr53c9x_poll] "))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_poll] " );} while (0); | |||
| 888 | while (count) { | |||
| 889 | if (NCRDMA_ISINTR(sc)(*(sc)->sc_glue->gl_dma_isintr)((sc))) { | |||
| 890 | s = splbio()splraise(0x3); | |||
| 891 | ncr53c9x_intr(sc); | |||
| 892 | splx(s)spllower(s); | |||
| 893 | } | |||
| 894 | #if alternatively | |||
| 895 | if (NCR_READ_REG(sc, NCR_STAT)(*(sc)->sc_glue->gl_read_reg)((sc), (0x04)) & NCRSTAT_INT0x80) { | |||
| 896 | s = splbio()splraise(0x3); | |||
| 897 | ncr53c9x_intr(sc); | |||
| 898 | splx(s)spllower(s); | |||
| 899 | } | |||
| 900 | #endif | |||
| 901 | if ((xs->flags & ITSDONE0x00008) != 0) | |||
| 902 | return (0); | |||
| 903 | s = splbio()splraise(0x3); | |||
| 904 | if (sc->sc_state == NCR_IDLE1) { | |||
| 905 | NCR_TRACE(("[ncr53c9x_poll: rescheduling] "))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_poll: rescheduling] " );} while (0); | |||
| 906 | ncr53c9x_sched(sc); | |||
| 907 | } | |||
| 908 | splx(s)spllower(s); | |||
| 909 | DELAY(1000)(*delay_func)(1000); | |||
| 910 | count--; | |||
| 911 | } | |||
| 912 | return (1); | |||
| 913 | } | |||
| 914 | ||||
| 915 | ||||
| 916 | /* | |||
| 917 | * LOW LEVEL SCSI UTILITIES | |||
| 918 | */ | |||
| 919 | ||||
| 920 | /* | |||
| 921 | * Schedule a scsi operation. This has now been pulled out of the interrupt | |||
| 922 | * handler so that we may call it from ncr53c9x_scsi_cmd and ncr53c9x_done. | |||
| 923 | * This may save us an unnecessary interrupt just to get things going. | |||
| 924 | * Should only be called when state == NCR_IDLE and at bio pl. | |||
| 925 | */ | |||
| 926 | void | |||
| 927 | ncr53c9x_sched(struct ncr53c9x_softc *sc) | |||
| 928 | { | |||
| 929 | struct ncr53c9x_ecb *ecb; | |||
| 930 | struct scsi_link *sc_link; | |||
| 931 | struct ncr53c9x_tinfo *ti; | |||
| 932 | int lun; | |||
| 933 | struct ncr53c9x_linfo *li; | |||
| 934 | int s, tag; | |||
| 935 | ||||
| 936 | NCR_TRACE(("[ncr53c9x_sched] "))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_sched] " );} while (0); | |||
| 937 | if (sc->sc_state != NCR_IDLE1) | |||
| 938 | panic("ncr53c9x_sched: not IDLE (state=%d)", sc->sc_state); | |||
| 939 | ||||
| 940 | /* | |||
| 941 | * Find first ecb in ready queue that is for a target/lunit | |||
| 942 | * combinations that is not busy. | |||
| 943 | */ | |||
| 944 | TAILQ_FOREACH(ecb, &sc->ready_list, chain)for((ecb) = ((&sc->ready_list)->tqh_first); (ecb) != ((void *)0); (ecb) = ((ecb)->chain.tqe_next)) { | |||
| 945 | sc_link = ecb->xs->sc_link; | |||
| 946 | ti = &sc->sc_tinfo[sc_link->target]; | |||
| 947 | lun = sc_link->lun; | |||
| 948 | ||||
| 949 | /* Select type of tag for this command */ | |||
| 950 | if ((ti->flags & (T_RSELECTOFF0x20)) != 0) | |||
| 951 | tag = 0; | |||
| 952 | else if ((ti->flags & T_TAG0x40) == 0) | |||
| 953 | tag = 0; | |||
| 954 | else if ((ecb->flags & ECB_SENSE0x04) != 0) | |||
| 955 | tag = 0; | |||
| 956 | else | |||
| 957 | tag = MSG_SIMPLE_Q_TAG0x20; | |||
| 958 | #if 0 | |||
| 959 | /* XXXX Use tags for polled commands? */ | |||
| 960 | if (ecb->xs->flags & SCSI_POLL0x00002) | |||
| 961 | tag = 0; | |||
| 962 | #endif | |||
| 963 | s = splbio()splraise(0x3); | |||
| 964 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 965 | if (!li) { | |||
| 966 | /* Initialize LUN info and add to list. */ | |||
| 967 | if ((li = malloc(sizeof(*li), M_DEVBUF2, | |||
| 968 | M_NOWAIT0x0002 | M_ZERO0x0008)) == NULL((void *)0)) { | |||
| 969 | splx(s)spllower(s); | |||
| 970 | continue; | |||
| 971 | } | |||
| 972 | li->lun = lun; | |||
| 973 | ||||
| 974 | LIST_INSERT_HEAD(&ti->luns, li, link)do { if (((li)->link.le_next = (&ti->luns)->lh_first ) != ((void *)0)) (&ti->luns)->lh_first->link.le_prev = &(li)->link.le_next; (&ti->luns)->lh_first = (li); (li)->link.le_prev = &(&ti->luns)-> lh_first; } while (0); | |||
| 975 | if (lun < NCR_NLUN8) | |||
| 976 | ti->lun[lun] = li; | |||
| 977 | } | |||
| 978 | li->last_used = getuptime(); | |||
| 979 | if (!tag) { | |||
| 980 | /* Try to issue this as an un-tagged command */ | |||
| 981 | if (!li->untagged) | |||
| 982 | li->untagged = ecb; | |||
| 983 | } | |||
| 984 | if (li->untagged) { | |||
| 985 | tag = 0; | |||
| 986 | if ((li->busy != 1) && !li->used) { | |||
| 987 | /* We need to issue this untagged command now */ | |||
| 988 | ecb = li->untagged; | |||
| 989 | sc_link = ecb->xs->sc_link; | |||
| 990 | } | |||
| 991 | else { | |||
| 992 | /* Not ready yet */ | |||
| 993 | splx(s)spllower(s); | |||
| 994 | continue; | |||
| 995 | } | |||
| 996 | } | |||
| 997 | ecb->tag[0] = tag; | |||
| 998 | if (tag) { | |||
| 999 | int i; | |||
| 1000 | ||||
| 1001 | /* Allocate a tag */ | |||
| 1002 | if (li->used == 255) { | |||
| 1003 | /* no free tags */ | |||
| 1004 | splx(s)spllower(s); | |||
| 1005 | continue; | |||
| 1006 | } | |||
| 1007 | /* Start from the last used location */ | |||
| 1008 | for (i=li->avail; i<256; i++) { | |||
| 1009 | if (li->queued[i] == NULL((void *)0)) | |||
| 1010 | break; | |||
| 1011 | } | |||
| 1012 | /* Couldn't find one, start again from the beginning */ | |||
| 1013 | if (i == 256) { | |||
| 1014 | for (i = 0; i<256; i++) { | |||
| 1015 | if (li->queued[i] == NULL((void *)0)) | |||
| 1016 | break; | |||
| 1017 | } | |||
| 1018 | } | |||
| 1019 | #ifdef DIAGNOSTIC1 | |||
| 1020 | if (i == 256) | |||
| 1021 | panic("ncr53c9x_sched: tag alloc failure"); | |||
| 1022 | #endif | |||
| 1023 | ||||
| 1024 | /* Save where to start next time. */ | |||
| 1025 | li->avail = i+1; | |||
| 1026 | li->used++; | |||
| 1027 | ||||
| 1028 | li->queued[i] = ecb; | |||
| 1029 | ecb->tag[1] = i; | |||
| 1030 | } | |||
| 1031 | splx(s)spllower(s); | |||
| 1032 | if (li->untagged && (li->busy != 1)) { | |||
| 1033 | li->busy = 1; | |||
| 1034 | TAILQ_REMOVE(&sc->ready_list, ecb, chain)do { if (((ecb)->chain.tqe_next) != ((void *)0)) (ecb)-> chain.tqe_next->chain.tqe_prev = (ecb)->chain.tqe_prev; else (&sc->ready_list)->tqh_last = (ecb)->chain .tqe_prev; *(ecb)->chain.tqe_prev = (ecb)->chain.tqe_next ; ((ecb)->chain.tqe_prev) = ((void *)-1); ((ecb)->chain .tqe_next) = ((void *)-1); } while (0); | |||
| 1035 | ecb->flags &= ~ECB_READY0x02; | |||
| 1036 | sc->sc_nexus = ecb; | |||
| 1037 | ncr53c9x_select(sc, ecb); | |||
| 1038 | break; | |||
| 1039 | } | |||
| 1040 | if (!li->untagged && tag) { | |||
| 1041 | TAILQ_REMOVE(&sc->ready_list, ecb, chain)do { if (((ecb)->chain.tqe_next) != ((void *)0)) (ecb)-> chain.tqe_next->chain.tqe_prev = (ecb)->chain.tqe_prev; else (&sc->ready_list)->tqh_last = (ecb)->chain .tqe_prev; *(ecb)->chain.tqe_prev = (ecb)->chain.tqe_next ; ((ecb)->chain.tqe_prev) = ((void *)-1); ((ecb)->chain .tqe_next) = ((void *)-1); } while (0); | |||
| 1042 | ecb->flags &= ~ECB_READY0x02; | |||
| 1043 | sc->sc_nexus = ecb; | |||
| 1044 | ncr53c9x_select(sc, ecb); | |||
| 1045 | break; | |||
| 1046 | } else | |||
| 1047 | NCR_MISC(("%d:%d busy\n",do {if (ncr53c9x_debug & 0x08) printf ("%d:%d busy\n", sc_link ->target, sc_link->lun);} while (0) | |||
| 1048 | sc_link->target,do {if (ncr53c9x_debug & 0x08) printf ("%d:%d busy\n", sc_link ->target, sc_link->lun);} while (0) | |||
| 1049 | sc_link->lun))do {if (ncr53c9x_debug & 0x08) printf ("%d:%d busy\n", sc_link ->target, sc_link->lun);} while (0); | |||
| 1050 | } | |||
| 1051 | } | |||
| 1052 | ||||
| 1053 | void | |||
| 1054 | ncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) | |||
| 1055 | { | |||
| 1056 | struct scsi_xfer *xs = ecb->xs; | |||
| 1057 | struct scsi_link *sc_link = xs->sc_link; | |||
| 1058 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target]; | |||
| 1059 | struct scsi_sense *ss = (void *)&ecb->cmd.cmd; | |||
| 1060 | struct ncr53c9x_linfo *li; | |||
| 1061 | int lun = sc_link->lun; | |||
| 1062 | ||||
| 1063 | NCR_MISC(("requesting sense "))do {if (ncr53c9x_debug & 0x08) printf ("requesting sense " );} while (0); | |||
| 1064 | /* Next, setup a request sense command block */ | |||
| 1065 | bzero(ss, sizeof(*ss))__builtin_bzero((ss), (sizeof(*ss))); | |||
| 1066 | ss->opcode = REQUEST_SENSE0x03; | |||
| 1067 | ss->byte2 = sc_link->lun << 5; | |||
| 1068 | ss->length = sizeof(struct scsi_sense_data); | |||
| 1069 | ecb->clen = sizeof(*ss); | |||
| 1070 | ecb->daddr = (char *)&xs->sense; | |||
| 1071 | ecb->dleft = sizeof(struct scsi_sense_data); | |||
| 1072 | ecb->flags |= ECB_SENSE0x04; | |||
| 1073 | ecb->timeout = NCR_SENSE_TIMEOUT1000; | |||
| 1074 | ti->senses++; | |||
| 1075 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 1076 | if (li->busy) li->busy = 0; | |||
| 1077 | ncr53c9x_dequeue(sc, ecb); | |||
| 1078 | li->untagged = ecb; | |||
| 1079 | li->busy = 2; | |||
| 1080 | if (ecb == sc->sc_nexus) { | |||
| 1081 | ncr53c9x_select(sc, ecb); | |||
| 1082 | } else { | |||
| 1083 | TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain)do { if (((ecb)->chain.tqe_next = (&sc->ready_list) ->tqh_first) != ((void *)0)) (&sc->ready_list)-> tqh_first->chain.tqe_prev = &(ecb)->chain.tqe_next; else (&sc->ready_list)->tqh_last = &(ecb)-> chain.tqe_next; (&sc->ready_list)->tqh_first = (ecb ); (ecb)->chain.tqe_prev = &(&sc->ready_list)-> tqh_first; } while (0); | |||
| 1084 | ecb->flags |= ECB_READY0x02; | |||
| 1085 | if (sc->sc_state == NCR_IDLE1) | |||
| 1086 | ncr53c9x_sched(sc); | |||
| 1087 | } | |||
| 1088 | } | |||
| 1089 | ||||
| 1090 | /* | |||
| 1091 | * POST PROCESSING OF SCSI_CMD (usually current) | |||
| 1092 | */ | |||
| 1093 | void | |||
| 1094 | ncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) | |||
| 1095 | { | |||
| 1096 | struct scsi_xfer *xs = ecb->xs; | |||
| 1097 | struct scsi_link *sc_link = xs->sc_link; | |||
| 1098 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target]; | |||
| 1099 | int lun = sc_link->lun; | |||
| 1100 | struct ncr53c9x_linfo *li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 1101 | ||||
| 1102 | NCR_TRACE(("[ncr53c9x_done(error:%x)] ", xs->error))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_done(error:%x)] " , xs->error);} while (0); | |||
| 1103 | ||||
| 1104 | timeout_del(&ecb->to); | |||
| 1105 | ||||
| 1106 | if (ecb->stat == SCSI_QUEUE_FULL0x28) { | |||
| 1107 | /* | |||
| 1108 | * Set current throttle -- we should reset | |||
| 1109 | * this periodically | |||
| 1110 | */ | |||
| 1111 | sc_link->openings = li->used - 1; | |||
| 1112 | printf("\n%s: QFULL -- throttling to %d commands\n", | |||
| 1113 | sc->sc_dev.dv_xname, sc_link->openings); | |||
| 1114 | } | |||
| 1115 | ||||
| 1116 | /* | |||
| 1117 | * Now, if we've come here with no error code, i.e. we've kept the | |||
| 1118 | * initial XS_NOERROR, and the status code signals that we should | |||
| 1119 | * check sense, we'll need to set up a request sense cmd block and | |||
| 1120 | * push the command back into the ready queue *before* any other | |||
| 1121 | * commands for this target/lunit, else we lose the sense info. | |||
| 1122 | * We don't support chk sense conditions for the request sense cmd. | |||
| 1123 | */ | |||
| 1124 | if (xs->error == XS_NOERROR0) { | |||
| 1125 | xs->status = ecb->stat; | |||
| 1126 | if ((ecb->flags & ECB_ABORT0x40) != 0) { | |||
| 1127 | xs->error = XS_TIMEOUT4; | |||
| 1128 | } else if ((ecb->flags & ECB_SENSE0x04) != 0) { | |||
| 1129 | xs->error = XS_SENSE1; | |||
| 1130 | } else if ((ecb->stat & ST_MASK0x3e) == SCSI_CHECK0x02) { | |||
| 1131 | /* First, save the return values */ | |||
| 1132 | xs->resid = ecb->dleft; | |||
| 1133 | ncr53c9x_sense(sc, ecb); | |||
| 1134 | return; | |||
| 1135 | } else { | |||
| 1136 | xs->resid = ecb->dleft; | |||
| 1137 | } | |||
| 1138 | } | |||
| 1139 | ||||
| 1140 | #ifdef NCR53C9X_DEBUG1 | |||
| 1141 | if (ncr53c9x_debug & NCR_SHOWMISC0x08) { | |||
| 1142 | if (xs->resid != 0) | |||
| 1143 | printf("resid=%lu ", (unsigned long)xs->resid); | |||
| 1144 | if (xs->error == XS_SENSE1) | |||
| 1145 | printf("sense=0x%02x\n", xs->sense.error_code); | |||
| 1146 | else | |||
| 1147 | printf("error=%d\n", xs->error); | |||
| 1148 | } | |||
| 1149 | #endif | |||
| 1150 | ||||
| 1151 | /* | |||
| 1152 | * Remove the ECB from whatever queue it's on. | |||
| 1153 | */ | |||
| 1154 | ncr53c9x_dequeue(sc, ecb); | |||
| 1155 | if (ecb == sc->sc_nexus) { | |||
| 1156 | sc->sc_nexus = NULL((void *)0); | |||
| 1157 | if (sc->sc_state != NCR_CLEANING8) { | |||
| 1158 | sc->sc_state = NCR_IDLE1; | |||
| 1159 | ncr53c9x_sched(sc); | |||
| 1160 | } | |||
| 1161 | } | |||
| 1162 | ||||
| 1163 | ti->cmds++; | |||
| 1164 | scsi_done(xs); | |||
| 1165 | } | |||
| 1166 | ||||
| 1167 | void | |||
| 1168 | ncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) | |||
| 1169 | { | |||
| 1170 | struct ncr53c9x_tinfo *ti = | |||
| 1171 | &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 1172 | struct ncr53c9x_linfo *li; | |||
| 1173 | int64_t lun = ecb->xs->sc_link->lun; | |||
| 1174 | ||||
| 1175 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 1176 | #ifdef DIAGNOSTIC1 | |||
| 1177 | if ((!li) || (li->lun != lun)) | |||
| 1178 | panic("ncr53c9x_dequeue: lun %llx for ecb %p does not exist", | |||
| 1179 | (long long)lun, ecb); | |||
| 1180 | #endif | |||
| 1181 | if (li->untagged == ecb) { | |||
| 1182 | li->busy = 0; | |||
| 1183 | li->untagged = NULL((void *)0); | |||
| 1184 | } | |||
| 1185 | if (ecb->tag[0] && li->queued[ecb->tag[1]]) { | |||
| 1186 | #ifdef DIAGNOSTIC1 | |||
| 1187 | if (li->queued[ecb->tag[1]] && (li->queued[ecb->tag[1]] != ecb)) | |||
| 1188 | panic("ncr53c9x_dequeue: slot %d for lun %llx has %p " | |||
| 1189 | "instead of ecb %p", ecb->tag[1], | |||
| 1190 | (long long)lun, | |||
| 1191 | li->queued[ecb->tag[1]], ecb); | |||
| 1192 | #endif | |||
| 1193 | li->queued[ecb->tag[1]] = NULL((void *)0); | |||
| 1194 | li->used --; | |||
| 1195 | ||||
| 1196 | } | |||
| 1197 | if (ecb->flags & ECB_READY0x02) { | |||
| 1198 | ecb->flags &= ~ECB_READY0x02; | |||
| 1199 | TAILQ_REMOVE(&sc->ready_list, ecb, chain)do { if (((ecb)->chain.tqe_next) != ((void *)0)) (ecb)-> chain.tqe_next->chain.tqe_prev = (ecb)->chain.tqe_prev; else (&sc->ready_list)->tqh_last = (ecb)->chain .tqe_prev; *(ecb)->chain.tqe_prev = (ecb)->chain.tqe_next ; ((ecb)->chain.tqe_prev) = ((void *)-1); ((ecb)->chain .tqe_next) = ((void *)-1); } while (0); | |||
| 1200 | } | |||
| 1201 | } | |||
| 1202 | ||||
| 1203 | /* | |||
| 1204 | * INTERRUPT/PROTOCOL ENGINE | |||
| 1205 | */ | |||
| 1206 | ||||
| 1207 | /* | |||
| 1208 | * Schedule an outgoing message by prioritizing it, and asserting | |||
| 1209 | * attention on the bus. We can only do this when we are the initiator | |||
| 1210 | * else there will be an illegal command interrupt. | |||
| 1211 | */ | |||
| 1212 | #define ncr53c9x_sched_msgout(m)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , m, 1212);} while (0); do { if (ncr53c9x_debug & 0x100) printf ("<cmd:0x%x %d>", (unsigned)0x1a, 1212); sc->sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), ( 0x1a)); } while (0); sc->sc_flags |= 0x40; sc->sc_msgpriq |= (m); } while (0) \ | |||
| 1213 | do { \ | |||
| 1214 | NCR_MISC(("ncr53c9x_sched_msgout %x %d ", m, __LINE__))do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , m, 1214);} while (0); \ | |||
| 1215 | NCRCMD(sc, NCRCMD_SETATN)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x1a, 1215); sc->sc_lastcmd = 0x1a; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); \ | |||
| 1216 | sc->sc_flags |= NCR_ATN0x40; \ | |||
| 1217 | sc->sc_msgpriq |= (m); \ | |||
| 1218 | } while (0) | |||
| 1219 | ||||
| 1220 | static void | |||
| 1221 | ncr53c9x_flushfifo(struct ncr53c9x_softc *sc) | |||
| 1222 | { | |||
| 1223 | NCR_MISC(("[flushfifo] "))do {if (ncr53c9x_debug & 0x08) printf ("[flushfifo] ");} while (0); | |||
| 1224 | ||||
| 1225 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 1225); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 1226 | ||||
| 1227 | if (sc->sc_phase == COMMAND_PHASE(0x02) || | |||
| 1228 | sc->sc_phase == MESSAGE_OUT_PHASE(0x04|0x02)) | |||
| 1229 | DELAY(2)(*delay_func)(2); | |||
| 1230 | } | |||
| 1231 | ||||
| 1232 | static int | |||
| 1233 | ncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how) | |||
| 1234 | { | |||
| 1235 | int i, n; | |||
| 1236 | u_char *buf; | |||
| 1237 | ||||
| 1238 | switch(how) { | |||
| 1239 | case NCR_RDFIFO_START0: | |||
| 1240 | buf = sc->sc_imess; | |||
| 1241 | sc->sc_imlen = 0; | |||
| 1242 | break; | |||
| 1243 | case NCR_RDFIFO_CONTINUE1: | |||
| 1244 | buf = sc->sc_imess + sc->sc_imlen; | |||
| 1245 | break; | |||
| 1246 | default: | |||
| 1247 | panic("ncr53c9x_rdfifo: bad flag"); | |||
| 1248 | break; | |||
| 1249 | } | |||
| 1250 | ||||
| 1251 | /* | |||
| 1252 | * XXX buffer (sc_imess) size for message | |||
| 1253 | */ | |||
| 1254 | ||||
| 1255 | n = NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f; | |||
| 1256 | ||||
| 1257 | if (sc->sc_rev == NCR_VARIANT_FAS3669) { | |||
| 1258 | n *= 2; | |||
| 1259 | ||||
| 1260 | for (i = 0; i < n; i++) | |||
| 1261 | buf[i] = NCR_READ_REG(sc, NCR_FIFO)(*(sc)->sc_glue->gl_read_reg)((sc), (0x02)); | |||
| 1262 | ||||
| 1263 | if (sc->sc_espstat2 & FAS_STAT2_ISHUTTLE0x20) { | |||
| 1264 | ||||
| 1265 | NCR_WRITE_REG(sc, NCR_FIFO, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0x02), (0)); | |||
| 1266 | buf[i++] = NCR_READ_REG(sc, NCR_FIFO)(*(sc)->sc_glue->gl_read_reg)((sc), (0x02)); | |||
| 1267 | ||||
| 1268 | NCR_READ_REG(sc, NCR_FIFO)(*(sc)->sc_glue->gl_read_reg)((sc), (0x02)); | |||
| 1269 | ||||
| 1270 | ncr53c9x_flushfifo(sc); | |||
| 1271 | } | |||
| 1272 | } else { | |||
| 1273 | for (i = 0; i < n; i++) | |||
| 1274 | buf[i] = NCR_READ_REG(sc, NCR_FIFO)(*(sc)->sc_glue->gl_read_reg)((sc), (0x02)); | |||
| 1275 | } | |||
| 1276 | ||||
| 1277 | sc->sc_imlen += i; | |||
| 1278 | ||||
| 1279 | #ifdef NCR53C9X_DEBUG1 | |||
| 1280 | { | |||
| 1281 | int j; | |||
| 1282 | ||||
| 1283 | NCR_TRACE(("\n[rdfifo %s (%d):",do {if (ncr53c9x_debug & 0x10) printf ("\n[rdfifo %s (%d):" , (how == 0) ? "start" : "cont", (int)sc->sc_imlen);} while (0) | |||
| 1284 | (how == NCR_RDFIFO_START) ? "start" : "cont",do {if (ncr53c9x_debug & 0x10) printf ("\n[rdfifo %s (%d):" , (how == 0) ? "start" : "cont", (int)sc->sc_imlen);} while (0) | |||
| 1285 | (int)sc->sc_imlen))do {if (ncr53c9x_debug & 0x10) printf ("\n[rdfifo %s (%d):" , (how == 0) ? "start" : "cont", (int)sc->sc_imlen);} while (0); | |||
| 1286 | if (ncr53c9x_debug & NCR_SHOWTRAC0x10) { | |||
| 1287 | for (j = 0; j < sc->sc_imlen; j++) | |||
| 1288 | printf(" %02x", sc->sc_imess[j]); | |||
| 1289 | printf("]\n"); | |||
| 1290 | } | |||
| 1291 | } | |||
| 1292 | #endif | |||
| 1293 | return sc->sc_imlen; | |||
| 1294 | } | |||
| 1295 | ||||
| 1296 | static void | |||
| 1297 | ncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len) | |||
| 1298 | { | |||
| 1299 | int i; | |||
| 1300 | ||||
| 1301 | #ifdef NCR53C9X_DEBUG1 | |||
| 1302 | NCR_MISC(("[wrfifo(%d):", len))do {if (ncr53c9x_debug & 0x08) printf ("[wrfifo(%d):", len );} while (0); | |||
| 1303 | if (ncr53c9x_debug & NCR_SHOWTRAC0x10) { | |||
| 1304 | for (i = 0; i < len; i++) | |||
| 1305 | printf(" %02x", p[i]); | |||
| 1306 | printf("]\n"); | |||
| 1307 | } | |||
| 1308 | #endif | |||
| 1309 | ||||
| 1310 | for (i = 0; i < len; i++) { | |||
| 1311 | NCR_WRITE_REG(sc, NCR_FIFO, p[i])(*(sc)->sc_glue->gl_write_reg)((sc), (0x02), (p[i])); | |||
| 1312 | ||||
| 1313 | if (sc->sc_rev == NCR_VARIANT_FAS3669) | |||
| 1314 | NCR_WRITE_REG(sc, NCR_FIFO, 0)(*(sc)->sc_glue->gl_write_reg)((sc), (0x02), (0)); | |||
| 1315 | } | |||
| 1316 | } | |||
| 1317 | ||||
| 1318 | int | |||
| 1319 | ncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype, | |||
| 1320 | int tagid) | |||
| 1321 | { | |||
| 1322 | u_char selid, target, lun; | |||
| 1323 | struct ncr53c9x_ecb *ecb = NULL((void *)0); | |||
| 1324 | struct ncr53c9x_tinfo *ti; | |||
| 1325 | struct ncr53c9x_linfo *li; | |||
| 1326 | ||||
| 1327 | if (sc->sc_rev == NCR_VARIANT_FAS3669) { | |||
| 1328 | target = sc->sc_selid; | |||
| 1329 | } else { | |||
| 1330 | /* | |||
| 1331 | * The SCSI chip made a snapshot of the data bus while the reselection | |||
| 1332 | * was being negotiated. This enables us to determine which target did | |||
| 1333 | * the reselect. | |||
| 1334 | */ | |||
| 1335 | selid = sc->sc_selid & ~(1 << sc->sc_id); | |||
| 1336 | if (selid & (selid - 1)) { | |||
| 1337 | printf("%s: reselect with invalid selid %02x;" | |||
| 1338 | " sending DEVICE RESET\n", sc->sc_dev.dv_xname, selid); | |||
| 1339 | goto reset; | |||
| 1340 | ||||
| 1341 | } | |||
| 1342 | target = ffs(selid) - 1; | |||
| 1343 | } | |||
| 1344 | lun = message & 0x07; | |||
| 1345 | ||||
| 1346 | /* | |||
| 1347 | * Search wait queue for disconnected cmd | |||
| 1348 | * The list should be short, so I haven't bothered with | |||
| 1349 | * any more sophisticated structures than a simple | |||
| 1350 | * singly linked list. | |||
| 1351 | */ | |||
| 1352 | ti = &sc->sc_tinfo[target]; | |||
| 1353 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 1354 | ||||
| 1355 | /* | |||
| 1356 | * We can get as far as the LUN with the IDENTIFY | |||
| 1357 | * message. Check to see if we're running an | |||
| 1358 | * un-tagged command. Otherwise ack the IDENTIFY | |||
| 1359 | * and wait for a tag message. | |||
| 1360 | */ | |||
| 1361 | if (li != NULL((void *)0)) { | |||
| 1362 | if (li->untagged != NULL((void *)0) && li->busy) | |||
| 1363 | ecb = li->untagged; | |||
| 1364 | else if (tagtype != MSG_SIMPLE_Q_TAG0x20) { | |||
| 1365 | /* Wait for tag to come by */ | |||
| 1366 | sc->sc_state = NCR_IDENTIFIED4; | |||
| 1367 | return (0); | |||
| 1368 | } else if (tagtype) ecb = li->queued[tagid]; | |||
| 1369 | } | |||
| 1370 | if (ecb == NULL((void *)0)) { | |||
| 1371 | printf("%s: reselect from target %d lun %d tag %x:%x with no nexus;" | |||
| 1372 | " sending ABORT\n", sc->sc_dev.dv_xname, target, lun, tagtype, tagid); | |||
| 1373 | goto abort; | |||
| 1374 | } | |||
| 1375 | ||||
| 1376 | /* Make this nexus active again. */ | |||
| 1377 | sc->sc_state = NCR_CONNECTED5; | |||
| 1378 | sc->sc_nexus = ecb; | |||
| 1379 | ncr53c9x_setsync(sc, ti); | |||
| 1380 | ||||
| 1381 | if (ecb->flags & ECB_RESET0x80) | |||
| 1382 | ncr53c9x_sched_msgout(SEND_DEV_RESET)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0001, 1382);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1382); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0001); } while (0); | |||
| 1383 | else if (ecb->flags & ECB_ABORT0x40) | |||
| 1384 | ncr53c9x_sched_msgout(SEND_ABORT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0020, 1384);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1384); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0020); } while (0); | |||
| 1385 | ||||
| 1386 | /* Do an implicit RESTORE POINTERS. */ | |||
| 1387 | sc->sc_dp = ecb->daddr; | |||
| 1388 | sc->sc_dleft = ecb->dleft; | |||
| 1389 | ||||
| 1390 | return (0); | |||
| 1391 | ||||
| 1392 | reset: | |||
| 1393 | ncr53c9x_sched_msgout(SEND_DEV_RESET)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0001, 1393);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1393); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0001); } while (0); | |||
| 1394 | return (1); | |||
| 1395 | ||||
| 1396 | abort: | |||
| 1397 | ncr53c9x_sched_msgout(SEND_ABORT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0020, 1397);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1397); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0020); } while (0); | |||
| 1398 | return (1); | |||
| 1399 | } | |||
| 1400 | ||||
| 1401 | static inline int | |||
| 1402 | __verify_msg_format(u_char *p, int len) | |||
| 1403 | { | |||
| 1404 | ||||
| 1405 | if (len == 1 && IS1BYTEMSG(p[0])(((p[0]) != 0x01 && (p[0]) < 0x20) || (p[0]) >= 0x80)) | |||
| 1406 | return 1; | |||
| 1407 | if (len == 2 && IS2BYTEMSG(p[0])(((p[0]) & 0xf0) == 0x20)) | |||
| 1408 | return 1; | |||
| 1409 | if (len >= 3 && ISEXTMSG(p[0])((p[0]) == 0x01) && | |||
| 1410 | len == p[1] + 2) | |||
| 1411 | return 1; | |||
| 1412 | ||||
| 1413 | return 0; | |||
| 1414 | } | |||
| 1415 | ||||
| 1416 | /* | |||
| 1417 | * Get an incoming message as initiator. | |||
| 1418 | * | |||
| 1419 | * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a | |||
| 1420 | * byte in the FIFO | |||
| 1421 | */ | |||
| 1422 | void | |||
| 1423 | ncr53c9x_msgin(struct ncr53c9x_softc *sc) | |||
| 1424 | { | |||
| 1425 | ||||
| 1426 | NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld)] ", (long)sc->sc_imlen))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_msgin(curmsglen:%ld)] " , (long)sc->sc_imlen);} while (0); | |||
| 1427 | ||||
| 1428 | if (sc->sc_imlen == 0) { | |||
| 1429 | printf("%s: msgin: no msg byte available\n", sc->sc_dev.dv_xname); | |||
| 1430 | return; | |||
| 1431 | } | |||
| 1432 | ||||
| 1433 | /* | |||
| 1434 | * Prepare for a new message. A message should (according | |||
| 1435 | * to the SCSI standard) be transmitted in one single | |||
| 1436 | * MESSAGE_IN_PHASE. If we have been in some other phase, | |||
| 1437 | * then this is a new message. | |||
| 1438 | */ | |||
| 1439 | if (sc->sc_prevphase != MESSAGE_IN_PHASE(0x04|0x02|0x01) && sc->sc_state != NCR_RESELECTED3) { | |||
| 1440 | printf("%s: phase change, dropping message, prev %d, state %d\n", | |||
| 1441 | sc->sc_dev.dv_xname, sc->sc_prevphase, sc->sc_state); | |||
| 1442 | sc->sc_flags &= ~NCR_DROP_MSGI0x01; | |||
| 1443 | sc->sc_imlen = 0; | |||
| 1444 | } | |||
| 1445 | ||||
| 1446 | NCR_TRACE(("<msgbyte:0x%02x>", sc->sc_imess[0]))do {if (ncr53c9x_debug & 0x10) printf ("<msgbyte:0x%02x>" , sc->sc_imess[0]);} while (0); | |||
| 1447 | ||||
| 1448 | /* | |||
| 1449 | * If we're going to reject the message, don't bother storing | |||
| 1450 | * the incoming bytes. But still, we need to ACK them. | |||
| 1451 | */ | |||
| 1452 | if ((sc->sc_flags & NCR_DROP_MSGI0x01)) { | |||
| 1453 | NCRCMD(sc, NCRCMD_MSGOK)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x12, 1453); sc->sc_lastcmd = 0x12; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x12)); } while (0); | |||
| 1454 | printf("<dropping msg byte %x>", | |||
| 1455 | sc->sc_imess[sc->sc_imlen]); | |||
| 1456 | return; | |||
| 1457 | } | |||
| 1458 | ||||
| 1459 | if (sc->sc_imlen >= NCR_MAX_MSG_LEN8) { | |||
| 1460 | ncr53c9x_sched_msgout(SEND_REJECT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0008, 1460);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1460); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0008); } while (0); | |||
| 1461 | sc->sc_flags |= NCR_DROP_MSGI0x01; | |||
| 1462 | } else { | |||
| 1463 | u_char *pb; | |||
| 1464 | int plen; | |||
| 1465 | ||||
| 1466 | switch (sc->sc_state) { | |||
| 1467 | /* | |||
| 1468 | * if received message is the first of reselection | |||
| 1469 | * then first byte is selid, and then message | |||
| 1470 | */ | |||
| 1471 | case NCR_RESELECTED3: | |||
| 1472 | pb = sc->sc_imess + 1; | |||
| 1473 | plen = sc->sc_imlen - 1; | |||
| 1474 | break; | |||
| 1475 | default: | |||
| 1476 | pb = sc->sc_imess; | |||
| 1477 | plen = sc->sc_imlen; | |||
| 1478 | break; | |||
| 1479 | } | |||
| 1480 | ||||
| 1481 | if (__verify_msg_format(pb, plen)) | |||
| 1482 | goto gotit; | |||
| 1483 | } | |||
| 1484 | ||||
| 1485 | /* Ack what we have so far */ | |||
| 1486 | NCRCMD(sc, NCRCMD_MSGOK)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x12, 1486); sc->sc_lastcmd = 0x12; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x12)); } while (0); | |||
| 1487 | return; | |||
| 1488 | ||||
| 1489 | gotit: | |||
| 1490 | NCR_MSGS(("gotmsg(%x) state %d", sc->sc_imess[0], sc->sc_state))do {if (ncr53c9x_debug & 0x200) printf ("gotmsg(%x) state %d" , sc->sc_imess[0], sc->sc_state);}while (0); | |||
| 1491 | /* we got complete message, flush the imess, XXX nobody uses imlen below */ | |||
| 1492 | sc->sc_imlen = 0; | |||
| 1493 | ||||
| 1494 | /* | |||
| 1495 | * Now we should have a complete message (1 byte, 2 byte | |||
| 1496 | * and moderately long extended messages). We only handle | |||
| 1497 | * extended messages which total length is shorter than | |||
| 1498 | * NCR_MAX_MSG_LEN. Longer messages will be amputated. | |||
| 1499 | */ | |||
| 1500 | switch (sc->sc_state) { | |||
| 1501 | struct ncr53c9x_ecb *ecb; | |||
| 1502 | struct ncr53c9x_tinfo *ti; | |||
| 1503 | struct ncr53c9x_linfo *li; | |||
| 1504 | int lun; | |||
| 1505 | ||||
| 1506 | case NCR_CONNECTED5: | |||
| 1507 | ecb = sc->sc_nexus; | |||
| 1508 | ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 1509 | ||||
| 1510 | switch (sc->sc_imess[0]) { | |||
| 1511 | case MSG_CMDCOMPLETE0x00: | |||
| 1512 | NCR_MSGS(("cmdcomplete "))do {if (ncr53c9x_debug & 0x200) printf ("cmdcomplete ");} while (0); | |||
| 1513 | if (sc->sc_dleft < 0) { | |||
| 1514 | sc_print_addr(ecb->xs->sc_link); | |||
| 1515 | printf("got %ld extra bytes\n", | |||
| 1516 | -(long)sc->sc_dleft); | |||
| 1517 | sc->sc_dleft = 0; | |||
| 1518 | } | |||
| 1519 | ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE0x100) | |||
| 1520 | ? 0 | |||
| 1521 | : sc->sc_dleft; | |||
| 1522 | if ((ecb->flags & ECB_SENSE0x04) == 0) | |||
| 1523 | ecb->xs->resid = ecb->dleft; | |||
| 1524 | sc->sc_state = NCR_CMDCOMPLETE7; | |||
| 1525 | break; | |||
| 1526 | ||||
| 1527 | case MSG_MESSAGE_REJECT0x07: | |||
| 1528 | NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout))do {if (ncr53c9x_debug & 0x200) printf ("msg reject (msgout=%x) " , sc->sc_msgout);}while (0); | |||
| 1529 | switch (sc->sc_msgout) { | |||
| 1530 | case SEND_TAG0x0100: | |||
| 1531 | /* Target does not like tagged queuing. | |||
| 1532 | * - Flush the command queue | |||
| 1533 | * - Disable tagged queuing for the target | |||
| 1534 | * - Dequeue ecb from the queued array. | |||
| 1535 | */ | |||
| 1536 | printf("%s: tagged queuing rejected: target %d\n", | |||
| 1537 | sc->sc_dev.dv_xname, ecb->xs->sc_link->target); | |||
| 1538 | ||||
| 1539 | NCR_MSGS(("(rejected sent tag)"))do {if (ncr53c9x_debug & 0x200) printf ("(rejected sent tag)" );}while (0); | |||
| 1540 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 1540); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 1541 | DELAY(1)(*delay_func)(1); | |||
| 1542 | ti->flags &= ~T_TAG0x40; | |||
| 1543 | lun = ecb->xs->sc_link->lun; | |||
| 1544 | li = TINFO_LUN(ti, lun)((((lun) < 8) && (((ti)->lun[(lun)]) != ((void * )0))) ? ((ti)->lun[(lun)]) : ncr53c9x_lunsearch((ti), (int64_t )(lun))); | |||
| 1545 | if (ecb->tag[0] && | |||
| 1546 | li->queued[ecb->tag[1]] != NULL((void *)0)) { | |||
| 1547 | li->queued[ecb->tag[1]] = NULL((void *)0); | |||
| 1548 | li->used--; | |||
| 1549 | } | |||
| 1550 | ecb->tag[0] = ecb->tag[1] = 0; | |||
| 1551 | li->untagged = ecb; | |||
| 1552 | li->busy = 1; | |||
| 1553 | break; | |||
| 1554 | ||||
| 1555 | case SEND_SDTR0x0080: | |||
| 1556 | printf("%s: sync transfer rejected: target %d\n", | |||
| 1557 | sc->sc_dev.dv_xname, ecb->xs->sc_link->target); | |||
| 1558 | sc->sc_flags &= ~NCR_SYNCHNEGO0x08; | |||
| 1559 | ti->flags &= ~(T_NEGOTIATE0x02 | T_SYNCMODE0x08); | |||
| 1560 | ncr53c9x_setsync(sc, ti); | |||
| 1561 | break; | |||
| 1562 | ||||
| 1563 | case SEND_WDTR0x0040: | |||
| 1564 | printf("%s: wide transfer rejected: target %d\n", | |||
| 1565 | sc->sc_dev.dv_xname, ecb->xs->sc_link->target); | |||
| 1566 | ti->flags &= ~T_WIDE0x80; | |||
| 1567 | ti->width = 0; | |||
| 1568 | break; | |||
| 1569 | ||||
| 1570 | case SEND_INIT_DET_ERR0x0004: | |||
| 1571 | goto abort; | |||
| 1572 | } | |||
| 1573 | break; | |||
| 1574 | ||||
| 1575 | case MSG_NOOP0x08: | |||
| 1576 | NCR_MSGS(("noop "))do {if (ncr53c9x_debug & 0x200) printf ("noop ");}while ( 0); | |||
| 1577 | break; | |||
| 1578 | ||||
| 1579 | case MSG_HEAD_OF_Q_TAG0x21: | |||
| 1580 | case MSG_SIMPLE_Q_TAG0x20: | |||
| 1581 | case MSG_ORDERED_Q_TAG0x22: | |||
| 1582 | NCR_MSGS(("TAG %x:%x", sc->sc_imess[0], sc->sc_imess[1]))do {if (ncr53c9x_debug & 0x200) printf ("TAG %x:%x", sc-> sc_imess[0], sc->sc_imess[1]);}while (0); | |||
| 1583 | break; | |||
| 1584 | ||||
| 1585 | case MSG_DISCONNECT0x04: | |||
| 1586 | NCR_MSGS(("disconnect "))do {if (ncr53c9x_debug & 0x200) printf ("disconnect ");}while (0); | |||
| 1587 | ti->dconns++; | |||
| 1588 | sc->sc_state = NCR_DISCONNECT6; | |||
| 1589 | ||||
| 1590 | /* | |||
| 1591 | * Mark the fact that all bytes have moved. The | |||
| 1592 | * target may not bother to do a SAVE POINTERS | |||
| 1593 | * at this stage. This flag will set the residual | |||
| 1594 | * count to zero on MSG COMPLETE. | |||
| 1595 | */ | |||
| 1596 | if (sc->sc_dleft == 0) | |||
| 1597 | ecb->flags |= ECB_TENTATIVE_DONE0x100; | |||
| 1598 | ||||
| 1599 | break; | |||
| 1600 | ||||
| 1601 | case MSG_SAVEDATAPOINTER0x02: | |||
| 1602 | NCR_MSGS(("save datapointer "))do {if (ncr53c9x_debug & 0x200) printf ("save datapointer " );}while (0); | |||
| 1603 | ecb->daddr = sc->sc_dp; | |||
| 1604 | ecb->dleft = sc->sc_dleft; | |||
| 1605 | break; | |||
| 1606 | ||||
| 1607 | case MSG_RESTOREPOINTERS0x03: | |||
| 1608 | NCR_MSGS(("restore datapointer "))do {if (ncr53c9x_debug & 0x200) printf ("restore datapointer " );}while (0); | |||
| 1609 | sc->sc_dp = ecb->daddr; | |||
| 1610 | sc->sc_dleft = ecb->dleft; | |||
| 1611 | break; | |||
| 1612 | ||||
| 1613 | case MSG_EXTENDED0x01: | |||
| 1614 | NCR_MSGS(("extended(%x) ", sc->sc_imess[2]))do {if (ncr53c9x_debug & 0x200) printf ("extended(%x) ", sc ->sc_imess[2]);}while (0); | |||
| 1615 | switch (sc->sc_imess[2]) { | |||
| 1616 | case MSG_EXT_SDTR0x01: | |||
| 1617 | NCR_MSGS(("SDTR period %d, offset %d ",do {if (ncr53c9x_debug & 0x200) printf ("SDTR period %d, offset %d " , sc->sc_imess[3], sc->sc_imess[4]);}while (0) | |||
| 1618 | sc->sc_imess[3], sc->sc_imess[4]))do {if (ncr53c9x_debug & 0x200) printf ("SDTR period %d, offset %d " , sc->sc_imess[3], sc->sc_imess[4]);}while (0); | |||
| 1619 | if (sc->sc_imess[1] != 3) | |||
| 1620 | goto reject; | |||
| 1621 | ti->period = sc->sc_imess[3]; | |||
| 1622 | ti->offset = sc->sc_imess[4]; | |||
| 1623 | ti->flags &= ~T_NEGOTIATE0x02; | |||
| 1624 | if (sc->sc_minsync == 0 || | |||
| 1625 | ti->offset == 0 || | |||
| 1626 | ti->period > 124) { | |||
| 1627 | #ifdef NCR53C9X_DEBUG1 | |||
| 1628 | sc_print_addr(ecb->xs->sc_link); | |||
| 1629 | printf("async mode\n"); | |||
| 1630 | #endif | |||
| 1631 | if ((sc->sc_flags&NCR_SYNCHNEGO0x08) | |||
| 1632 | == 0) { | |||
| 1633 | /* | |||
| 1634 | * target initiated negotiation | |||
| 1635 | */ | |||
| 1636 | ti->offset = 0; | |||
| 1637 | ti->flags &= ~T_SYNCMODE0x08; | |||
| 1638 | ncr53c9x_sched_msgout(do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0080, 1639);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1639); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0080); } while (0) | |||
| 1639 | SEND_SDTR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0080, 1639);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1639); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0080); } while (0); | |||
| 1640 | } else { | |||
| 1641 | /* we are async */ | |||
| 1642 | ti->flags &= ~T_SYNCMODE0x08; | |||
| 1643 | } | |||
| 1644 | } else { | |||
| 1645 | #ifdef NCR53C9X_DEBUG1 | |||
| 1646 | int r, s; | |||
| 1647 | #endif | |||
| 1648 | int p; | |||
| 1649 | ||||
| 1650 | p = ncr53c9x_stp2cpb(sc, ti->period); | |||
| 1651 | ti->period = ncr53c9x_cpb2stp(sc, p)((250 * (p)) / (sc)->sc_freq); | |||
| 1652 | #ifdef NCR53C9X_DEBUG1 | |||
| 1653 | sc_print_addr(ecb->xs->sc_link); | |||
| 1654 | r = 250/ti->period; | |||
| 1655 | s = (100*250)/ti->period - 100*r; | |||
| 1656 | printf("max sync rate %d.%02dMB/s\n", | |||
| 1657 | r, s); | |||
| 1658 | #endif | |||
| 1659 | if ((sc->sc_flags&NCR_SYNCHNEGO0x08) == 0) { | |||
| 1660 | /* | |||
| 1661 | * target initiated negotiation | |||
| 1662 | */ | |||
| 1663 | if (ti->period < | |||
| 1664 | sc->sc_minsync) | |||
| 1665 | ti->period = | |||
| 1666 | sc->sc_minsync; | |||
| 1667 | if (ti->offset > 15) | |||
| 1668 | ti->offset = 15; | |||
| 1669 | ti->flags &= ~T_SYNCMODE0x08; | |||
| 1670 | ncr53c9x_sched_msgout(do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0080, 1671);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1671); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0080); } while (0) | |||
| 1671 | SEND_SDTR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0080, 1671);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1671); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0080); } while (0); | |||
| 1672 | } else { | |||
| 1673 | /* we are sync */ | |||
| 1674 | ti->flags |= T_SYNCMODE0x08; | |||
| 1675 | } | |||
| 1676 | } | |||
| 1677 | sc->sc_flags &= ~NCR_SYNCHNEGO0x08; | |||
| 1678 | ncr53c9x_setsync(sc, ti); | |||
| 1679 | break; | |||
| 1680 | ||||
| 1681 | case MSG_EXT_WDTR0x03: | |||
| 1682 | printf("%s: wide mode %d\n", | |||
| 1683 | sc->sc_dev.dv_xname, sc->sc_imess[3]); | |||
| 1684 | if (sc->sc_imess[3] == 1) { | |||
| 1685 | ti->cfg3 |= NCRFASCFG3_EWIDE0x40; | |||
| 1686 | ncr53c9x_setsync(sc, ti); | |||
| 1687 | } else | |||
| 1688 | ti->width = 0; | |||
| 1689 | ti->flags &= ~T_WIDE0x80; | |||
| 1690 | break; | |||
| 1691 | default: | |||
| 1692 | sc_print_addr(ecb->xs->sc_link); | |||
| 1693 | printf("unrecognized MESSAGE EXTENDED;" | |||
| 1694 | " sending REJECT\n"); | |||
| 1695 | goto reject; | |||
| 1696 | } | |||
| 1697 | break; | |||
| 1698 | ||||
| 1699 | default: | |||
| 1700 | NCR_MSGS(("ident "))do {if (ncr53c9x_debug & 0x200) printf ("ident ");}while ( 0); | |||
| 1701 | sc_print_addr(ecb->xs->sc_link); | |||
| 1702 | printf("unrecognized MESSAGE; sending REJECT\n"); | |||
| 1703 | reject: | |||
| 1704 | ncr53c9x_sched_msgout(SEND_REJECT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0008, 1704);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1704); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0008); } while (0); | |||
| 1705 | break; | |||
| 1706 | } | |||
| 1707 | break; | |||
| 1708 | ||||
| 1709 | case NCR_IDENTIFIED4: | |||
| 1710 | /* | |||
| 1711 | * IDENTIFY message was received and queue tag is expected now | |||
| 1712 | */ | |||
| 1713 | if ((sc->sc_imess[0] != MSG_SIMPLE_Q_TAG0x20) || | |||
| 1714 | (sc->sc_msgify == 0)) { | |||
| 1715 | printf("%s: TAG reselect without IDENTIFY;" | |||
| 1716 | " MSG %x;" | |||
| 1717 | " sending DEVICE RESET\n", | |||
| 1718 | sc->sc_dev.dv_xname, | |||
| 1719 | sc->sc_imess[0]); | |||
| 1720 | goto reset; | |||
| 1721 | } | |||
| 1722 | (void) ncr53c9x_reselect(sc, sc->sc_msgify, | |||
| 1723 | sc->sc_imess[0], sc->sc_imess[1]); | |||
| 1724 | break; | |||
| 1725 | ||||
| 1726 | case NCR_RESELECTED3: | |||
| 1727 | if (MSG_ISIDENTIFY(sc->sc_imess[1])((sc->sc_imess[1]) & 0x80)) { | |||
| 1728 | sc->sc_msgify = sc->sc_imess[1]; | |||
| 1729 | } else { | |||
| 1730 | printf("%s: reselect without IDENTIFY;" | |||
| 1731 | " MSG %x;" | |||
| 1732 | " sending DEVICE RESET\n", | |||
| 1733 | sc->sc_dev.dv_xname, | |||
| 1734 | sc->sc_imess[1]); | |||
| 1735 | goto reset; | |||
| 1736 | } | |||
| 1737 | (void) ncr53c9x_reselect(sc, sc->sc_msgify, 0, 0); | |||
| 1738 | break; | |||
| 1739 | ||||
| 1740 | default: | |||
| 1741 | printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n", | |||
| 1742 | sc->sc_dev.dv_xname); | |||
| 1743 | reset: | |||
| 1744 | ncr53c9x_sched_msgout(SEND_DEV_RESET)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0001, 1744);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1744); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0001); } while (0); | |||
| 1745 | break; | |||
| 1746 | ||||
| 1747 | abort: | |||
| 1748 | ncr53c9x_sched_msgout(SEND_ABORT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0020, 1748);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1748); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0020); } while (0); | |||
| 1749 | break; | |||
| 1750 | } | |||
| 1751 | ||||
| 1752 | /* if we have more messages to send set ATN */ | |||
| 1753 | if (sc->sc_msgpriq) | |||
| 1754 | NCRCMD(sc, NCRCMD_SETATN)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x1a, 1754); sc->sc_lastcmd = 0x1a; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); | |||
| 1755 | ||||
| 1756 | /* Ack last message byte */ | |||
| 1757 | NCRCMD(sc, NCRCMD_MSGOK)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x12, 1757); sc->sc_lastcmd = 0x12; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x12)); } while (0); | |||
| 1758 | ||||
| 1759 | /* Done, reset message pointer. */ | |||
| 1760 | sc->sc_flags &= ~NCR_DROP_MSGI0x01; | |||
| 1761 | sc->sc_imlen = 0; | |||
| 1762 | } | |||
| 1763 | ||||
| 1764 | ||||
| 1765 | /* | |||
| 1766 | * Send the highest priority, scheduled message | |||
| 1767 | */ | |||
| 1768 | void | |||
| 1769 | ncr53c9x_msgout(struct ncr53c9x_softc *sc) | |||
| 1770 | { | |||
| 1771 | struct ncr53c9x_tinfo *ti; | |||
| 1772 | struct ncr53c9x_ecb *ecb; | |||
| 1773 | size_t size; | |||
| 1774 | ||||
| 1775 | NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]",do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_msgout(priq:%x, prevphase:%x)]" , sc->sc_msgpriq, sc->sc_prevphase);} while (0) | |||
| 1776 | sc->sc_msgpriq, sc->sc_prevphase))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_msgout(priq:%x, prevphase:%x)]" , sc->sc_msgpriq, sc->sc_prevphase);} while (0); | |||
| 1777 | ||||
| 1778 | /* | |||
| 1779 | * XXX - the NCR_ATN flag is not in sync with the actual ATN | |||
| 1780 | * condition on the SCSI bus. The 53c9x chip | |||
| 1781 | * automatically turns off ATN before sending the | |||
| 1782 | * message byte. (see also the comment below in the | |||
| 1783 | * default case when picking out a message to send) | |||
| 1784 | */ | |||
| 1785 | if (sc->sc_flags & NCR_ATN0x40) { | |||
| 1786 | if (sc->sc_prevphase != MESSAGE_OUT_PHASE(0x04|0x02)) { | |||
| 1787 | new: | |||
| 1788 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 1788); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 1789 | /* DELAY(1); */ | |||
| 1790 | sc->sc_msgoutq = 0; | |||
| 1791 | sc->sc_omlen = 0; | |||
| 1792 | } | |||
| 1793 | } else { | |||
| 1794 | if (sc->sc_prevphase == MESSAGE_OUT_PHASE(0x04|0x02)) { | |||
| 1795 | ncr53c9x_sched_msgout(sc->sc_msgoutq)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , sc->sc_msgoutq, 1795);} while (0); do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>", (unsigned)0x1a, 1795 ); sc->sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg )((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40 ; sc->sc_msgpriq |= (sc->sc_msgoutq); } while (0); | |||
| 1796 | goto new; | |||
| 1797 | } else { | |||
| 1798 | printf("%s at line %d: unexpected MESSAGE OUT phase\n", | |||
| 1799 | sc->sc_dev.dv_xname, __LINE__1799); | |||
| 1800 | } | |||
| 1801 | } | |||
| 1802 | ||||
| 1803 | if (sc->sc_omlen == 0) { | |||
| 1804 | /* Pick up highest priority message */ | |||
| 1805 | sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; | |||
| 1806 | sc->sc_msgoutq |= sc->sc_msgout; | |||
| 1807 | sc->sc_msgpriq &= ~sc->sc_msgout; | |||
| 1808 | sc->sc_omlen = 1; /* "Default" message len */ | |||
| 1809 | switch (sc->sc_msgout) { | |||
| 1810 | case SEND_SDTR0x0080: | |||
| 1811 | ecb = sc->sc_nexus; | |||
| 1812 | ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 1813 | sc->sc_omess[0] = MSG_EXTENDED0x01; | |||
| 1814 | sc->sc_omess[1] = 3; | |||
| 1815 | sc->sc_omess[2] = MSG_EXT_SDTR0x01; | |||
| 1816 | sc->sc_omess[3] = ti->period; | |||
| 1817 | sc->sc_omess[4] = ti->offset; | |||
| 1818 | sc->sc_omlen = 5; | |||
| 1819 | if ((sc->sc_flags & NCR_SYNCHNEGO0x08) == 0) { | |||
| 1820 | ti->flags |= T_SYNCMODE0x08; | |||
| 1821 | ncr53c9x_setsync(sc, ti); | |||
| 1822 | } | |||
| 1823 | break; | |||
| 1824 | case SEND_WDTR0x0040: | |||
| 1825 | ecb = sc->sc_nexus; | |||
| 1826 | ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 1827 | sc->sc_omess[0] = MSG_EXTENDED0x01; | |||
| 1828 | sc->sc_omess[1] = 2; | |||
| 1829 | sc->sc_omess[2] = MSG_EXT_WDTR0x03; | |||
| 1830 | sc->sc_omess[3] = ti->width; | |||
| 1831 | sc->sc_omlen = 4; | |||
| 1832 | break; | |||
| 1833 | case SEND_IDENTIFY0x0010: | |||
| 1834 | if (sc->sc_state != NCR_CONNECTED5) { | |||
| 1835 | printf("%s at line %d: no nexus\n", | |||
| 1836 | sc->sc_dev.dv_xname, __LINE__1836); | |||
| 1837 | } | |||
| 1838 | ecb = sc->sc_nexus; | |||
| 1839 | sc->sc_omess[0] = | |||
| 1840 | MSG_IDENTIFY(ecb->xs->sc_link->lun, 0)(((0) ? 0xc0 : 0x80) | (ecb->xs->sc_link->lun)); | |||
| 1841 | break; | |||
| 1842 | case SEND_TAG0x0100: | |||
| 1843 | if (sc->sc_state != NCR_CONNECTED5) { | |||
| 1844 | printf("%s at line %d: no nexus\n", | |||
| 1845 | sc->sc_dev.dv_xname, __LINE__1845); | |||
| 1846 | } | |||
| 1847 | ecb = sc->sc_nexus; | |||
| 1848 | sc->sc_omess[0] = ecb->tag[0]; | |||
| 1849 | sc->sc_omess[1] = ecb->tag[1]; | |||
| 1850 | sc->sc_omlen = 2; | |||
| 1851 | break; | |||
| 1852 | case SEND_DEV_RESET0x0001: | |||
| 1853 | sc->sc_flags |= NCR_ABORTING0x02; | |||
| 1854 | sc->sc_omess[0] = MSG_BUS_DEV_RESET0x0c; | |||
| 1855 | ecb = sc->sc_nexus; | |||
| 1856 | ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 1857 | ti->flags &= ~T_SYNCMODE0x08; | |||
| 1858 | if ((ti->flags & T_SYNCHOFF0x10) == 0) | |||
| 1859 | /* We can re-start sync negotiation */ | |||
| 1860 | ti->flags |= T_NEGOTIATE0x02; | |||
| 1861 | break; | |||
| 1862 | case SEND_PARITY_ERROR0x0002: | |||
| 1863 | sc->sc_omess[0] = MSG_PARITY_ERROR0x09; | |||
| 1864 | break; | |||
| 1865 | case SEND_ABORT0x0020: | |||
| 1866 | sc->sc_flags |= NCR_ABORTING0x02; | |||
| 1867 | sc->sc_omess[0] = MSG_ABORT0x06; | |||
| 1868 | break; | |||
| 1869 | case SEND_INIT_DET_ERR0x0004: | |||
| 1870 | sc->sc_omess[0] = MSG_INITIATOR_DET_ERR0x05; | |||
| 1871 | break; | |||
| 1872 | case SEND_REJECT0x0008: | |||
| 1873 | sc->sc_omess[0] = MSG_MESSAGE_REJECT0x07; | |||
| 1874 | break; | |||
| 1875 | default: | |||
| 1876 | /* | |||
| 1877 | * We normally do not get here, since the chip | |||
| 1878 | * automatically turns off ATN before the last | |||
| 1879 | * byte of a message is sent to the target. | |||
| 1880 | * However, if the target rejects our (multi-byte) | |||
| 1881 | * message early by switching to MSG IN phase | |||
| 1882 | * ATN remains on, so the target may return to | |||
| 1883 | * MSG OUT phase. If there are no scheduled messages | |||
| 1884 | * left we send a NO-OP. | |||
| 1885 | * | |||
| 1886 | * XXX - Note that this leaves no useful purpose for | |||
| 1887 | * the NCR_ATN flag. | |||
| 1888 | */ | |||
| 1889 | sc->sc_flags &= ~NCR_ATN0x40; | |||
| 1890 | sc->sc_omess[0] = MSG_NOOP0x08; | |||
| 1891 | break; | |||
| 1892 | } | |||
| 1893 | sc->sc_omp = sc->sc_omess; | |||
| 1894 | } | |||
| 1895 | ||||
| 1896 | #ifdef DEBUG | |||
| 1897 | { | |||
| 1898 | int i; | |||
| 1899 | ||||
| 1900 | for (i = 0; i<sc->sc_omlen; i++) | |||
| 1901 | NCR_MISC(("<msgbyte:0x%02x>", sc->sc_omess[i]))do {if (ncr53c9x_debug & 0x08) printf ("<msgbyte:0x%02x>" , sc->sc_omess[i]);} while (0); | |||
| 1902 | } | |||
| 1903 | #endif | |||
| 1904 | if (sc->sc_rev == NCR_VARIANT_FAS3669) { | |||
| 1905 | /* | |||
| 1906 | * XXX fifo size | |||
| 1907 | */ | |||
| 1908 | ncr53c9x_flushfifo(sc); | |||
| 1909 | ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen); | |||
| 1910 | sc->sc_cmdlen = 0; | |||
| 1911 | NCRCMD(sc, NCRCMD_TRANS)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x10, 1911); sc->sc_lastcmd = 0x10; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x10)); } while (0); | |||
| 1912 | } else { | |||
| 1913 | /* (re)send the message */ | |||
| 1914 | size = min(sc->sc_omlen, sc->sc_maxxfer); | |||
| 1915 | NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_omp ), (&sc->sc_omlen), (0), (&size)); | |||
| 1916 | /* Program the SCSI counter */ | |||
| 1917 | NCR_SET_COUNT(sc, size)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (size))); (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x01 ), ((size) >> 8)); if ((sc->sc_cfg2 & 0x40) || ( sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg) (((sc)), (0x0e), ((size) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0)); } } while (0); | |||
| 1918 | ||||
| 1919 | /* Load the count in and start the message-out transfer */ | |||
| 1920 | NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00|0x80, 1920); sc->sc_lastcmd = 0x00|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x00|0x80) ); } while (0); | |||
| 1921 | NCRCMD(sc, NCRCMD_TRANS|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x10|0x80, 1921); sc->sc_lastcmd = 0x10|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x10|0x80) ); } while (0); | |||
| 1922 | NCRDMA_GO(sc)(*(sc)->sc_glue->gl_dma_go)((sc)); | |||
| 1923 | } | |||
| 1924 | } | |||
| 1925 | ||||
| 1926 | /* | |||
| 1927 | * This is the most critical part of the driver, and has to know | |||
| 1928 | * how to deal with *all* error conditions and phases from the SCSI | |||
| 1929 | * bus. If there are no errors and the DMA was active, then call the | |||
| 1930 | * DMA pseudo-interrupt handler. If this returns 1, then that was it | |||
| 1931 | * and we can return from here without further processing. | |||
| 1932 | * | |||
| 1933 | * Most of this needs verifying. | |||
| 1934 | */ | |||
| 1935 | int sdebug = 0; | |||
| 1936 | int | |||
| 1937 | ncr53c9x_intr(void *arg) | |||
| 1938 | { | |||
| 1939 | struct ncr53c9x_softc *sc = arg; | |||
| 1940 | struct ncr53c9x_ecb *ecb; | |||
| 1941 | struct scsi_link *sc_link; | |||
| 1942 | struct ncr53c9x_tinfo *ti; | |||
| 1943 | size_t size; | |||
| 1944 | int nfifo; | |||
| 1945 | ||||
| 1946 | NCR_TRACE(("[ncr53c9x_intr: state %d] ", sc->sc_state))do {if (ncr53c9x_debug & 0x10) printf ("[ncr53c9x_intr: state %d] " , sc->sc_state);} while (0); | |||
| ||||
| 1947 | ||||
| 1948 | if (!NCRDMA_ISINTR(sc)(*(sc)->sc_glue->gl_dma_isintr)((sc))) | |||
| 1949 | return (0); | |||
| 1950 | ||||
| 1951 | again: | |||
| 1952 | /* and what do the registers say... */ | |||
| 1953 | ncr53c9x_readregs(sc); | |||
| 1954 | ||||
| 1955 | /* | |||
| 1956 | * At the moment, only a SCSI Bus Reset or Illegal | |||
| 1957 | * Command are classed as errors. A disconnect is a | |||
| 1958 | * valid condition, and we let the code check is the | |||
| 1959 | * "NCR_BUSFREE_OK" flag was set before declaring it | |||
| 1960 | * and error. | |||
| 1961 | * | |||
| 1962 | * Also, the status register tells us about "Gross | |||
| 1963 | * Errors" and "Parity errors". Only the Gross Error | |||
| 1964 | * is really bad, and the parity errors are dealt | |||
| 1965 | * with later | |||
| 1966 | * | |||
| 1967 | * TODO | |||
| 1968 | * If there are too many parity error, go to slow | |||
| 1969 | * cable mode ? | |||
| 1970 | */ | |||
| 1971 | ||||
| 1972 | /* SCSI Reset */ | |||
| 1973 | if (sc->sc_espintr & NCRINTR_SBR0x80) { | |||
| 1974 | if (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f) { | |||
| 1975 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 1975); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 1976 | DELAY(1)(*delay_func)(1); | |||
| 1977 | } | |||
| 1978 | if (sc->sc_state != NCR_SBR9) { | |||
| 1979 | printf("%s: SCSI bus reset\n", | |||
| 1980 | sc->sc_dev.dv_xname); | |||
| 1981 | ncr53c9x_init(sc, 0); /* Restart everything */ | |||
| 1982 | return (1); | |||
| 1983 | } | |||
| 1984 | #if 0 | |||
| 1985 | /*XXX*/ printf("<expected bus reset: " | |||
| 1986 | "[intr %x, stat %x, step %d]>\n", | |||
| 1987 | sc->sc_espintr, sc->sc_espstat, | |||
| 1988 | sc->sc_espstep); | |||
| 1989 | #endif | |||
| 1990 | if (sc->sc_nexus) | |||
| 1991 | panic("%s: nexus in reset state", | |||
| 1992 | sc->sc_dev.dv_xname); | |||
| 1993 | goto sched; | |||
| 1994 | } | |||
| 1995 | ||||
| 1996 | ecb = sc->sc_nexus; | |||
| 1997 | ||||
| 1998 | #define NCRINTR_ERR(0x80|0x40) (NCRINTR_SBR0x80|NCRINTR_ILL0x40) | |||
| 1999 | if (sc->sc_espintr & NCRINTR_ERR(0x80|0x40) || | |||
| 2000 | sc->sc_espstat & NCRSTAT_GE0x40) { | |||
| 2001 | ||||
| 2002 | if (sc->sc_espstat & NCRSTAT_GE0x40) { | |||
| 2003 | /* Gross Error; no target ? */ | |||
| 2004 | if (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f) { | |||
| 2005 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2005); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2006 | DELAY(1)(*delay_func)(1); | |||
| 2007 | } | |||
| 2008 | if (sc->sc_state == NCR_CONNECTED5 || | |||
| 2009 | sc->sc_state == NCR_SELECTING2) { | |||
| 2010 | ecb->xs->error = XS_TIMEOUT4; | |||
| 2011 | ncr53c9x_done(sc, ecb); | |||
| 2012 | } | |||
| 2013 | return (1); | |||
| 2014 | } | |||
| 2015 | ||||
| 2016 | if (sc->sc_espintr & NCRINTR_ILL0x40) { | |||
| 2017 | if (sc->sc_flags & NCR_EXPECT_ILLCMD0x80) { | |||
| 2018 | /* | |||
| 2019 | * Eat away "Illegal command" interrupt | |||
| 2020 | * on a ESP100 caused by a re-selection | |||
| 2021 | * while we were trying to select | |||
| 2022 | * another target. | |||
| 2023 | */ | |||
| 2024 | #ifdef DEBUG | |||
| 2025 | printf("%s: ESP100 work-around activated\n", | |||
| 2026 | sc->sc_dev.dv_xname); | |||
| 2027 | #endif | |||
| 2028 | sc->sc_flags &= ~NCR_EXPECT_ILLCMD0x80; | |||
| 2029 | return (1); | |||
| 2030 | } | |||
| 2031 | /* illegal command, out of sync ? */ | |||
| 2032 | printf("%s: illegal command: 0x%x " | |||
| 2033 | "(state %d, phase %x, prevphase %x)\n", | |||
| 2034 | sc->sc_dev.dv_xname, sc->sc_lastcmd, | |||
| 2035 | sc->sc_state, sc->sc_phase, | |||
| 2036 | sc->sc_prevphase); | |||
| 2037 | if (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f) { | |||
| 2038 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2038); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2039 | DELAY(1)(*delay_func)(1); | |||
| 2040 | } | |||
| 2041 | ncr53c9x_init(sc, 1); /* Restart everything */ | |||
| 2042 | return (1); | |||
| 2043 | } | |||
| 2044 | } | |||
| 2045 | sc->sc_flags &= ~NCR_EXPECT_ILLCMD0x80; | |||
| 2046 | ||||
| 2047 | /* | |||
| 2048 | * Call if DMA is active. | |||
| 2049 | * | |||
| 2050 | * If DMA_INTR returns true, then maybe go 'round the loop | |||
| 2051 | * again in case there is no more DMA queued, but a phase | |||
| 2052 | * change is expected. | |||
| 2053 | */ | |||
| 2054 | if (NCRDMA_ISACTIVE(sc)(*(sc)->sc_glue->gl_dma_isactive)((sc))) { | |||
| 2055 | int r = NCRDMA_INTR(sc)(*(sc)->sc_glue->gl_dma_intr)((sc)); | |||
| 2056 | if (r == -1) { | |||
| 2057 | printf("%s: DMA error; resetting\n", | |||
| 2058 | sc->sc_dev.dv_xname); | |||
| 2059 | ncr53c9x_init(sc, 1); | |||
| 2060 | return (1); | |||
| 2061 | } | |||
| 2062 | /* If DMA active here, then go back to work... */ | |||
| 2063 | if (NCRDMA_ISACTIVE(sc)(*(sc)->sc_glue->gl_dma_isactive)((sc))) | |||
| 2064 | return (1); | |||
| 2065 | ||||
| 2066 | if ((sc->sc_espstat & NCRSTAT_TC0x10) == 0) { | |||
| 2067 | /* | |||
| 2068 | * DMA not completed. If we can not find a | |||
| 2069 | * acceptable explanation, print a diagnostic. | |||
| 2070 | */ | |||
| 2071 | if (sc->sc_state == NCR_SELECTING2) | |||
| 2072 | /* | |||
| 2073 | * This can happen if we are reselected | |||
| 2074 | * while using DMA to select a target. | |||
| 2075 | */ | |||
| 2076 | /*void*/; | |||
| 2077 | else if (sc->sc_prevphase == MESSAGE_OUT_PHASE(0x04|0x02)){ | |||
| 2078 | /* | |||
| 2079 | * Our (multi-byte) message (eg SDTR) | |||
| 2080 | * was interrupted by the target to | |||
| 2081 | * send a MSG REJECT. | |||
| 2082 | * Print diagnostic if current phase | |||
| 2083 | * is not MESSAGE IN. | |||
| 2084 | */ | |||
| 2085 | if (sc->sc_phase != MESSAGE_IN_PHASE(0x04|0x02|0x01)) | |||
| 2086 | printf("%s: !TC on MSG OUT" | |||
| 2087 | " [intr %x, stat %x, step %d]" | |||
| 2088 | " prevphase %x, resid %lx\n", | |||
| 2089 | sc->sc_dev.dv_xname, | |||
| 2090 | sc->sc_espintr, | |||
| 2091 | sc->sc_espstat, | |||
| 2092 | sc->sc_espstep, | |||
| 2093 | sc->sc_prevphase, | |||
| 2094 | (u_long)sc->sc_omlen); | |||
| 2095 | } else if (sc->sc_dleft == 0) { | |||
| 2096 | /* | |||
| 2097 | * The DMA operation was started for | |||
| 2098 | * a DATA transfer. Print a diagnostic | |||
| 2099 | * if the DMA counter and TC bit | |||
| 2100 | * appear to be out of sync. | |||
| 2101 | */ | |||
| 2102 | printf("%s: !TC on DATA XFER" | |||
| 2103 | " [intr %x, stat %x, step %d]" | |||
| 2104 | " prevphase %x, resid %x\n", | |||
| 2105 | sc->sc_dev.dv_xname, | |||
| 2106 | sc->sc_espintr, | |||
| 2107 | sc->sc_espstat, | |||
| 2108 | sc->sc_espstep, | |||
| 2109 | sc->sc_prevphase, | |||
| 2110 | ecb?ecb->dleft:-1); | |||
| 2111 | } | |||
| 2112 | } | |||
| 2113 | } | |||
| 2114 | ||||
| 2115 | /* | |||
| 2116 | * check for less serious errors | |||
| 2117 | */ | |||
| 2118 | if (sc->sc_espstat & NCRSTAT_PE0x20) { | |||
| 2119 | printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname); | |||
| 2120 | if (sc->sc_prevphase == MESSAGE_IN_PHASE(0x04|0x02|0x01)) | |||
| 2121 | ncr53c9x_sched_msgout(SEND_PARITY_ERROR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0002, 2121);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2121); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0002); } while (0); | |||
| 2122 | else | |||
| 2123 | ncr53c9x_sched_msgout(SEND_INIT_DET_ERR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0004, 2123);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2123); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0004); } while (0); | |||
| 2124 | } | |||
| 2125 | ||||
| 2126 | if (sc->sc_espintr & NCRINTR_DIS0x20) { | |||
| 2127 | sc->sc_msgify = 0; | |||
| 2128 | NCR_MISC(("<DISC [intr %x, stat %x, step %d]>",do {if (ncr53c9x_debug & 0x08) printf ("<DISC [intr %x, stat %x, step %d]>" , sc->sc_espintr,sc->sc_espstat,sc->sc_espstep);} while (0) | |||
| 2129 | sc->sc_espintr,sc->sc_espstat,sc->sc_espstep))do {if (ncr53c9x_debug & 0x08) printf ("<DISC [intr %x, stat %x, step %d]>" , sc->sc_espintr,sc->sc_espstat,sc->sc_espstep);} while (0); | |||
| 2130 | if (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f) { | |||
| 2131 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2131); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2132 | /* DELAY(1); */ | |||
| 2133 | } | |||
| 2134 | /* | |||
| 2135 | * This command must (apparently) be issued within | |||
| 2136 | * 250mS of a disconnect. So here you are... | |||
| 2137 | */ | |||
| 2138 | NCRCMD(sc, NCRCMD_ENSEL)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x44, 2138); sc->sc_lastcmd = 0x44; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x44)); } while (0); | |||
| 2139 | ||||
| 2140 | switch (sc->sc_state) { | |||
| 2141 | case NCR_RESELECTED3: | |||
| 2142 | goto sched; | |||
| 2143 | ||||
| 2144 | case NCR_SELECTING2: | |||
| 2145 | ecb->xs->error = XS_SELTIMEOUT3; | |||
| ||||
| 2146 | goto finish; | |||
| 2147 | ||||
| 2148 | case NCR_CONNECTED5: | |||
| 2149 | if ((sc->sc_flags & NCR_SYNCHNEGO0x08)) { | |||
| 2150 | #ifdef NCR53C9X_DEBUG1 | |||
| 2151 | if (ecb) | |||
| 2152 | sc_print_addr(ecb->xs->sc_link); | |||
| 2153 | printf("sync nego not completed!\n"); | |||
| 2154 | #endif | |||
| 2155 | ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; | |||
| 2156 | sc->sc_flags &= ~NCR_SYNCHNEGO0x08; | |||
| 2157 | ti->flags &= ~(T_NEGOTIATE0x02 | T_SYNCMODE0x08); | |||
| 2158 | } | |||
| 2159 | ||||
| 2160 | /* it may be OK to disconnect */ | |||
| 2161 | if ((sc->sc_flags & NCR_ABORTING0x02) == 0) { | |||
| 2162 | /* | |||
| 2163 | * Section 5.1.1 of the SCSI 2 spec | |||
| 2164 | * suggests issuing a REQUEST SENSE | |||
| 2165 | * following an unexpected disconnect. | |||
| 2166 | * Some devices go into a contingent | |||
| 2167 | * allegiance condition when | |||
| 2168 | * disconnecting, and this is necessary | |||
| 2169 | * to clean up their state. | |||
| 2170 | */ | |||
| 2171 | printf("%s: unexpected disconnect; ", | |||
| 2172 | sc->sc_dev.dv_xname); | |||
| 2173 | if (ecb->flags & ECB_SENSE0x04) { | |||
| 2174 | printf("resetting\n"); | |||
| 2175 | goto reset; | |||
| 2176 | } | |||
| 2177 | printf("sending REQUEST SENSE\n"); | |||
| 2178 | timeout_del(&ecb->to); | |||
| 2179 | ncr53c9x_sense(sc, ecb); | |||
| 2180 | goto out; | |||
| 2181 | } | |||
| 2182 | ||||
| 2183 | ecb->xs->error = XS_TIMEOUT4; | |||
| 2184 | goto finish; | |||
| 2185 | ||||
| 2186 | case NCR_DISCONNECT6: | |||
| 2187 | sc->sc_nexus = NULL((void *)0); | |||
| 2188 | goto sched; | |||
| 2189 | ||||
| 2190 | case NCR_CMDCOMPLETE7: | |||
| 2191 | goto finish; | |||
| 2192 | } | |||
| 2193 | } | |||
| 2194 | ||||
| 2195 | switch (sc->sc_state) { | |||
| 2196 | ||||
| 2197 | case NCR_SBR9: | |||
| 2198 | printf("%s: waiting for SCSI Bus Reset to happen\n", | |||
| 2199 | sc->sc_dev.dv_xname); | |||
| 2200 | return (1); | |||
| 2201 | ||||
| 2202 | case NCR_RESELECTED3: | |||
| 2203 | /* | |||
| 2204 | * we must be continuing a message ? | |||
| 2205 | */ | |||
| 2206 | if (sc->sc_phase != MESSAGE_IN_PHASE(0x04|0x02|0x01)) { | |||
| 2207 | printf("%s: target didn't identify\n", | |||
| 2208 | sc->sc_dev.dv_xname); | |||
| 2209 | ncr53c9x_init(sc, 1); | |||
| 2210 | return (1); | |||
| 2211 | } | |||
| 2212 | printf("<<RESELECT CONT'd>>"); | |||
| 2213 | #if XXXX | |||
| 2214 | ncr53c9x_msgin(sc); | |||
| 2215 | if (sc->sc_state != NCR_CONNECTED5) { | |||
| 2216 | /* IDENTIFY fail?! */ | |||
| 2217 | printf("%s: identify failed\n", | |||
| 2218 | sc->sc_dev.dv_xname); | |||
| 2219 | ncr53c9x_init(sc, 1); | |||
| 2220 | return (1); | |||
| 2221 | } | |||
| 2222 | #endif | |||
| 2223 | break; | |||
| 2224 | ||||
| 2225 | case NCR_IDENTIFIED4: | |||
| 2226 | ecb = sc->sc_nexus; | |||
| 2227 | if (sc->sc_phase != MESSAGE_IN_PHASE(0x04|0x02|0x01)) { | |||
| 2228 | int i = (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) | |||
| 2229 | & NCRFIFO_FF0x1f); | |||
| 2230 | /* | |||
| 2231 | * Things are seriously fucked up. | |||
| 2232 | * Pull the brakes, i.e. reset | |||
| 2233 | */ | |||
| 2234 | printf("%s: target didn't send tag: %d bytes in fifo\n", | |||
| 2235 | sc->sc_dev.dv_xname, i); | |||
| 2236 | /* Drain and display fifo */ | |||
| 2237 | while (i-- > 0) | |||
| 2238 | printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO)(*(sc)->sc_glue->gl_read_reg)((sc), (0x02))); | |||
| 2239 | ncr53c9x_init(sc, 1); | |||
| 2240 | return (1); | |||
| 2241 | } else | |||
| 2242 | goto msgin; | |||
| 2243 | ||||
| 2244 | break; | |||
| 2245 | case NCR_IDLE1: | |||
| 2246 | case NCR_SELECTING2: | |||
| 2247 | ecb = sc->sc_nexus; | |||
| 2248 | if (sc->sc_espintr & NCRINTR_RESEL0x04) { | |||
| 2249 | sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0; | |||
| 2250 | sc->sc_flags = 0; | |||
| 2251 | /* | |||
| 2252 | * If we're trying to select a | |||
| 2253 | * target ourselves, push our command | |||
| 2254 | * back into the ready list. | |||
| 2255 | */ | |||
| 2256 | if (sc->sc_state == NCR_SELECTING2) { | |||
| 2257 | NCR_MISC(("backoff selector "))do {if (ncr53c9x_debug & 0x08) printf ("backoff selector " );} while (0); | |||
| 2258 | timeout_del(&ecb->to); | |||
| 2259 | ncr53c9x_dequeue(sc, ecb); | |||
| 2260 | TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain)do { if (((ecb)->chain.tqe_next = (&sc->ready_list) ->tqh_first) != ((void *)0)) (&sc->ready_list)-> tqh_first->chain.tqe_prev = &(ecb)->chain.tqe_next; else (&sc->ready_list)->tqh_last = &(ecb)-> chain.tqe_next; (&sc->ready_list)->tqh_first = (ecb ); (ecb)->chain.tqe_prev = &(&sc->ready_list)-> tqh_first; } while (0); | |||
| 2261 | ecb->flags |= ECB_READY0x02; | |||
| 2262 | ecb = sc->sc_nexus = NULL((void *)0); | |||
| 2263 | } | |||
| 2264 | sc->sc_state = NCR_RESELECTED3; | |||
| 2265 | if (sc->sc_phase != MESSAGE_IN_PHASE(0x04|0x02|0x01)) { | |||
| 2266 | /* | |||
| 2267 | * Things are seriously fucked up. | |||
| 2268 | * Pull the brakes, i.e. reset | |||
| 2269 | */ | |||
| 2270 | printf("%s: target didn't identify\n", | |||
| 2271 | sc->sc_dev.dv_xname); | |||
| 2272 | ncr53c9x_init(sc, 1); | |||
| 2273 | return (1); | |||
| 2274 | } | |||
| 2275 | /* | |||
| 2276 | * The C90 only inhibits FIFO writes until | |||
| 2277 | * reselection is complete, instead of | |||
| 2278 | * waiting until the interrupt status register | |||
| 2279 | * has been read. So, if the reselect happens | |||
| 2280 | * while we were entering a command bytes (for | |||
| 2281 | * another target) some of those bytes can | |||
| 2282 | * appear in the FIFO here, after the | |||
| 2283 | * interrupt is taken. | |||
| 2284 | */ | |||
| 2285 | nfifo = ncr53c9x_rdfifo(sc, NCR_RDFIFO_START0); | |||
| 2286 | ||||
| 2287 | if (nfifo < 2 || | |||
| 2288 | (nfifo > 2 && | |||
| 2289 | sc->sc_rev != NCR_VARIANT_ESP1000)) { | |||
| 2290 | printf("%s: RESELECT: " | |||
| 2291 | "%d bytes in FIFO! " | |||
| 2292 | "[intr %x, stat %x, step %d, prevphase %x]\n", | |||
| 2293 | sc->sc_dev.dv_xname, | |||
| 2294 | nfifo, | |||
| 2295 | sc->sc_espintr, | |||
| 2296 | sc->sc_espstat, | |||
| 2297 | sc->sc_espstep, | |||
| 2298 | sc->sc_prevphase); | |||
| 2299 | ncr53c9x_init(sc, 1); | |||
| 2300 | return (1); | |||
| 2301 | } | |||
| 2302 | sc->sc_selid = sc->sc_imess[0]; | |||
| 2303 | NCR_MISC(("selid=%2x ", sc->sc_selid))do {if (ncr53c9x_debug & 0x08) printf ("selid=%2x ", sc-> sc_selid);} while (0); | |||
| 2304 | ||||
| 2305 | /* Handle identify message */ | |||
| 2306 | ncr53c9x_msgin(sc); | |||
| 2307 | if (nfifo != 2) { | |||
| 2308 | /* | |||
| 2309 | * Note: this should not happen | |||
| 2310 | * with `dmaselect' on. | |||
| 2311 | */ | |||
| 2312 | sc->sc_flags |= NCR_EXPECT_ILLCMD0x80; | |||
| 2313 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2313); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2314 | } else if (sc->sc_features & NCR_F_DMASELECT0x04 && | |||
| 2315 | sc->sc_rev == NCR_VARIANT_ESP1000) { | |||
| 2316 | sc->sc_flags |= NCR_EXPECT_ILLCMD0x80; | |||
| 2317 | } | |||
| 2318 | ||||
| 2319 | if (sc->sc_state != NCR_CONNECTED5 && | |||
| 2320 | sc->sc_state != NCR_IDENTIFIED4) { | |||
| 2321 | /* IDENTIFY fail?! */ | |||
| 2322 | printf("%s: identify failed, state %d, intr %02x\n", | |||
| 2323 | sc->sc_dev.dv_xname, sc->sc_state, | |||
| 2324 | sc->sc_espintr); | |||
| 2325 | ncr53c9x_init(sc, 1); | |||
| 2326 | return (1); | |||
| 2327 | } | |||
| 2328 | goto shortcut; /* ie. next phase expected soon */ | |||
| 2329 | } | |||
| 2330 | ||||
| 2331 | #define NCRINTR_DONE(0x08|0x10) (NCRINTR_FC0x08|NCRINTR_BS0x10) | |||
| 2332 | if ((sc->sc_espintr & NCRINTR_DONE(0x08|0x10)) == NCRINTR_DONE(0x08|0x10)) { | |||
| 2333 | /* | |||
| 2334 | * Arbitration won; examine the `step' register | |||
| 2335 | * to determine how far the selection could progress. | |||
| 2336 | */ | |||
| 2337 | ecb = sc->sc_nexus; | |||
| 2338 | if (!ecb) | |||
| 2339 | panic("ncr53c9x: no nexus"); | |||
| 2340 | ||||
| 2341 | sc_link = ecb->xs->sc_link; | |||
| 2342 | ti = &sc->sc_tinfo[sc_link->target]; | |||
| 2343 | ||||
| 2344 | switch (sc->sc_espstep) { | |||
| 2345 | case 0: | |||
| 2346 | /* | |||
| 2347 | * The target did not respond with a | |||
| 2348 | * message out phase - probably an old | |||
| 2349 | * device that doesn't recognize ATN. | |||
| 2350 | * Clear ATN and just continue, the | |||
| 2351 | * target should be in the command | |||
| 2352 | * phase. | |||
| 2353 | * XXXX check for command phase? | |||
| 2354 | */ | |||
| 2355 | NCRCMD(sc, NCRCMD_RSTATN)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x1b, 2355); sc->sc_lastcmd = 0x1b; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x1b)); } while (0); | |||
| 2356 | break; | |||
| 2357 | case 1: | |||
| 2358 | if ((ti->flags & T_NEGOTIATE0x02) == 0 && | |||
| 2359 | ecb->tag[0] == 0) { | |||
| 2360 | printf("%s: step 1 & !NEG\n", | |||
| 2361 | sc->sc_dev.dv_xname); | |||
| 2362 | goto reset; | |||
| 2363 | } | |||
| 2364 | if (sc->sc_phase != MESSAGE_OUT_PHASE(0x04|0x02)) { | |||
| 2365 | printf("%s: !MSGOUT\n", | |||
| 2366 | sc->sc_dev.dv_xname); | |||
| 2367 | goto reset; | |||
| 2368 | } | |||
| 2369 | if (ti->flags & T_WIDE0x80) { | |||
| 2370 | ncr53c9x_sched_msgout(SEND_WDTR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0040, 2370);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2370); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0040); } while (0); | |||
| 2371 | } | |||
| 2372 | if (ti->flags & T_NEGOTIATE0x02) { | |||
| 2373 | /* Start negotiating */ | |||
| 2374 | ti->period = sc->sc_minsync; | |||
| 2375 | ti->offset = 15; | |||
| 2376 | sc->sc_flags |= NCR_SYNCHNEGO0x08; | |||
| 2377 | if (ecb->tag[0]) | |||
| 2378 | ncr53c9x_sched_msgout(SEND_TAG|SEND_SDTR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0100|0x0080, 2378);} while (0); do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2378); sc ->sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)( (sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc ->sc_msgpriq |= (0x0100|0x0080); } while (0); | |||
| 2379 | else | |||
| 2380 | ncr53c9x_sched_msgout(SEND_SDTR)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0080, 2380);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2380); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0080); } while (0); | |||
| 2381 | } else { | |||
| 2382 | /* Could not do ATN3 so send TAG */ | |||
| 2383 | ncr53c9x_sched_msgout(SEND_TAG)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0100, 2383);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2383); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0100); } while (0); | |||
| 2384 | } | |||
| 2385 | sc->sc_prevphase = MESSAGE_OUT_PHASE(0x04|0x02); /* XXXX */ | |||
| 2386 | break; | |||
| 2387 | case 3: | |||
| 2388 | /* | |||
| 2389 | * Grr, this is supposed to mean | |||
| 2390 | * "target left command phase prematurely". | |||
| 2391 | * It seems to happen regularly when | |||
| 2392 | * sync mode is on. | |||
| 2393 | * Look at FIFO to see if command went out. | |||
| 2394 | * (Timing problems?) | |||
| 2395 | */ | |||
| 2396 | if (sc->sc_features & NCR_F_DMASELECT0x04) { | |||
| 2397 | if (sc->sc_cmdlen == 0) | |||
| 2398 | /* Hope for the best.. */ | |||
| 2399 | break; | |||
| 2400 | } else if ((NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) | |||
| 2401 | & NCRFIFO_FF0x1f) == 0) { | |||
| 2402 | /* Hope for the best.. */ | |||
| 2403 | break; | |||
| 2404 | } | |||
| 2405 | printf("(%s:%d:%d): selection failed;" | |||
| 2406 | " %d left in FIFO " | |||
| 2407 | "[intr %x, stat %x, step %d]\n", | |||
| 2408 | sc->sc_dev.dv_xname, | |||
| 2409 | sc_link->target, | |||
| 2410 | sc_link->lun, | |||
| 2411 | NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) | |||
| 2412 | & NCRFIFO_FF0x1f, | |||
| 2413 | sc->sc_espintr, sc->sc_espstat, | |||
| 2414 | sc->sc_espstep); | |||
| 2415 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2415); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2416 | ncr53c9x_sched_msgout(SEND_ABORT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0020, 2416);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2416); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0020); } while (0); | |||
| 2417 | return (1); | |||
| 2418 | case 2: | |||
| 2419 | /* Select stuck at Command Phase */ | |||
| 2420 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2420); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2421 | break; | |||
| 2422 | case 4: | |||
| 2423 | if (sc->sc_features & NCR_F_DMASELECT0x04 && | |||
| 2424 | sc->sc_cmdlen != 0) | |||
| 2425 | printf("(%s:%d:%d): select; " | |||
| 2426 | "%lu left in DMA buffer " | |||
| 2427 | "[intr %x, stat %x, step %d]\n", | |||
| 2428 | sc->sc_dev.dv_xname, | |||
| 2429 | sc_link->target, | |||
| 2430 | sc_link->lun, | |||
| 2431 | (u_long)sc->sc_cmdlen, | |||
| 2432 | sc->sc_espintr, | |||
| 2433 | sc->sc_espstat, | |||
| 2434 | sc->sc_espstep); | |||
| 2435 | /* So far, everything went fine */ | |||
| 2436 | break; | |||
| 2437 | } | |||
| 2438 | ||||
| 2439 | sc->sc_prevphase = INVALID_PHASE0x101; /* ?? */ | |||
| 2440 | /* Do an implicit RESTORE POINTERS. */ | |||
| 2441 | sc->sc_dp = ecb->daddr; | |||
| 2442 | sc->sc_dleft = ecb->dleft; | |||
| 2443 | sc->sc_state = NCR_CONNECTED5; | |||
| 2444 | break; | |||
| 2445 | ||||
| 2446 | } else { | |||
| 2447 | ||||
| 2448 | printf("%s: unexpected status after select" | |||
| 2449 | ": [intr %x, stat %x, step %x]\n", | |||
| 2450 | sc->sc_dev.dv_xname, | |||
| 2451 | sc->sc_espintr, sc->sc_espstat, | |||
| 2452 | sc->sc_espstep); | |||
| 2453 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2453); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2454 | DELAY(1)(*delay_func)(1); | |||
| 2455 | goto reset; | |||
| 2456 | } | |||
| 2457 | if (sc->sc_state == NCR_IDLE1) { | |||
| 2458 | printf("%s: stray interrupt\n", | |||
| 2459 | sc->sc_dev.dv_xname); | |||
| 2460 | return (0); | |||
| 2461 | } | |||
| 2462 | break; | |||
| 2463 | ||||
| 2464 | case NCR_CONNECTED5: | |||
| 2465 | if (sc->sc_flags & NCR_ICCS0x10) { | |||
| 2466 | /* "Initiate Command Complete Steps" in progress */ | |||
| 2467 | u_char msg; | |||
| 2468 | ||||
| 2469 | sc->sc_flags &= ~NCR_ICCS0x10; | |||
| 2470 | ||||
| 2471 | if (!(sc->sc_espintr & NCRINTR_DONE(0x08|0x10))) { | |||
| 2472 | printf("%s: ICCS: " | |||
| 2473 | ": [intr %x, stat %x, step %x]\n", | |||
| 2474 | sc->sc_dev.dv_xname, | |||
| 2475 | sc->sc_espintr, sc->sc_espstat, | |||
| 2476 | sc->sc_espstep); | |||
| 2477 | } | |||
| 2478 | ncr53c9x_rdfifo(sc, NCR_RDFIFO_START0); | |||
| 2479 | if (sc->sc_imlen < 2) | |||
| 2480 | printf("%s: can't get status, only %d bytes\n", | |||
| 2481 | sc->sc_dev.dv_xname, (int)sc->sc_imlen); | |||
| 2482 | ecb->stat = sc->sc_imess[sc->sc_imlen - 2]; | |||
| 2483 | msg = sc->sc_imess[sc->sc_imlen - 1]; | |||
| 2484 | NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg))do {if (ncr53c9x_debug & 0x40) printf ("<stat:(%x,%x)>" , ecb->stat, msg);}while (0); | |||
| 2485 | if (msg == MSG_CMDCOMPLETE0x00) { | |||
| 2486 | ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE0x100) | |||
| 2487 | ? 0 | |||
| 2488 | : sc->sc_dleft; | |||
| 2489 | if ((ecb->flags & ECB_SENSE0x04) == 0) | |||
| 2490 | ecb->xs->resid = ecb->dleft; | |||
| 2491 | sc->sc_state = NCR_CMDCOMPLETE7; | |||
| 2492 | } else | |||
| 2493 | printf("%s: STATUS_PHASE: msg %d\n", | |||
| 2494 | sc->sc_dev.dv_xname, msg); | |||
| 2495 | sc->sc_imlen = 0; | |||
| 2496 | NCRCMD(sc, NCRCMD_MSGOK)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x12, 2496); sc->sc_lastcmd = 0x12; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x12)); } while (0); | |||
| 2497 | goto shortcut; /* ie. wait for disconnect */ | |||
| 2498 | } | |||
| 2499 | break; | |||
| 2500 | default: | |||
| 2501 | /* Don't panic: reset. */ | |||
| 2502 | printf("%s: invalid state: %d\n", | |||
| 2503 | sc->sc_dev.dv_xname, | |||
| 2504 | sc->sc_state); | |||
| 2505 | ncr53c9x_scsi_reset(sc); | |||
| 2506 | goto out; | |||
| 2507 | break; | |||
| 2508 | } | |||
| 2509 | ||||
| 2510 | /* | |||
| 2511 | * Driver is now in state NCR_CONNECTED, i.e. we | |||
| 2512 | * have a current command working the SCSI bus. | |||
| 2513 | */ | |||
| 2514 | if (sc->sc_state != NCR_CONNECTED5 || ecb == NULL((void *)0)) { | |||
| 2515 | panic("ncr53c9x no nexus"); | |||
| 2516 | } | |||
| 2517 | ||||
| 2518 | switch (sc->sc_phase) { | |||
| 2519 | case MESSAGE_OUT_PHASE(0x04|0x02): | |||
| 2520 | NCR_PHASE(("MESSAGE_OUT_PHASE "))do {if (ncr53c9x_debug & 0x40) printf ("MESSAGE_OUT_PHASE " );}while (0); | |||
| 2521 | ncr53c9x_msgout(sc); | |||
| 2522 | sc->sc_prevphase = MESSAGE_OUT_PHASE(0x04|0x02); | |||
| 2523 | break; | |||
| 2524 | case MESSAGE_IN_PHASE(0x04|0x02|0x01): | |||
| 2525 | msgin: | |||
| 2526 | NCR_PHASE(("MESSAGE_IN_PHASE "))do {if (ncr53c9x_debug & 0x40) printf ("MESSAGE_IN_PHASE " );}while (0); | |||
| 2527 | if (sc->sc_espintr & NCRINTR_BS0x10) { | |||
| 2528 | if ((sc->sc_rev != NCR_VARIANT_FAS3669) || | |||
| 2529 | !(sc->sc_espstat2 & FAS_STAT2_EMPTY0x80)) { | |||
| 2530 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2530); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2531 | } | |||
| 2532 | sc->sc_flags |= NCR_WAITI0x20; | |||
| 2533 | NCRCMD(sc, NCRCMD_TRANS)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x10, 2533); sc->sc_lastcmd = 0x10; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x10)); } while (0); | |||
| 2534 | } else if (sc->sc_espintr & NCRINTR_FC0x08) { | |||
| 2535 | if ((sc->sc_flags & NCR_WAITI0x20) == 0) { | |||
| 2536 | printf("%s: MSGIN: unexpected FC bit: " | |||
| 2537 | "[intr %x, stat %x, step %x]\n", | |||
| 2538 | sc->sc_dev.dv_xname, | |||
| 2539 | sc->sc_espintr, sc->sc_espstat, | |||
| 2540 | sc->sc_espstep); | |||
| 2541 | } | |||
| 2542 | sc->sc_flags &= ~NCR_WAITI0x20; | |||
| 2543 | ncr53c9x_rdfifo(sc, | |||
| 2544 | (sc->sc_prevphase == sc->sc_phase) ? | |||
| 2545 | NCR_RDFIFO_CONTINUE1 : NCR_RDFIFO_START0); | |||
| 2546 | ncr53c9x_msgin(sc); | |||
| 2547 | } else { | |||
| 2548 | printf("%s: MSGIN: weird bits: " | |||
| 2549 | "[intr %x, stat %x, step %x]\n", | |||
| 2550 | sc->sc_dev.dv_xname, | |||
| 2551 | sc->sc_espintr, sc->sc_espstat, | |||
| 2552 | sc->sc_espstep); | |||
| 2553 | } | |||
| 2554 | sc->sc_prevphase = MESSAGE_IN_PHASE(0x04|0x02|0x01); | |||
| 2555 | goto shortcut; /* i.e. expect data to be ready */ | |||
| 2556 | break; | |||
| 2557 | case COMMAND_PHASE(0x02): | |||
| 2558 | /* | |||
| 2559 | * Send the command block. Normally we don't see this | |||
| 2560 | * phase because the SEL_ATN command takes care of | |||
| 2561 | * all this. However, we end up here if either the | |||
| 2562 | * target or we wanted to exchange some more messages | |||
| 2563 | * first (e.g. to start negotiations). | |||
| 2564 | */ | |||
| 2565 | ||||
| 2566 | NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ",do {if (ncr53c9x_debug & 0x40) printf ("COMMAND_PHASE 0x%02x (%d) " , ecb->cmd.cmd.opcode, ecb->clen);}while (0) | |||
| 2567 | ecb->cmd.cmd.opcode, ecb->clen))do {if (ncr53c9x_debug & 0x40) printf ("COMMAND_PHASE 0x%02x (%d) " , ecb->cmd.cmd.opcode, ecb->clen);}while (0); | |||
| 2568 | if (NCR_READ_REG(sc, NCR_FFLAG)(*(sc)->sc_glue->gl_read_reg)((sc), (0x07)) & NCRFIFO_FF0x1f) { | |||
| 2569 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2569); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2570 | /* DELAY(1); */ | |||
| 2571 | } | |||
| 2572 | if (sc->sc_features & NCR_F_DMASELECT0x04) { | |||
| 2573 | /* setup DMA transfer for command */ | |||
| 2574 | size = ecb->clen; | |||
| 2575 | sc->sc_cmdlen = size; | |||
| 2576 | sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd; | |||
| 2577 | NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_cmdp ), (&sc->sc_cmdlen), (0), (&size)) | |||
| 2578 | 0, &size)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_cmdp ), (&sc->sc_cmdlen), (0), (&size)); | |||
| 2579 | /* Program the SCSI counter */ | |||
| 2580 | NCR_SET_COUNT(sc, size)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (size))); (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x01 ), ((size) >> 8)); if ((sc->sc_cfg2 & 0x40) || ( sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg) (((sc)), (0x0e), ((size) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0)); } } while (0); | |||
| 2581 | ||||
| 2582 | /* load the count in */ | |||
| 2583 | NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00|0x80, 2583); sc->sc_lastcmd = 0x00|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x00|0x80) ); } while (0); | |||
| 2584 | ||||
| 2585 | /* start the command transfer */ | |||
| 2586 | NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x10 | 0x80, 2586); sc->sc_lastcmd = 0x10 | 0x80 ; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x10 | 0x80 )); } while (0); | |||
| 2587 | NCRDMA_GO(sc)(*(sc)->sc_glue->gl_dma_go)((sc)); | |||
| 2588 | } else { | |||
| 2589 | ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen); | |||
| 2590 | sc->sc_cmdlen = 0; | |||
| 2591 | NCRCMD(sc, NCRCMD_TRANS)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x10, 2591); sc->sc_lastcmd = 0x10; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x10)); } while (0); | |||
| 2592 | } | |||
| 2593 | sc->sc_prevphase = COMMAND_PHASE(0x02); | |||
| 2594 | break; | |||
| 2595 | case DATA_OUT_PHASE(0): | |||
| 2596 | NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft))do {if (ncr53c9x_debug & 0x40) printf ("DATA_OUT_PHASE [%ld] " ,(long)sc->sc_dleft);}while (0); | |||
| 2597 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2597); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2598 | size = min(sc->sc_dleft, sc->sc_maxxfer); | |||
| 2599 | NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft,(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_dp ), (&sc->sc_dleft), (0), (&size)) | |||
| 2600 | 0, &size)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_dp ), (&sc->sc_dleft), (0), (&size)); | |||
| 2601 | sc->sc_prevphase = DATA_OUT_PHASE(0); | |||
| 2602 | goto setup_xfer; | |||
| 2603 | case DATA_IN_PHASE(0x01): | |||
| 2604 | NCR_PHASE(("DATA_IN_PHASE "))do {if (ncr53c9x_debug & 0x40) printf ("DATA_IN_PHASE "); }while (0); | |||
| 2605 | if (sc->sc_rev == NCR_VARIANT_ESP1000) | |||
| 2606 | NCRCMD(sc, NCRCMD_FLUSH)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x01, 2606); sc->sc_lastcmd = 0x01; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x01)); } while (0); | |||
| 2607 | size = min(sc->sc_dleft, sc->sc_maxxfer); | |||
| 2608 | NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft,(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_dp ), (&sc->sc_dleft), (1), (&size)) | |||
| 2609 | 1, &size)(*(sc)->sc_glue->gl_dma_setup)((sc), (&sc->sc_dp ), (&sc->sc_dleft), (1), (&size)); | |||
| 2610 | sc->sc_prevphase = DATA_IN_PHASE(0x01); | |||
| 2611 | setup_xfer: | |||
| 2612 | /* Target returned to data phase: wipe "done" memory */ | |||
| 2613 | ecb->flags &= ~ECB_TENTATIVE_DONE0x100; | |||
| 2614 | ||||
| 2615 | /* Program the SCSI counter */ | |||
| 2616 | NCR_SET_COUNT(sc, size)do { (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x00), ( (size))); (*((sc))->sc_glue->gl_write_reg)(((sc)), (0x01 ), ((size) >> 8)); if ((sc->sc_cfg2 & 0x40) || ( sc->sc_rev == 9)) { (*((sc))->sc_glue->gl_write_reg) (((sc)), (0x0e), ((size) >> 16)); } if (sc->sc_rev == 9) { (*(sc)->sc_glue->gl_write_reg)((sc), (0xf), (0)); } } while (0); | |||
| 2617 | ||||
| 2618 | /* load the count in */ | |||
| 2619 | NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x00|0x80, 2619); sc->sc_lastcmd = 0x00|0x80; ( *(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x00|0x80) ); } while (0); | |||
| 2620 | ||||
| 2621 | /* | |||
| 2622 | * Note that if `size' is 0, we've already transceived | |||
| 2623 | * all the bytes we want but we're still in DATA PHASE. | |||
| 2624 | * Apparently, the device needs padding. Also, a | |||
| 2625 | * transfer size of 0 means "maximum" to the chip | |||
| 2626 | * DMA logic. | |||
| 2627 | */ | |||
| 2628 | NCRCMD(sc,do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)(size==0?0x18:0x10)|0x80, 2629); sc->sc_lastcmd = (size==0?0x18:0x10)|0x80; (*(sc)->sc_glue->gl_write_reg )((sc), (0x03), ((size==0?0x18:0x10)|0x80)); } while (0) | |||
| 2629 | (size==0?NCRCMD_TRPAD:NCRCMD_TRANS)|NCRCMD_DMA)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)(size==0?0x18:0x10)|0x80, 2629); sc->sc_lastcmd = (size==0?0x18:0x10)|0x80; (*(sc)->sc_glue->gl_write_reg )((sc), (0x03), ((size==0?0x18:0x10)|0x80)); } while (0); | |||
| 2630 | NCRDMA_GO(sc)(*(sc)->sc_glue->gl_dma_go)((sc)); | |||
| 2631 | return (1); | |||
| 2632 | case STATUS_PHASE(0x02|0x01): | |||
| 2633 | NCR_PHASE(("STATUS_PHASE "))do {if (ncr53c9x_debug & 0x40) printf ("STATUS_PHASE ");} while (0); | |||
| 2634 | sc->sc_flags |= NCR_ICCS0x10; | |||
| 2635 | NCRCMD(sc, NCRCMD_ICCS)do { if (ncr53c9x_debug & 0x100) printf("<cmd:0x%x %d>" , (unsigned)0x11, 2635); sc->sc_lastcmd = 0x11; (*(sc)-> sc_glue->gl_write_reg)((sc), (0x03), (0x11)); } while (0); | |||
| 2636 | sc->sc_prevphase = STATUS_PHASE(0x02|0x01); | |||
| 2637 | goto shortcut; /* i.e. expect status results soon */ | |||
| 2638 | break; | |||
| 2639 | case INVALID_PHASE0x101: | |||
| 2640 | break; | |||
| 2641 | default: | |||
| 2642 | printf("%s: unexpected bus phase; resetting\n", | |||
| 2643 | sc->sc_dev.dv_xname); | |||
| 2644 | goto reset; | |||
| 2645 | } | |||
| 2646 | ||||
| 2647 | out: | |||
| 2648 | return (1); | |||
| 2649 | ||||
| 2650 | reset: | |||
| 2651 | ncr53c9x_init(sc, 1); | |||
| 2652 | goto out; | |||
| 2653 | ||||
| 2654 | finish: | |||
| 2655 | ncr53c9x_done(sc, ecb); | |||
| 2656 | goto out; | |||
| 2657 | ||||
| 2658 | sched: | |||
| 2659 | sc->sc_state = NCR_IDLE1; | |||
| 2660 | ncr53c9x_sched(sc); | |||
| 2661 | goto out; | |||
| 2662 | ||||
| 2663 | shortcut: | |||
| 2664 | /* | |||
| 2665 | * The idea is that many of the SCSI operations take very little | |||
| 2666 | * time, and going away and getting interrupted is too high an | |||
| 2667 | * overhead to pay. For example, selecting, sending a message | |||
| 2668 | * and command and then doing some work can be done in one "pass". | |||
| 2669 | * | |||
| 2670 | * The delay is a heuristic. It is 2 when at 20MHz, 2 at 25MHz and 1 | |||
| 2671 | * at 40MHz. This needs testing. | |||
| 2672 | */ | |||
| 2673 | { | |||
| 2674 | struct timeval wait, cur; | |||
| 2675 | ||||
| 2676 | microuptime(&wait); | |||
| 2677 | wait.tv_usec += 50/sc->sc_freq; | |||
| 2678 | if (wait.tv_usec >= 1000000) { | |||
| 2679 | wait.tv_sec++; | |||
| 2680 | wait.tv_usec -= 1000000; | |||
| 2681 | } | |||
| 2682 | do { | |||
| 2683 | if (NCRDMA_ISINTR(sc)(*(sc)->sc_glue->gl_dma_isintr)((sc))) | |||
| 2684 | goto again; | |||
| 2685 | microuptime(&cur); | |||
| 2686 | } while (timercmp(&cur, &wait, <=)(((&cur)->tv_sec == (&wait)->tv_sec) ? ((&cur )->tv_usec <= (&wait)->tv_usec) : ((&cur)-> tv_sec <= (&wait)->tv_sec))); | |||
| 2687 | } | |||
| 2688 | goto out; | |||
| 2689 | } | |||
| 2690 | ||||
| 2691 | void | |||
| 2692 | ncr53c9x_abort(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb) | |||
| 2693 | { | |||
| 2694 | ||||
| 2695 | /* 2 secs for the abort */ | |||
| 2696 | ecb->timeout = NCR_ABORT_TIMEOUT2000; | |||
| 2697 | ecb->flags |= ECB_ABORT0x40; | |||
| 2698 | ||||
| 2699 | if (ecb == sc->sc_nexus) { | |||
| 2700 | int timeout = ecb->timeout; | |||
| 2701 | ||||
| 2702 | /* | |||
| 2703 | * If we're still selecting, the message will be scheduled | |||
| 2704 | * after selection is complete. | |||
| 2705 | */ | |||
| 2706 | if (sc->sc_state == NCR_CONNECTED5) | |||
| 2707 | ncr53c9x_sched_msgout(SEND_ABORT)do { do {if (ncr53c9x_debug & 0x08) printf ("ncr53c9x_sched_msgout %x %d " , 0x0020, 2707);} while (0); do { if (ncr53c9x_debug & 0x100 ) printf("<cmd:0x%x %d>", (unsigned)0x1a, 2707); sc-> sc_lastcmd = 0x1a; (*(sc)->sc_glue->gl_write_reg)((sc), (0x03), (0x1a)); } while (0); sc->sc_flags |= 0x40; sc-> sc_msgpriq |= (0x0020); } while (0); | |||
| 2708 | ||||
| 2709 | /* | |||
| 2710 | * Reschedule timeout. | |||
| 2711 | */ | |||
| 2712 | if (timeout > 1000000) | |||
| 2713 | timeout = (timeout / 1000) * hz; | |||
| 2714 | else | |||
| 2715 | timeout = (timeout * hz) / 1000; | |||
| 2716 | timeout_add(&ecb->to, timeout); | |||
| 2717 | } else { | |||
| 2718 | /* | |||
| 2719 | * Just leave the command where it is. | |||
| 2720 | * XXX - what choice do we have but to reset the SCSI | |||
| 2721 | * eventually? | |||
| 2722 | */ | |||
| 2723 | if (sc->sc_state == NCR_IDLE1) | |||
| 2724 | ncr53c9x_sched(sc); | |||
| 2725 | } | |||
| 2726 | } | |||
| 2727 | ||||
| 2728 | void | |||
| 2729 | ncr53c9x_timeout(void *arg) | |||
| 2730 | { | |||
| 2731 | struct ncr53c9x_ecb *ecb = arg; | |||
| 2732 | struct scsi_xfer *xs = ecb->xs; | |||
| 2733 | struct scsi_link *sc_link = xs->sc_link; | |||
| 2734 | struct ncr53c9x_softc *sc = sc_link->bus->sb_adapter_softc; | |||
| 2735 | struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[sc_link->target]; | |||
| 2736 | int s; | |||
| 2737 | ||||
| 2738 | sc_print_addr(sc_link); | |||
| 2739 | printf("timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], " | |||
| 2740 | "<state %d, nexus %p, phase(l %x, c %x, p %x), resid %lx, " | |||
| 2741 | "msg(q %x,o %x) %s>", | |||
| 2742 | ecb, ecb->flags, ecb->dleft, ecb->stat, | |||
| 2743 | sc->sc_state, sc->sc_nexus, | |||
| 2744 | NCR_READ_REG(sc, NCR_STAT)(*(sc)->sc_glue->gl_read_reg)((sc), (0x04)), | |||
| 2745 | sc->sc_phase, sc->sc_prevphase, | |||
| 2746 | (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout, | |||
| 2747 | NCRDMA_ISACTIVE(sc)(*(sc)->sc_glue->gl_dma_isactive)((sc)) ? "DMA active" : ""); | |||
| 2748 | #if NCR53C9X_DEBUG1 > 1 | |||
| 2749 | printf("TRACE: %s.", ecb->trace); | |||
| 2750 | #endif | |||
| 2751 | ||||
| 2752 | s = splbio()splraise(0x3); | |||
| 2753 | ||||
| 2754 | if (ecb->flags & ECB_ABORT0x40) { | |||
| 2755 | /* abort timed out */ | |||
| 2756 | printf(" AGAIN\n"); | |||
| 2757 | ||||
| 2758 | ncr53c9x_init(sc, 1); | |||
| 2759 | } else { | |||
| 2760 | /* abort the operation that has timed out */ | |||
| 2761 | printf("\n"); | |||
| 2762 | xs->error = XS_TIMEOUT4; | |||
| 2763 | ncr53c9x_abort(sc, ecb); | |||
| 2764 | ||||
| 2765 | /* Disable sync mode if stuck in a data phase */ | |||
| 2766 | if (ecb == sc->sc_nexus && | |||
| 2767 | (ti->flags & T_SYNCMODE0x08) != 0 && | |||
| 2768 | (sc->sc_phase & (MSGI0x04|CDI0x02)) == 0) { | |||
| 2769 | sc_print_addr(sc_link); | |||
| 2770 | printf("sync negotiation disabled\n"); | |||
| 2771 | sc->sc_cfflags |= (1 << (sc_link->target + 16)); | |||
| 2772 | } | |||
| 2773 | } | |||
| 2774 | ||||
| 2775 | splx(s)spllower(s); | |||
| 2776 | } |