1 1.105 andvar /* $NetBSD: siop.c,v 1.105 2024/02/08 19:44:08 andvar Exp $ */ 2 1.1 bouyer 3 1.1 bouyer /* 4 1.1 bouyer * Copyright (c) 2000 Manuel Bouyer. 5 1.1 bouyer * 6 1.1 bouyer * Redistribution and use in source and binary forms, with or without 7 1.1 bouyer * modification, are permitted provided that the following conditions 8 1.1 bouyer * are met: 9 1.1 bouyer * 1. Redistributions of source code must retain the above copyright 10 1.1 bouyer * notice, this list of conditions and the following disclaimer. 11 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 bouyer * notice, this list of conditions and the following disclaimer in the 13 1.1 bouyer * documentation and/or other materials provided with the distribution. 14 1.1 bouyer * 15 1.14 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.14 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.14 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.78 perry * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.14 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.14 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.14 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.14 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.14 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.14 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 bouyer * 26 1.1 bouyer */ 27 1.1 bouyer 28 1.1 bouyer /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ 29 1.48 lukem 30 1.48 lukem #include <sys/cdefs.h> 31 1.105 andvar __KERNEL_RCSID(0, "$NetBSD: siop.c,v 1.105 2024/02/08 19:44:08 andvar Exp $"); 32 1.1 bouyer 33 1.1 bouyer #include <sys/param.h> 34 1.1 bouyer #include <sys/systm.h> 35 1.1 bouyer #include <sys/device.h> 36 1.1 bouyer #include <sys/malloc.h> 37 1.1 bouyer #include <sys/buf.h> 38 1.1 bouyer #include <sys/kernel.h> 39 1.1 bouyer 40 1.1 bouyer #include <machine/endian.h> 41 1.85 ad #include <sys/bus.h> 42 1.1 bouyer 43 1.1 bouyer #include <dev/microcode/siop/siop.out> 44 1.1 bouyer 45 1.1 bouyer #include <dev/scsipi/scsi_all.h> 46 1.1 bouyer #include <dev/scsipi/scsi_message.h> 47 1.1 bouyer #include <dev/scsipi/scsipi_all.h> 48 1.1 bouyer 49 1.1 bouyer #include <dev/scsipi/scsiconf.h> 50 1.1 bouyer 51 1.1 bouyer #include <dev/ic/siopreg.h> 52 1.53 bouyer #include <dev/ic/siopvar_common.h> 53 1.1 bouyer #include <dev/ic/siopvar.h> 54 1.1 bouyer 55 1.52 bouyer #include "opt_siop.h" 56 1.52 bouyer 57 1.82 garbled /* 58 1.82 garbled #define SIOP_DEBUG 59 1.82 garbled #define SIOP_DEBUG_DR 60 1.82 garbled #define SIOP_DEBUG_INTR 61 1.82 garbled #define SIOP_DEBUG_SCHED 62 1.97 jakllsch #define SIOP_DUMP_SCRIPT 63 1.82 garbled */ 64 1.2 bouyer 65 1.2 bouyer #define SIOP_STATS 66 1.2 bouyer 67 1.1 bouyer #ifndef SIOP_DEFAULT_TARGET 68 1.1 bouyer #define SIOP_DEFAULT_TARGET 7 69 1.1 bouyer #endif 70 1.1 bouyer 71 1.16 bouyer /* number of cmd descriptors per block */ 72 1.37 thorpej #define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct siop_xfer)) 73 1.1 bouyer 74 1.35 bouyer /* Number of scheduler slot (needs to match script) */ 75 1.35 bouyer #define SIOP_NSLOTS 40 76 1.35 bouyer 77 1.77 perry void siop_reset(struct siop_softc *); 78 1.77 perry void siop_handle_reset(struct siop_softc *); 79 1.77 perry int siop_handle_qtag_reject(struct siop_cmd *); 80 1.77 perry void siop_scsicmd_end(struct siop_cmd *); 81 1.77 perry void siop_unqueue(struct siop_softc *, int, int); 82 1.77 perry static void siop_start(struct siop_softc *, struct siop_cmd *); 83 1.93 tsutsui void siop_timeout(void *); 84 1.77 perry int siop_scsicmd(struct scsipi_xfer *); 85 1.77 perry void siop_scsipi_request(struct scsipi_channel *, 86 1.77 perry scsipi_adapter_req_t, void *); 87 1.77 perry void siop_dump_script(struct siop_softc *); 88 1.77 perry void siop_morecbd(struct siop_softc *); 89 1.77 perry struct siop_lunsw *siop_get_lunsw(struct siop_softc *); 90 1.77 perry void siop_add_reselsw(struct siop_softc *, int); 91 1.77 perry void siop_update_scntl3(struct siop_softc *, 92 1.77 perry struct siop_common_target *); 93 1.1 bouyer 94 1.2 bouyer #ifdef SIOP_STATS 95 1.2 bouyer static int siop_stat_intr = 0; 96 1.2 bouyer static int siop_stat_intr_shortxfer = 0; 97 1.2 bouyer static int siop_stat_intr_sdp = 0; 98 1.79 bouyer static int siop_stat_intr_saveoffset = 0; 99 1.2 bouyer static int siop_stat_intr_done = 0; 100 1.2 bouyer static int siop_stat_intr_xferdisc = 0; 101 1.35 bouyer static int siop_stat_intr_lunresel = 0; 102 1.36 bouyer static int siop_stat_intr_qfull = 0; 103 1.77 perry void siop_printstats(void); 104 1.2 bouyer #define INCSTAT(x) x++ 105 1.2 bouyer #else 106 1.78 perry #define INCSTAT(x) 107 1.2 bouyer #endif 108 1.2 bouyer 109 1.80 perry static inline void siop_script_sync(struct siop_softc *, int); 110 1.80 perry static inline void 111 1.88 dsl siop_script_sync(struct siop_softc *sc, int ops) 112 1.32 bouyer { 113 1.92 tsutsui 114 1.53 bouyer if ((sc->sc_c.features & SF_CHIP_RAM) == 0) 115 1.53 bouyer bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0, 116 1.37 thorpej PAGE_SIZE, ops); 117 1.32 bouyer } 118 1.32 bouyer 119 1.92 tsutsui static inline uint32_t siop_script_read(struct siop_softc *, u_int); 120 1.92 tsutsui static inline uint32_t 121 1.88 dsl siop_script_read(struct siop_softc *sc, u_int offset) 122 1.31 bouyer { 123 1.92 tsutsui 124 1.53 bouyer if (sc->sc_c.features & SF_CHIP_RAM) { 125 1.53 bouyer return bus_space_read_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 126 1.53 bouyer offset * 4); 127 1.31 bouyer } else { 128 1.86 skrll return siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[offset]); 129 1.31 bouyer } 130 1.31 bouyer } 131 1.31 bouyer 132 1.80 perry static inline void siop_script_write(struct siop_softc *, u_int, 133 1.92 tsutsui uint32_t); 134 1.80 perry static inline void 135 1.92 tsutsui siop_script_write(struct siop_softc *sc, u_int offset, uint32_t val) 136 1.28 bouyer { 137 1.92 tsutsui 138 1.53 bouyer if (sc->sc_c.features & SF_CHIP_RAM) { 139 1.53 bouyer bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 140 1.53 bouyer offset * 4, val); 141 1.31 bouyer } else { 142 1.86 skrll sc->sc_c.sc_script[offset] = siop_htoc32(&sc->sc_c, val); 143 1.31 bouyer } 144 1.2 bouyer } 145 1.2 bouyer 146 1.1 bouyer void 147 1.88 dsl siop_attach(struct siop_softc *sc) 148 1.1 bouyer { 149 1.92 tsutsui 150 1.58 bouyer if (siop_common_attach(&sc->sc_c) != 0) 151 1.58 bouyer return; 152 1.1 bouyer 153 1.1 bouyer TAILQ_INIT(&sc->free_list); 154 1.16 bouyer TAILQ_INIT(&sc->cmds); 155 1.31 bouyer TAILQ_INIT(&sc->lunsw_list); 156 1.29 bouyer sc->sc_currschedslot = 0; 157 1.35 bouyer #ifdef SIOP_DEBUG 158 1.35 bouyer printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n", 159 1.91 tsutsui device_xname(sc->sc_c.sc_dev), (int)sizeof(siop_script), 160 1.92 tsutsui (uint32_t)sc->sc_c.sc_scriptaddr, sc->sc_c.sc_script); 161 1.1 bouyer #endif 162 1.1 bouyer 163 1.53 bouyer sc->sc_c.sc_adapt.adapt_max_periph = SIOP_NTAG - 1; 164 1.53 bouyer sc->sc_c.sc_adapt.adapt_request = siop_scsipi_request; 165 1.53 bouyer 166 1.26 bouyer /* Do a bus reset, so that devices fall back to narrow/async */ 167 1.53 bouyer siop_resetbus(&sc->sc_c); 168 1.26 bouyer /* 169 1.26 bouyer * siop_reset() will reset the chip, thus clearing pending interrupts 170 1.26 bouyer */ 171 1.1 bouyer siop_reset(sc); 172 1.97 jakllsch #ifdef SIOP_DUMP_SCRIPT 173 1.2 bouyer siop_dump_script(sc); 174 1.2 bouyer #endif 175 1.1 bouyer 176 1.102 thorpej config_found(sc->sc_c.sc_dev, &sc->sc_c.sc_chan, scsiprint, CFARGS_NONE); 177 1.1 bouyer } 178 1.1 bouyer 179 1.1 bouyer void 180 1.88 dsl siop_reset(struct siop_softc *sc) 181 1.1 bouyer { 182 1.4 bouyer int i, j; 183 1.31 bouyer struct siop_lunsw *lunsw; 184 1.4 bouyer 185 1.53 bouyer siop_common_reset(&sc->sc_c); 186 1.1 bouyer 187 1.1 bouyer /* copy and patch the script */ 188 1.53 bouyer if (sc->sc_c.features & SF_CHIP_RAM) { 189 1.53 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 0, 190 1.92 tsutsui siop_script, __arraycount(siop_script)); 191 1.92 tsutsui for (j = 0; j < __arraycount(E_abs_msgin_Used); j++) { 192 1.53 bouyer bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 193 1.31 bouyer E_abs_msgin_Used[j] * 4, 194 1.53 bouyer sc->sc_c.sc_scriptaddr + Ent_msgin_space); 195 1.28 bouyer } 196 1.56 bouyer if (sc->sc_c.features & SF_CHIP_LED0) { 197 1.56 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, 198 1.56 bouyer sc->sc_c.sc_ramh, 199 1.56 bouyer Ent_led_on1, siop_led_on, 200 1.92 tsutsui __arraycount(siop_led_on)); 201 1.56 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, 202 1.56 bouyer sc->sc_c.sc_ramh, 203 1.56 bouyer Ent_led_on2, siop_led_on, 204 1.92 tsutsui __arraycount(siop_led_on)); 205 1.56 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, 206 1.56 bouyer sc->sc_c.sc_ramh, 207 1.56 bouyer Ent_led_off, siop_led_off, 208 1.92 tsutsui __arraycount(siop_led_off)); 209 1.56 bouyer } 210 1.17 bouyer } else { 211 1.92 tsutsui for (j = 0; j < __arraycount(siop_script); j++) { 212 1.93 tsutsui sc->sc_c.sc_script[j] = 213 1.86 skrll siop_htoc32(&sc->sc_c, siop_script[j]); 214 1.17 bouyer } 215 1.92 tsutsui for (j = 0; j < __arraycount(E_abs_msgin_Used); j++) { 216 1.53 bouyer sc->sc_c.sc_script[E_abs_msgin_Used[j]] = 217 1.86 skrll siop_htoc32(&sc->sc_c, 218 1.86 skrll sc->sc_c.sc_scriptaddr + Ent_msgin_space); 219 1.17 bouyer } 220 1.56 bouyer if (sc->sc_c.features & SF_CHIP_LED0) { 221 1.92 tsutsui for (j = 0; j < __arraycount(siop_led_on); j++) 222 1.56 bouyer sc->sc_c.sc_script[ 223 1.56 bouyer Ent_led_on1 / sizeof(siop_led_on[0]) + j 224 1.86 skrll ] = siop_htoc32(&sc->sc_c, siop_led_on[j]); 225 1.92 tsutsui for (j = 0; j < __arraycount(siop_led_on); j++) 226 1.56 bouyer sc->sc_c.sc_script[ 227 1.56 bouyer Ent_led_on2 / sizeof(siop_led_on[0]) + j 228 1.86 skrll ] = siop_htoc32(&sc->sc_c, siop_led_on[j]); 229 1.92 tsutsui for (j = 0; j < __arraycount(siop_led_off); j++) 230 1.56 bouyer sc->sc_c.sc_script[ 231 1.92 tsutsui Ent_led_off / sizeof(siop_led_off[0]) + j 232 1.92 tsutsui ] = siop_htoc32(&sc->sc_c, siop_led_off[j]); 233 1.56 bouyer } 234 1.4 bouyer } 235 1.92 tsutsui sc->script_free_lo = __arraycount(siop_script); 236 1.53 bouyer sc->script_free_hi = sc->sc_c.ram_size / 4; 237 1.65 bouyer sc->sc_ntargets = 0; 238 1.1 bouyer 239 1.31 bouyer /* free used and unused lun switches */ 240 1.31 bouyer while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) { 241 1.35 bouyer #ifdef SIOP_DEBUG 242 1.31 bouyer printf("%s: free lunsw at offset %d\n", 243 1.92 tsutsui device_xname(sc->sc_c.sc_dev), lunsw->lunsw_off); 244 1.31 bouyer #endif 245 1.31 bouyer TAILQ_REMOVE(&sc->lunsw_list, lunsw, next); 246 1.31 bouyer free(lunsw, M_DEVBUF); 247 1.31 bouyer } 248 1.31 bouyer TAILQ_INIT(&sc->lunsw_list); 249 1.31 bouyer /* restore reselect switch */ 250 1.53 bouyer for (i = 0; i < sc->sc_c.sc_chan.chan_ntargets; i++) { 251 1.53 bouyer struct siop_target *target; 252 1.53 bouyer if (sc->sc_c.targets[i] == NULL) 253 1.31 bouyer continue; 254 1.35 bouyer #ifdef SIOP_DEBUG 255 1.31 bouyer printf("%s: restore sw for target %d\n", 256 1.92 tsutsui device_xname(sc->sc_c.sc_dev), i); 257 1.31 bouyer #endif 258 1.53 bouyer target = (struct siop_target *)sc->sc_c.targets[i]; 259 1.53 bouyer free(target->lunsw, M_DEVBUF); 260 1.53 bouyer target->lunsw = siop_get_lunsw(sc); 261 1.53 bouyer if (target->lunsw == NULL) { 262 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 263 1.92 tsutsui "can't alloc lunsw for target %d\n", i); 264 1.31 bouyer break; 265 1.28 bouyer } 266 1.31 bouyer siop_add_reselsw(sc, i); 267 1.28 bouyer } 268 1.28 bouyer 269 1.2 bouyer /* start script */ 270 1.53 bouyer if ((sc->sc_c.features & SF_CHIP_RAM) == 0) { 271 1.53 bouyer bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0, 272 1.53 bouyer PAGE_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 273 1.22 bouyer } 274 1.53 bouyer bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, 275 1.53 bouyer sc->sc_c.sc_scriptaddr + Ent_reselect); 276 1.1 bouyer } 277 1.1 bouyer 278 1.1 bouyer #if 0 279 1.92 tsutsui #define CALL_SCRIPT(ent) do { \ 280 1.92 tsutsui printf ("start script DSA 0x%lx DSP 0x%lx\n", \ 281 1.92 tsutsui siop_cmd->cmd_c.dsa, \ 282 1.92 tsutsui sc->sc_c.sc_scriptaddr + ent); \ 283 1.92 tsutsui bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, \ 284 1.92 tsutsui SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \ 285 1.92 tsutsui } while (/* CONSTCOND */0) 286 1.1 bouyer #else 287 1.92 tsutsui #define CALL_SCRIPT(ent) do { \ 288 1.92 tsutsui bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, \ 289 1.92 tsutsui SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \ 290 1.92 tsutsui } while (/* CONSTCOND */0) 291 1.1 bouyer #endif 292 1.1 bouyer 293 1.1 bouyer int 294 1.88 dsl siop_intr(void *v) 295 1.1 bouyer { 296 1.1 bouyer struct siop_softc *sc = v; 297 1.7 bouyer struct siop_target *siop_target; 298 1.1 bouyer struct siop_cmd *siop_cmd; 299 1.31 bouyer struct siop_lun *siop_lun; 300 1.1 bouyer struct scsipi_xfer *xs; 301 1.68 christos int istat, sist, sstat1, dstat = 0; /* XXX: gcc */ 302 1.92 tsutsui uint32_t irqcode; 303 1.1 bouyer int need_reset = 0; 304 1.35 bouyer int offset, target, lun, tag; 305 1.2 bouyer bus_addr_t dsa; 306 1.16 bouyer struct siop_cbd *cbdp; 307 1.35 bouyer int freetarget = 0; 308 1.39 bouyer int restart = 0; 309 1.1 bouyer 310 1.53 bouyer istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT); 311 1.2 bouyer if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) 312 1.2 bouyer return 0; 313 1.2 bouyer INCSTAT(siop_stat_intr); 314 1.1 bouyer if (istat & ISTAT_INTF) { 315 1.1 bouyer printf("INTRF\n"); 316 1.53 bouyer bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 317 1.53 bouyer SIOP_ISTAT, ISTAT_INTF); 318 1.1 bouyer } 319 1.60 bouyer if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) == 320 1.60 bouyer (ISTAT_DIP | ISTAT_ABRT)) { 321 1.60 bouyer /* clear abort */ 322 1.60 bouyer bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 323 1.60 bouyer SIOP_ISTAT, 0); 324 1.60 bouyer } 325 1.2 bouyer /* use DSA to find the current siop_cmd */ 326 1.69 matt siop_cmd = NULL; 327 1.53 bouyer dsa = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA); 328 1.69 matt TAILQ_FOREACH(cbdp, &sc->cmds, next) { 329 1.16 bouyer if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr && 330 1.93 tsutsui dsa < cbdp->xferdma->dm_segs[0].ds_addr + PAGE_SIZE) { 331 1.16 bouyer dsa -= cbdp->xferdma->dm_segs[0].ds_addr; 332 1.16 bouyer siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)]; 333 1.16 bouyer siop_table_sync(siop_cmd, 334 1.16 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 335 1.16 bouyer break; 336 1.16 bouyer } 337 1.78 perry } 338 1.31 bouyer if (siop_cmd) { 339 1.53 bouyer xs = siop_cmd->cmd_c.xs; 340 1.53 bouyer siop_target = (struct siop_target *)siop_cmd->cmd_c.siop_target; 341 1.53 bouyer target = siop_cmd->cmd_c.xs->xs_periph->periph_target; 342 1.53 bouyer lun = siop_cmd->cmd_c.xs->xs_periph->periph_lun; 343 1.53 bouyer tag = siop_cmd->cmd_c.tag; 344 1.35 bouyer siop_lun = siop_target->siop_lun[lun]; 345 1.31 bouyer #ifdef DIAGNOSTIC 346 1.53 bouyer if (siop_cmd->cmd_c.status != CMDST_ACTIVE) { 347 1.93 tsutsui printf("siop_cmd (lun %d) for DSA 0x%x " 348 1.45 bouyer "not active (%d)\n", lun, (u_int)dsa, 349 1.53 bouyer siop_cmd->cmd_c.status); 350 1.31 bouyer xs = NULL; 351 1.31 bouyer siop_target = NULL; 352 1.35 bouyer target = -1; 353 1.31 bouyer lun = -1; 354 1.35 bouyer tag = -1; 355 1.31 bouyer siop_lun = NULL; 356 1.31 bouyer siop_cmd = NULL; 357 1.35 bouyer } else if (siop_lun->siop_tag[tag].active != siop_cmd) { 358 1.35 bouyer printf("siop_cmd (lun %d tag %d) not in siop_lun " 359 1.35 bouyer "active (%p != %p)\n", lun, tag, siop_cmd, 360 1.35 bouyer siop_lun->siop_tag[tag].active); 361 1.31 bouyer } 362 1.31 bouyer #endif 363 1.31 bouyer } else { 364 1.31 bouyer xs = NULL; 365 1.31 bouyer siop_target = NULL; 366 1.35 bouyer target = -1; 367 1.31 bouyer lun = -1; 368 1.35 bouyer tag = -1; 369 1.31 bouyer siop_lun = NULL; 370 1.31 bouyer } 371 1.1 bouyer if (istat & ISTAT_DIP) { 372 1.53 bouyer dstat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 373 1.53 bouyer SIOP_DSTAT); 374 1.60 bouyer if (dstat & DSTAT_ABRT) { 375 1.60 bouyer /* was probably generated by a bus reset IOCTL */ 376 1.60 bouyer if ((dstat & DSTAT_DFE) == 0) 377 1.60 bouyer siop_clearfifo(&sc->sc_c); 378 1.60 bouyer goto reset; 379 1.60 bouyer } 380 1.2 bouyer if (dstat & DSTAT_SSI) { 381 1.2 bouyer printf("single step dsp 0x%08x dsa 0x08%x\n", 382 1.53 bouyer (int)(bus_space_read_4(sc->sc_c.sc_rt, 383 1.53 bouyer sc->sc_c.sc_rh, SIOP_DSP) - 384 1.53 bouyer sc->sc_c.sc_scriptaddr), 385 1.53 bouyer bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 386 1.53 bouyer SIOP_DSA)); 387 1.2 bouyer if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 && 388 1.2 bouyer (istat & ISTAT_SIP) == 0) { 389 1.53 bouyer bus_space_write_1(sc->sc_c.sc_rt, 390 1.53 bouyer sc->sc_c.sc_rh, SIOP_DCNTL, 391 1.53 bouyer bus_space_read_1(sc->sc_c.sc_rt, 392 1.53 bouyer sc->sc_c.sc_rh, SIOP_DCNTL) | DCNTL_STD); 393 1.2 bouyer } 394 1.2 bouyer return 1; 395 1.2 bouyer } 396 1.60 bouyer 397 1.2 bouyer if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) { 398 1.1 bouyer printf("DMA IRQ:"); 399 1.1 bouyer if (dstat & DSTAT_IID) 400 1.1 bouyer printf(" Illegal instruction"); 401 1.1 bouyer if (dstat & DSTAT_BF) 402 1.1 bouyer printf(" bus fault"); 403 1.1 bouyer if (dstat & DSTAT_MDPE) 404 1.1 bouyer printf(" parity"); 405 1.1 bouyer if (dstat & DSTAT_DFE) 406 1.66 wiz printf(" DMA fifo empty"); 407 1.60 bouyer else 408 1.60 bouyer siop_clearfifo(&sc->sc_c); 409 1.1 bouyer printf(", DSP=0x%x DSA=0x%x: ", 410 1.53 bouyer (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 411 1.53 bouyer SIOP_DSP) - sc->sc_c.sc_scriptaddr), 412 1.53 bouyer bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA)); 413 1.2 bouyer if (siop_cmd) 414 1.1 bouyer printf("last msg_in=0x%x status=0x%x\n", 415 1.53 bouyer siop_cmd->cmd_tables->msg_in[0], 416 1.86 skrll siop_ctoh32(&sc->sc_c, 417 1.86 skrll siop_cmd->cmd_tables->status)); 418 1.78 perry else 419 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 420 1.92 tsutsui "current DSA invalid\n"); 421 1.1 bouyer need_reset = 1; 422 1.1 bouyer } 423 1.1 bouyer } 424 1.1 bouyer if (istat & ISTAT_SIP) { 425 1.1 bouyer if (istat & ISTAT_DIP) 426 1.8 bouyer delay(10); 427 1.35 bouyer /* 428 1.70 wiz * Can't read sist0 & sist1 independently, or we have to 429 1.35 bouyer * insert delay 430 1.35 bouyer */ 431 1.53 bouyer sist = bus_space_read_2(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 432 1.53 bouyer SIOP_SIST0); 433 1.53 bouyer sstat1 = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 434 1.53 bouyer SIOP_SSTAT1); 435 1.35 bouyer #ifdef SIOP_DEBUG_INTR 436 1.35 bouyer printf("scsi interrupt, sist=0x%x sstat1=0x%x " 437 1.35 bouyer "DSA=0x%x DSP=0x%lx\n", sist, 438 1.53 bouyer bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 439 1.53 bouyer SIOP_SSTAT1), 440 1.53 bouyer bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA), 441 1.53 bouyer (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 442 1.53 bouyer SIOP_DSP) - 443 1.53 bouyer sc->sc_c.sc_scriptaddr)); 444 1.1 bouyer #endif 445 1.35 bouyer if (sist & SIST0_RST) { 446 1.2 bouyer siop_handle_reset(sc); 447 1.2 bouyer /* no table to flush here */ 448 1.1 bouyer return 1; 449 1.1 bouyer } 450 1.35 bouyer if (sist & SIST0_SGE) { 451 1.1 bouyer if (siop_cmd) 452 1.42 bouyer scsipi_printaddr(xs->xs_periph); 453 1.1 bouyer else 454 1.91 tsutsui printf("%s:", device_xname(sc->sc_c.sc_dev)); 455 1.1 bouyer printf("scsi gross error\n"); 456 1.1 bouyer goto reset; 457 1.1 bouyer } 458 1.35 bouyer if ((sist & SIST0_MA) && need_reset == 0) { 459 1.78 perry if (siop_cmd) { 460 1.8 bouyer int scratcha0; 461 1.53 bouyer dstat = bus_space_read_1(sc->sc_c.sc_rt, 462 1.53 bouyer sc->sc_c.sc_rh, SIOP_DSTAT); 463 1.3 bouyer /* 464 1.3 bouyer * first restore DSA, in case we were in a S/G 465 1.3 bouyer * operation. 466 1.3 bouyer */ 467 1.53 bouyer bus_space_write_4(sc->sc_c.sc_rt, 468 1.53 bouyer sc->sc_c.sc_rh, 469 1.53 bouyer SIOP_DSA, siop_cmd->cmd_c.dsa); 470 1.53 bouyer scratcha0 = bus_space_read_1(sc->sc_c.sc_rt, 471 1.53 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA); 472 1.1 bouyer switch (sstat1 & SSTAT1_PHASE_MASK) { 473 1.1 bouyer case SSTAT1_PHASE_STATUS: 474 1.1 bouyer /* 475 1.1 bouyer * previous phase may be aborted for any reason 476 1.1 bouyer * ( for example, the target has less data to 477 1.74 bouyer * transfer than requested). Compute resid and 478 1.74 bouyer * just go to status, the command should 479 1.74 bouyer * terminate. 480 1.1 bouyer */ 481 1.2 bouyer INCSTAT(siop_stat_intr_shortxfer); 482 1.73 bouyer if (scratcha0 & A_flag_data) 483 1.74 bouyer siop_ma(&siop_cmd->cmd_c); 484 1.73 bouyer else if ((dstat & DSTAT_DFE) == 0) 485 1.53 bouyer siop_clearfifo(&sc->sc_c); 486 1.31 bouyer CALL_SCRIPT(Ent_status); 487 1.1 bouyer return 1; 488 1.1 bouyer case SSTAT1_PHASE_MSGIN: 489 1.74 bouyer /* 490 1.74 bouyer * target may be ready to disconnect 491 1.74 bouyer * Compute resid which would be used later 492 1.74 bouyer * if a save data pointer is needed. 493 1.74 bouyer */ 494 1.2 bouyer INCSTAT(siop_stat_intr_xferdisc); 495 1.8 bouyer if (scratcha0 & A_flag_data) 496 1.74 bouyer siop_ma(&siop_cmd->cmd_c); 497 1.8 bouyer else if ((dstat & DSTAT_DFE) == 0) 498 1.53 bouyer siop_clearfifo(&sc->sc_c); 499 1.53 bouyer bus_space_write_1(sc->sc_c.sc_rt, 500 1.53 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA, 501 1.8 bouyer scratcha0 & ~A_flag_data); 502 1.1 bouyer CALL_SCRIPT(Ent_msgin); 503 1.1 bouyer return 1; 504 1.1 bouyer } 505 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 506 1.92 tsutsui "unexpected phase mismatch %d\n", 507 1.1 bouyer sstat1 & SSTAT1_PHASE_MASK); 508 1.1 bouyer } else { 509 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 510 1.92 tsutsui "phase mismatch without command\n"); 511 1.1 bouyer } 512 1.1 bouyer need_reset = 1; 513 1.1 bouyer } 514 1.35 bouyer if (sist & SIST0_PAR) { 515 1.1 bouyer /* parity error, reset */ 516 1.1 bouyer if (siop_cmd) 517 1.42 bouyer scsipi_printaddr(xs->xs_periph); 518 1.1 bouyer else 519 1.91 tsutsui printf("%s:", device_xname(sc->sc_c.sc_dev)); 520 1.1 bouyer printf("parity error\n"); 521 1.11 bouyer goto reset; 522 1.1 bouyer } 523 1.35 bouyer if ((sist & (SIST1_STO << 8)) && need_reset == 0) { 524 1.1 bouyer /* selection time out, assume there's no device here */ 525 1.1 bouyer if (siop_cmd) { 526 1.53 bouyer siop_cmd->cmd_c.status = CMDST_DONE; 527 1.1 bouyer xs->error = XS_SELTIMEOUT; 528 1.31 bouyer freetarget = 1; 529 1.1 bouyer goto end; 530 1.1 bouyer } else { 531 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 532 1.92 tsutsui "selection timeout without " 533 1.87 cegger "command\n"); 534 1.1 bouyer need_reset = 1; 535 1.1 bouyer } 536 1.1 bouyer } 537 1.35 bouyer if (sist & SIST0_UDC) { 538 1.1 bouyer /* 539 1.1 bouyer * unexpected disconnect. Usually the target signals 540 1.1 bouyer * a fatal condition this way. Attempt to get sense. 541 1.1 bouyer */ 542 1.36 bouyer if (siop_cmd) { 543 1.53 bouyer siop_cmd->cmd_tables->status = 544 1.86 skrll siop_htoc32(&sc->sc_c, SCSI_CHECK); 545 1.36 bouyer goto end; 546 1.36 bouyer } 547 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 548 1.92 tsutsui "unexpected disconnect without " 549 1.87 cegger "command\n"); 550 1.2 bouyer goto reset; 551 1.1 bouyer } 552 1.35 bouyer if (sist & (SIST1_SBMC << 8)) { 553 1.20 bouyer /* SCSI bus mode change */ 554 1.53 bouyer if (siop_modechange(&sc->sc_c) == 0 || need_reset == 1) 555 1.20 bouyer goto reset; 556 1.20 bouyer if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { 557 1.20 bouyer /* 558 1.20 bouyer * we have a script interrupt, it will 559 1.20 bouyer * restart the script. 560 1.20 bouyer */ 561 1.20 bouyer goto scintr; 562 1.20 bouyer } 563 1.20 bouyer /* 564 1.104 andvar * else we have to restart it ourselves, at the 565 1.20 bouyer * interrupted instruction. 566 1.20 bouyer */ 567 1.53 bouyer bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 568 1.53 bouyer SIOP_DSP, 569 1.53 bouyer bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 570 1.20 bouyer SIOP_DSP) - 8); 571 1.20 bouyer return 1; 572 1.20 bouyer } 573 1.70 wiz /* Else it's an unhandled exception (for now). */ 574 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 575 1.92 tsutsui "unhandled scsi interrupt, sist=0x%x sstat1=0x%x " 576 1.87 cegger "DSA=0x%x DSP=0x%x\n", sist, 577 1.53 bouyer bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 578 1.53 bouyer SIOP_SSTAT1), 579 1.53 bouyer bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA), 580 1.53 bouyer (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 581 1.53 bouyer SIOP_DSP) - sc->sc_c.sc_scriptaddr)); 582 1.1 bouyer if (siop_cmd) { 583 1.53 bouyer siop_cmd->cmd_c.status = CMDST_DONE; 584 1.1 bouyer xs->error = XS_SELTIMEOUT; 585 1.1 bouyer goto end; 586 1.1 bouyer } 587 1.1 bouyer need_reset = 1; 588 1.1 bouyer } 589 1.1 bouyer if (need_reset) { 590 1.1 bouyer reset: 591 1.1 bouyer /* fatal error, reset the bus */ 592 1.53 bouyer siop_resetbus(&sc->sc_c); 593 1.2 bouyer /* no table to flush here */ 594 1.1 bouyer return 1; 595 1.1 bouyer } 596 1.1 bouyer 597 1.20 bouyer scintr: 598 1.1 bouyer if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ 599 1.53 bouyer irqcode = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 600 1.1 bouyer SIOP_DSPS); 601 1.35 bouyer #ifdef SIOP_DEBUG_INTR 602 1.2 bouyer printf("script interrupt 0x%x\n", irqcode); 603 1.2 bouyer #endif 604 1.2 bouyer /* 605 1.31 bouyer * no command, or an inactive command is only valid for a 606 1.31 bouyer * reselect interrupt 607 1.2 bouyer */ 608 1.31 bouyer if ((irqcode & 0x80) == 0) { 609 1.31 bouyer if (siop_cmd == NULL) { 610 1.93 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 611 1.92 tsutsui "script interrupt (0x%x) with " 612 1.92 tsutsui "invalid DSA !!!\n", 613 1.87 cegger irqcode); 614 1.31 bouyer goto reset; 615 1.31 bouyer } 616 1.53 bouyer if (siop_cmd->cmd_c.status != CMDST_ACTIVE) { 617 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 618 1.92 tsutsui "command with invalid status " 619 1.31 bouyer "(IRQ code 0x%x current status %d) !\n", 620 1.53 bouyer irqcode, siop_cmd->cmd_c.status); 621 1.31 bouyer xs = NULL; 622 1.31 bouyer } 623 1.7 bouyer } 624 1.1 bouyer switch(irqcode) { 625 1.1 bouyer case A_int_err: 626 1.2 bouyer printf("error, DSP=0x%x\n", 627 1.53 bouyer (int)(bus_space_read_4(sc->sc_c.sc_rt, 628 1.92 tsutsui sc->sc_c.sc_rh, SIOP_DSP) - 629 1.92 tsutsui sc->sc_c.sc_scriptaddr)); 630 1.2 bouyer if (xs) { 631 1.2 bouyer xs->error = XS_SELTIMEOUT; 632 1.2 bouyer goto end; 633 1.2 bouyer } else { 634 1.2 bouyer goto reset; 635 1.2 bouyer } 636 1.31 bouyer case A_int_reseltarg: 637 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 638 1.92 tsutsui "reselect with invalid target\n"); 639 1.31 bouyer goto reset; 640 1.78 perry case A_int_resellun: 641 1.35 bouyer INCSTAT(siop_stat_intr_lunresel); 642 1.53 bouyer target = bus_space_read_1(sc->sc_c.sc_rt, 643 1.53 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA) & 0xf; 644 1.53 bouyer lun = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 645 1.35 bouyer SIOP_SCRATCHA + 1); 646 1.53 bouyer tag = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 647 1.35 bouyer SIOP_SCRATCHA + 2); 648 1.53 bouyer siop_target = 649 1.53 bouyer (struct siop_target *)sc->sc_c.targets[target]; 650 1.35 bouyer if (siop_target == NULL) { 651 1.53 bouyer printf("%s: reselect with invalid target %d\n", 652 1.91 tsutsui device_xname(sc->sc_c.sc_dev), target); 653 1.35 bouyer goto reset; 654 1.35 bouyer } 655 1.35 bouyer siop_lun = siop_target->siop_lun[lun]; 656 1.35 bouyer if (siop_lun == NULL) { 657 1.35 bouyer printf("%s: target %d reselect with invalid " 658 1.91 tsutsui "lun %d\n", device_xname(sc->sc_c.sc_dev), 659 1.35 bouyer target, lun); 660 1.35 bouyer goto reset; 661 1.35 bouyer } 662 1.35 bouyer if (siop_lun->siop_tag[tag].active == NULL) { 663 1.35 bouyer printf("%s: target %d lun %d tag %d reselect " 664 1.53 bouyer "without command\n", 665 1.91 tsutsui device_xname(sc->sc_c.sc_dev), 666 1.35 bouyer target, lun, tag); 667 1.35 bouyer goto reset; 668 1.35 bouyer } 669 1.35 bouyer siop_cmd = siop_lun->siop_tag[tag].active; 670 1.53 bouyer bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 671 1.53 bouyer SIOP_DSP, siop_cmd->cmd_c.dsa + 672 1.53 bouyer sizeof(struct siop_common_xfer) + 673 1.35 bouyer Ent_ldsa_reload_dsa); 674 1.38 bouyer siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); 675 1.35 bouyer return 1; 676 1.31 bouyer case A_int_reseltag: 677 1.31 bouyer printf("%s: reselect with invalid tag\n", 678 1.92 tsutsui device_xname(sc->sc_c.sc_dev)); 679 1.31 bouyer goto reset; 680 1.1 bouyer case A_int_msgin: 681 1.31 bouyer { 682 1.53 bouyer int msgin = bus_space_read_1(sc->sc_c.sc_rt, 683 1.53 bouyer sc->sc_c.sc_rh, SIOP_SFBR); 684 1.92 tsutsui 685 1.31 bouyer if (msgin == MSG_MESSAGE_REJECT) { 686 1.8 bouyer int msg, extmsg; 687 1.53 bouyer if (siop_cmd->cmd_tables->msg_out[0] & 0x80) { 688 1.8 bouyer /* 689 1.8 bouyer * message was part of a identify + 690 1.63 wiz * something else. Identify shouldn't 691 1.8 bouyer * have been rejected. 692 1.8 bouyer */ 693 1.53 bouyer msg = 694 1.53 bouyer siop_cmd->cmd_tables->msg_out[1]; 695 1.8 bouyer extmsg = 696 1.53 bouyer siop_cmd->cmd_tables->msg_out[3]; 697 1.8 bouyer } else { 698 1.53 bouyer msg = siop_cmd->cmd_tables->msg_out[0]; 699 1.8 bouyer extmsg = 700 1.53 bouyer siop_cmd->cmd_tables->msg_out[2]; 701 1.8 bouyer } 702 1.8 bouyer if (msg == MSG_MESSAGE_REJECT) { 703 1.2 bouyer /* MSG_REJECT for a MSG_REJECT !*/ 704 1.9 bouyer if (xs) 705 1.42 bouyer scsipi_printaddr(xs->xs_periph); 706 1.9 bouyer else 707 1.92 tsutsui printf("%s: ", device_xname( 708 1.92 tsutsui sc->sc_c.sc_dev)); 709 1.9 bouyer printf("our reject message was " 710 1.9 bouyer "rejected\n"); 711 1.2 bouyer goto reset; 712 1.2 bouyer } 713 1.8 bouyer if (msg == MSG_EXTENDED && 714 1.8 bouyer extmsg == MSG_EXT_WDTR) { 715 1.9 bouyer /* WDTR rejected, initiate sync */ 716 1.53 bouyer if ((siop_target->target_c.flags & 717 1.53 bouyer TARF_SYNC) == 0) { 718 1.53 bouyer siop_target->target_c.status = 719 1.53 bouyer TARST_OK; 720 1.53 bouyer siop_update_xfer_mode(&sc->sc_c, 721 1.42 bouyer target); 722 1.26 bouyer /* no table to flush here */ 723 1.26 bouyer CALL_SCRIPT(Ent_msgin_ack); 724 1.26 bouyer return 1; 725 1.26 bouyer } 726 1.53 bouyer siop_target->target_c.status = 727 1.53 bouyer TARST_SYNC_NEG; 728 1.53 bouyer siop_sdtr_msg(&siop_cmd->cmd_c, 0, 729 1.58 bouyer sc->sc_c.st_minsync, 730 1.58 bouyer sc->sc_c.maxoff); 731 1.9 bouyer siop_table_sync(siop_cmd, 732 1.9 bouyer BUS_DMASYNC_PREREAD | 733 1.9 bouyer BUS_DMASYNC_PREWRITE); 734 1.9 bouyer CALL_SCRIPT(Ent_send_msgout); 735 1.9 bouyer return 1; 736 1.8 bouyer } else if (msg == MSG_EXTENDED && 737 1.8 bouyer extmsg == MSG_EXT_SDTR) { 738 1.7 bouyer /* sync rejected */ 739 1.53 bouyer siop_target->target_c.offset = 0; 740 1.53 bouyer siop_target->target_c.period = 0; 741 1.53 bouyer siop_target->target_c.status = TARST_OK; 742 1.53 bouyer siop_update_xfer_mode(&sc->sc_c, 743 1.53 bouyer target); 744 1.9 bouyer /* no table to flush here */ 745 1.9 bouyer CALL_SCRIPT(Ent_msgin_ack); 746 1.9 bouyer return 1; 747 1.78 perry } else if (msg == MSG_SIMPLE_Q_TAG || 748 1.35 bouyer msg == MSG_HEAD_OF_Q_TAG || 749 1.35 bouyer msg == MSG_ORDERED_Q_TAG) { 750 1.35 bouyer if (siop_handle_qtag_reject( 751 1.35 bouyer siop_cmd) == -1) 752 1.35 bouyer goto reset; 753 1.35 bouyer CALL_SCRIPT(Ent_msgin_ack); 754 1.35 bouyer return 1; 755 1.9 bouyer } 756 1.9 bouyer if (xs) 757 1.42 bouyer scsipi_printaddr(xs->xs_periph); 758 1.9 bouyer else 759 1.53 bouyer printf("%s: ", 760 1.91 tsutsui device_xname(sc->sc_c.sc_dev)); 761 1.9 bouyer if (msg == MSG_EXTENDED) { 762 1.9 bouyer printf("scsi message reject, extended " 763 1.9 bouyer "message sent was 0x%x\n", extmsg); 764 1.9 bouyer } else { 765 1.9 bouyer printf("scsi message reject, message " 766 1.9 bouyer "sent was 0x%x\n", msg); 767 1.7 bouyer } 768 1.2 bouyer /* no table to flush here */ 769 1.2 bouyer CALL_SCRIPT(Ent_msgin_ack); 770 1.2 bouyer return 1; 771 1.2 bouyer } 772 1.75 bouyer if (msgin == MSG_IGN_WIDE_RESIDUE) { 773 1.75 bouyer /* use the extmsgdata table to get the second byte */ 774 1.75 bouyer siop_cmd->cmd_tables->t_extmsgdata.count = 775 1.86 skrll siop_htoc32(&sc->sc_c, 1); 776 1.75 bouyer siop_table_sync(siop_cmd, 777 1.75 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 778 1.75 bouyer CALL_SCRIPT(Ent_get_extmsgdata); 779 1.76 bouyer return 1; 780 1.75 bouyer } 781 1.9 bouyer if (xs) 782 1.42 bouyer scsipi_printaddr(xs->xs_periph); 783 1.9 bouyer else 784 1.91 tsutsui printf("%s: ", device_xname(sc->sc_c.sc_dev)); 785 1.8 bouyer printf("unhandled message 0x%x\n", 786 1.53 bouyer siop_cmd->cmd_tables->msg_in[0]); 787 1.53 bouyer siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT; 788 1.86 skrll siop_cmd->cmd_tables->t_msgout.count = 789 1.86 skrll siop_htoc32(&sc->sc_c, 1); 790 1.2 bouyer siop_table_sync(siop_cmd, 791 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 792 1.2 bouyer CALL_SCRIPT(Ent_send_msgout); 793 1.2 bouyer return 1; 794 1.31 bouyer } 795 1.2 bouyer case A_int_extmsgin: 796 1.35 bouyer #ifdef SIOP_DEBUG_INTR 797 1.2 bouyer printf("extended message: msg 0x%x len %d\n", 798 1.78 perry siop_cmd->cmd_tables->msg_in[2], 799 1.53 bouyer siop_cmd->cmd_tables->msg_in[1]); 800 1.2 bouyer #endif 801 1.57 bouyer if (siop_cmd->cmd_tables->msg_in[1] > 802 1.57 bouyer sizeof(siop_cmd->cmd_tables->msg_in) - 2) 803 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 804 1.92 tsutsui "extended message too big (%d)\n", 805 1.53 bouyer siop_cmd->cmd_tables->msg_in[1]); 806 1.53 bouyer siop_cmd->cmd_tables->t_extmsgdata.count = 807 1.86 skrll siop_htoc32(&sc->sc_c, 808 1.86 skrll siop_cmd->cmd_tables->msg_in[1] - 1); 809 1.2 bouyer siop_table_sync(siop_cmd, 810 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 811 1.2 bouyer CALL_SCRIPT(Ent_get_extmsgdata); 812 1.2 bouyer return 1; 813 1.2 bouyer case A_int_extmsgdata: 814 1.35 bouyer #ifdef SIOP_DEBUG_INTR 815 1.2 bouyer { 816 1.2 bouyer int i; 817 1.2 bouyer printf("extended message: 0x%x, data:", 818 1.53 bouyer siop_cmd->cmd_tables->msg_in[2]); 819 1.53 bouyer for (i = 3; i < 2 + siop_cmd->cmd_tables->msg_in[1]; 820 1.2 bouyer i++) 821 1.2 bouyer printf(" 0x%x", 822 1.53 bouyer siop_cmd->cmd_tables->msg_in[i]); 823 1.2 bouyer printf("\n"); 824 1.2 bouyer } 825 1.2 bouyer #endif 826 1.75 bouyer if (siop_cmd->cmd_tables->msg_in[0] == 827 1.75 bouyer MSG_IGN_WIDE_RESIDUE) { 828 1.75 bouyer /* we got the second byte of MSG_IGN_WIDE_RESIDUE */ 829 1.75 bouyer if (siop_cmd->cmd_tables->msg_in[3] != 1) 830 1.75 bouyer printf("MSG_IGN_WIDE_RESIDUE: " 831 1.75 bouyer "bad len %d\n", 832 1.75 bouyer siop_cmd->cmd_tables->msg_in[3]); 833 1.75 bouyer switch (siop_iwr(&siop_cmd->cmd_c)) { 834 1.75 bouyer case SIOP_NEG_MSGOUT: 835 1.75 bouyer siop_table_sync(siop_cmd, 836 1.75 bouyer BUS_DMASYNC_PREREAD | 837 1.75 bouyer BUS_DMASYNC_PREWRITE); 838 1.75 bouyer CALL_SCRIPT(Ent_send_msgout); 839 1.75 bouyer return(1); 840 1.75 bouyer case SIOP_NEG_ACK: 841 1.75 bouyer CALL_SCRIPT(Ent_msgin_ack); 842 1.75 bouyer return(1); 843 1.75 bouyer default: 844 1.75 bouyer panic("invalid retval from " 845 1.75 bouyer "siop_iwr()"); 846 1.75 bouyer } 847 1.75 bouyer return(1); 848 1.75 bouyer } 849 1.53 bouyer if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) { 850 1.53 bouyer switch (siop_wdtr_neg(&siop_cmd->cmd_c)) { 851 1.14 bouyer case SIOP_NEG_MSGOUT: 852 1.31 bouyer siop_update_scntl3(sc, 853 1.53 bouyer siop_cmd->cmd_c.siop_target); 854 1.14 bouyer siop_table_sync(siop_cmd, 855 1.14 bouyer BUS_DMASYNC_PREREAD | 856 1.14 bouyer BUS_DMASYNC_PREWRITE); 857 1.14 bouyer CALL_SCRIPT(Ent_send_msgout); 858 1.31 bouyer return(1); 859 1.26 bouyer case SIOP_NEG_ACK: 860 1.31 bouyer siop_update_scntl3(sc, 861 1.53 bouyer siop_cmd->cmd_c.siop_target); 862 1.26 bouyer CALL_SCRIPT(Ent_msgin_ack); 863 1.31 bouyer return(1); 864 1.14 bouyer default: 865 1.14 bouyer panic("invalid retval from " 866 1.14 bouyer "siop_wdtr_neg()"); 867 1.14 bouyer } 868 1.7 bouyer return(1); 869 1.7 bouyer } 870 1.53 bouyer if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) { 871 1.53 bouyer switch (siop_sdtr_neg(&siop_cmd->cmd_c)) { 872 1.14 bouyer case SIOP_NEG_MSGOUT: 873 1.31 bouyer siop_update_scntl3(sc, 874 1.53 bouyer siop_cmd->cmd_c.siop_target); 875 1.14 bouyer siop_table_sync(siop_cmd, 876 1.14 bouyer BUS_DMASYNC_PREREAD | 877 1.14 bouyer BUS_DMASYNC_PREWRITE); 878 1.14 bouyer CALL_SCRIPT(Ent_send_msgout); 879 1.31 bouyer return(1); 880 1.14 bouyer case SIOP_NEG_ACK: 881 1.31 bouyer siop_update_scntl3(sc, 882 1.53 bouyer siop_cmd->cmd_c.siop_target); 883 1.14 bouyer CALL_SCRIPT(Ent_msgin_ack); 884 1.31 bouyer return(1); 885 1.14 bouyer default: 886 1.14 bouyer panic("invalid retval from " 887 1.99 gson "siop_sdtr_neg()"); 888 1.14 bouyer } 889 1.7 bouyer return(1); 890 1.2 bouyer } 891 1.7 bouyer /* send a message reject */ 892 1.53 bouyer siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT; 893 1.86 skrll siop_cmd->cmd_tables->t_msgout.count = 894 1.86 skrll siop_htoc32(&sc->sc_c, 1); 895 1.2 bouyer siop_table_sync(siop_cmd, 896 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 897 1.2 bouyer CALL_SCRIPT(Ent_send_msgout); 898 1.2 bouyer return 1; 899 1.1 bouyer case A_int_disc: 900 1.2 bouyer INCSTAT(siop_stat_intr_sdp); 901 1.53 bouyer offset = bus_space_read_1(sc->sc_c.sc_rt, 902 1.53 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); 903 1.35 bouyer #ifdef SIOP_DEBUG_DR 904 1.1 bouyer printf("disconnect offset %d\n", offset); 905 1.1 bouyer #endif 906 1.74 bouyer siop_sdp(&siop_cmd->cmd_c, offset); 907 1.79 bouyer /* we start again with no offset */ 908 1.79 bouyer siop_cmd->saved_offset = SIOP_NOOFFSET; 909 1.74 bouyer siop_table_sync(siop_cmd, 910 1.74 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 911 1.31 bouyer CALL_SCRIPT(Ent_script_sched); 912 1.1 bouyer return 1; 913 1.79 bouyer case A_int_saveoffset: 914 1.79 bouyer INCSTAT(siop_stat_intr_saveoffset); 915 1.79 bouyer offset = bus_space_read_1(sc->sc_c.sc_rt, 916 1.79 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); 917 1.79 bouyer #ifdef SIOP_DEBUG_DR 918 1.79 bouyer printf("saveoffset offset %d\n", offset); 919 1.79 bouyer #endif 920 1.79 bouyer siop_cmd->saved_offset = offset; 921 1.79 bouyer CALL_SCRIPT(Ent_script_sched); 922 1.79 bouyer return 1; 923 1.1 bouyer case A_int_resfail: 924 1.1 bouyer printf("reselect failed\n"); 925 1.31 bouyer CALL_SCRIPT(Ent_script_sched); 926 1.1 bouyer return 1; 927 1.1 bouyer case A_int_done: 928 1.2 bouyer if (xs == NULL) { 929 1.8 bouyer printf("%s: done without command, DSA=0x%lx\n", 930 1.91 tsutsui device_xname(sc->sc_c.sc_dev), 931 1.53 bouyer (u_long)siop_cmd->cmd_c.dsa); 932 1.53 bouyer siop_cmd->cmd_c.status = CMDST_FREE; 933 1.31 bouyer CALL_SCRIPT(Ent_script_sched); 934 1.2 bouyer return 1; 935 1.2 bouyer } 936 1.35 bouyer #ifdef SIOP_DEBUG_INTR 937 1.8 bouyer printf("done, DSA=0x%lx target id 0x%x last msg " 938 1.92 tsutsui "in=0x%x status=0x%x\n", 939 1.92 tsutsui (u_long)siop_cmd->cmd_c.dsa, 940 1.86 skrll siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->id), 941 1.53 bouyer siop_cmd->cmd_tables->msg_in[0], 942 1.86 skrll siop_ctoh32(&sc->sc_c, 943 1.86 skrll siop_cmd->cmd_tables->status)); 944 1.1 bouyer #endif 945 1.2 bouyer INCSTAT(siop_stat_intr_done); 946 1.74 bouyer /* update resid. */ 947 1.73 bouyer offset = bus_space_read_1(sc->sc_c.sc_rt, 948 1.73 bouyer sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); 949 1.79 bouyer /* 950 1.79 bouyer * if we got a disconnect between the last data phase 951 1.79 bouyer * and the status phase, offset will be 0. In this 952 1.79 bouyer * case, siop_cmd->saved_offset will have the proper 953 1.79 bouyer * value if it got updated by the controller 954 1.79 bouyer */ 955 1.93 tsutsui if (offset == 0 && 956 1.79 bouyer siop_cmd->saved_offset != SIOP_NOOFFSET) 957 1.79 bouyer offset = siop_cmd->saved_offset; 958 1.74 bouyer siop_update_resid(&siop_cmd->cmd_c, offset); 959 1.53 bouyer siop_cmd->cmd_c.status = CMDST_DONE; 960 1.1 bouyer goto end; 961 1.1 bouyer default: 962 1.1 bouyer printf("unknown irqcode %x\n", irqcode); 963 1.35 bouyer if (xs) { 964 1.35 bouyer xs->error = XS_SELTIMEOUT; 965 1.35 bouyer goto end; 966 1.35 bouyer } 967 1.35 bouyer goto reset; 968 1.1 bouyer } 969 1.1 bouyer return 1; 970 1.1 bouyer } 971 1.100 gson /* 972 1.105 andvar * We just shouldn't get there, but on some KVM virtual hosts, 973 1.100 gson * we do - see PR 48277. 974 1.100 gson */ 975 1.100 gson printf("siop_intr: I shouldn't be there !\n"); 976 1.100 gson return 1; 977 1.67 simonb 978 1.1 bouyer end: 979 1.39 bouyer /* 980 1.39 bouyer * restart the script now if command completed properly 981 1.42 bouyer * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the 982 1.42 bouyer * queue 983 1.39 bouyer */ 984 1.86 skrll xs->status = siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->status); 985 1.42 bouyer if (xs->status == SCSI_OK) 986 1.39 bouyer CALL_SCRIPT(Ent_script_sched); 987 1.39 bouyer else 988 1.39 bouyer restart = 1; 989 1.35 bouyer siop_lun->siop_tag[tag].active = NULL; 990 1.44 bouyer siop_scsicmd_end(siop_cmd); 991 1.53 bouyer if (freetarget && siop_target->target_c.status == TARST_PROBING) 992 1.44 bouyer siop_del_dev(sc, target, lun); 993 1.44 bouyer if (restart) 994 1.44 bouyer CALL_SCRIPT(Ent_script_sched); 995 1.42 bouyer if (sc->sc_flags & SCF_CHAN_NOSLOT) { 996 1.42 bouyer /* a command terminated, so we have free slots now */ 997 1.42 bouyer sc->sc_flags &= ~SCF_CHAN_NOSLOT; 998 1.53 bouyer scsipi_channel_thaw(&sc->sc_c.sc_chan, 1); 999 1.2 bouyer } 1000 1.78 perry 1001 1.2 bouyer return 1; 1002 1.2 bouyer } 1003 1.2 bouyer 1004 1.2 bouyer void 1005 1.88 dsl siop_scsicmd_end(struct siop_cmd *siop_cmd) 1006 1.2 bouyer { 1007 1.53 bouyer struct scsipi_xfer *xs = siop_cmd->cmd_c.xs; 1008 1.53 bouyer struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; 1009 1.2 bouyer 1010 1.42 bouyer switch(xs->status) { 1011 1.36 bouyer case SCSI_OK: 1012 1.42 bouyer xs->error = XS_NOERROR; 1013 1.36 bouyer break; 1014 1.36 bouyer case SCSI_BUSY: 1015 1.36 bouyer xs->error = XS_BUSY; 1016 1.36 bouyer break; 1017 1.36 bouyer case SCSI_CHECK: 1018 1.42 bouyer xs->error = XS_BUSY; 1019 1.42 bouyer /* remove commands in the queue and scheduler */ 1020 1.42 bouyer siop_unqueue(sc, xs->xs_periph->periph_target, 1021 1.42 bouyer xs->xs_periph->periph_lun); 1022 1.36 bouyer break; 1023 1.36 bouyer case SCSI_QUEUE_FULL: 1024 1.36 bouyer INCSTAT(siop_stat_intr_qfull); 1025 1.36 bouyer #ifdef SIOP_DEBUG 1026 1.53 bouyer printf("%s:%d:%d: queue full (tag %d)\n", 1027 1.91 tsutsui device_xname(sc->sc_c.sc_dev), 1028 1.42 bouyer xs->xs_periph->periph_target, 1029 1.53 bouyer xs->xs_periph->periph_lun, siop_cmd->cmd_c.tag); 1030 1.36 bouyer #endif 1031 1.42 bouyer xs->error = XS_BUSY; 1032 1.42 bouyer break; 1033 1.36 bouyer case SCSI_SIOP_NOCHECK: 1034 1.36 bouyer /* 1035 1.36 bouyer * don't check status, xs->error is already valid 1036 1.36 bouyer */ 1037 1.36 bouyer break; 1038 1.36 bouyer case SCSI_SIOP_NOSTATUS: 1039 1.36 bouyer /* 1040 1.36 bouyer * the status byte was not updated, cmd was 1041 1.36 bouyer * aborted 1042 1.36 bouyer */ 1043 1.36 bouyer xs->error = XS_SELTIMEOUT; 1044 1.36 bouyer break; 1045 1.36 bouyer default: 1046 1.62 bouyer scsipi_printaddr(xs->xs_periph); 1047 1.62 bouyer printf("invalid status code %d\n", xs->status); 1048 1.36 bouyer xs->error = XS_DRIVER_STUFFUP; 1049 1.36 bouyer } 1050 1.42 bouyer if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 1051 1.92 tsutsui bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, 1052 1.92 tsutsui 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize, 1053 1.1 bouyer (xs->xs_control & XS_CTL_DATA_IN) ? 1054 1.1 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1055 1.92 tsutsui bus_dmamap_unload(sc->sc_c.sc_dmat, 1056 1.92 tsutsui siop_cmd->cmd_c.dmamap_data); 1057 1.1 bouyer } 1058 1.53 bouyer bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd); 1059 1.84 martin if ((xs->xs_control & XS_CTL_POLL) == 0) 1060 1.84 martin callout_stop(&xs->xs_callout); 1061 1.53 bouyer siop_cmd->cmd_c.status = CMDST_FREE; 1062 1.42 bouyer TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); 1063 1.74 bouyer #if 0 1064 1.74 bouyer if (xs->resid != 0) 1065 1.74 bouyer printf("resid %d datalen %d\n", xs->resid, xs->datalen); 1066 1.74 bouyer #endif 1067 1.92 tsutsui scsipi_done(xs); 1068 1.42 bouyer } 1069 1.42 bouyer 1070 1.42 bouyer void 1071 1.88 dsl siop_unqueue(struct siop_softc *sc, int target, int lun) 1072 1.42 bouyer { 1073 1.93 tsutsui int slot, tag; 1074 1.42 bouyer struct siop_cmd *siop_cmd; 1075 1.53 bouyer struct siop_lun *siop_lun = 1076 1.53 bouyer ((struct siop_target *)sc->sc_c.targets[target])->siop_lun[lun]; 1077 1.42 bouyer 1078 1.42 bouyer /* first make sure to read valid data */ 1079 1.42 bouyer siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1080 1.42 bouyer 1081 1.42 bouyer for (tag = 1; tag < SIOP_NTAG; tag++) { 1082 1.42 bouyer /* look for commands in the scheduler, not yet started */ 1083 1.78 perry if (siop_lun->siop_tag[tag].active == NULL) 1084 1.42 bouyer continue; 1085 1.42 bouyer siop_cmd = siop_lun->siop_tag[tag].active; 1086 1.42 bouyer for (slot = 0; slot <= sc->sc_currschedslot; slot++) { 1087 1.42 bouyer if (siop_script_read(sc, 1088 1.42 bouyer (Ent_script_sched_slot0 / 4) + slot * 2 + 1) == 1089 1.53 bouyer siop_cmd->cmd_c.dsa + 1090 1.53 bouyer sizeof(struct siop_common_xfer) + 1091 1.42 bouyer Ent_ldsa_select) 1092 1.42 bouyer break; 1093 1.42 bouyer } 1094 1.42 bouyer if (slot > sc->sc_currschedslot) 1095 1.42 bouyer continue; /* didn't find it */ 1096 1.42 bouyer if (siop_script_read(sc, 1097 1.42 bouyer (Ent_script_sched_slot0 / 4) + slot * 2) == 0x80000000) 1098 1.42 bouyer continue; /* already started */ 1099 1.42 bouyer /* clear the slot */ 1100 1.42 bouyer siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2, 1101 1.42 bouyer 0x80000000); 1102 1.42 bouyer /* ask to requeue */ 1103 1.53 bouyer siop_cmd->cmd_c.xs->error = XS_REQUEUE; 1104 1.53 bouyer siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK; 1105 1.42 bouyer siop_lun->siop_tag[tag].active = NULL; 1106 1.42 bouyer siop_scsicmd_end(siop_cmd); 1107 1.42 bouyer } 1108 1.42 bouyer /* update sc_currschedslot */ 1109 1.42 bouyer sc->sc_currschedslot = 0; 1110 1.42 bouyer for (slot = SIOP_NSLOTS - 1; slot >= 0; slot--) { 1111 1.42 bouyer if (siop_script_read(sc, 1112 1.42 bouyer (Ent_script_sched_slot0 / 4) + slot * 2) != 0x80000000) 1113 1.42 bouyer sc->sc_currschedslot = slot; 1114 1.42 bouyer } 1115 1.7 bouyer } 1116 1.7 bouyer 1117 1.2 bouyer /* 1118 1.31 bouyer * handle a rejected queue tag message: the command will run untagged, 1119 1.31 bouyer * has to adjust the reselect script. 1120 1.31 bouyer */ 1121 1.31 bouyer int 1122 1.88 dsl siop_handle_qtag_reject(struct siop_cmd *siop_cmd) 1123 1.31 bouyer { 1124 1.53 bouyer struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; 1125 1.53 bouyer int target = siop_cmd->cmd_c.xs->xs_periph->periph_target; 1126 1.53 bouyer int lun = siop_cmd->cmd_c.xs->xs_periph->periph_lun; 1127 1.53 bouyer int tag = siop_cmd->cmd_tables->msg_out[2]; 1128 1.53 bouyer struct siop_lun *siop_lun = 1129 1.53 bouyer ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun]; 1130 1.31 bouyer 1131 1.36 bouyer #ifdef SIOP_DEBUG 1132 1.36 bouyer printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n", 1133 1.92 tsutsui device_xname(sc->sc_c.sc_dev), target, lun, tag, 1134 1.92 tsutsui siop_cmd->cmd_c.tag, 1135 1.53 bouyer siop_cmd->cmd_c.status); 1136 1.36 bouyer #endif 1137 1.36 bouyer 1138 1.35 bouyer if (siop_lun->siop_tag[0].active != NULL) { 1139 1.36 bouyer printf("%s: untagged command already running for target %d " 1140 1.91 tsutsui "lun %d (status %d)\n", device_xname(sc->sc_c.sc_dev), 1141 1.53 bouyer target, lun, siop_lun->siop_tag[0].active->cmd_c.status); 1142 1.35 bouyer return -1; 1143 1.35 bouyer } 1144 1.35 bouyer /* clear tag slot */ 1145 1.35 bouyer siop_lun->siop_tag[tag].active = NULL; 1146 1.35 bouyer /* add command to non-tagged slot */ 1147 1.35 bouyer siop_lun->siop_tag[0].active = siop_cmd; 1148 1.53 bouyer siop_cmd->cmd_c.tag = 0; 1149 1.35 bouyer /* adjust reselect script if there is one */ 1150 1.35 bouyer if (siop_lun->siop_tag[0].reseloff > 0) { 1151 1.35 bouyer siop_script_write(sc, 1152 1.35 bouyer siop_lun->siop_tag[0].reseloff + 1, 1153 1.53 bouyer siop_cmd->cmd_c.dsa + sizeof(struct siop_common_xfer) + 1154 1.35 bouyer Ent_ldsa_reload_dsa); 1155 1.38 bouyer siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); 1156 1.35 bouyer } 1157 1.31 bouyer return 0; 1158 1.31 bouyer } 1159 1.31 bouyer 1160 1.31 bouyer /* 1161 1.31 bouyer * handle a bus reset: reset chip, unqueue all active commands, free all 1162 1.70 wiz * target struct and report lossage to upper layer. 1163 1.103 andvar * As the upper layer may requeue immediately we have to first store 1164 1.2 bouyer * all active commands in a temporary queue. 1165 1.2 bouyer */ 1166 1.2 bouyer void 1167 1.88 dsl siop_handle_reset(struct siop_softc *sc) 1168 1.2 bouyer { 1169 1.42 bouyer struct siop_cmd *siop_cmd; 1170 1.31 bouyer struct siop_lun *siop_lun; 1171 1.35 bouyer int target, lun, tag; 1172 1.92 tsutsui 1173 1.2 bouyer /* 1174 1.2 bouyer * scsi bus reset. reset the chip and restart 1175 1.2 bouyer * the queue. Need to clean up all active commands 1176 1.2 bouyer */ 1177 1.91 tsutsui printf("%s: scsi bus reset\n", device_xname(sc->sc_c.sc_dev)); 1178 1.2 bouyer /* stop, reset and restart the chip */ 1179 1.2 bouyer siop_reset(sc); 1180 1.42 bouyer if (sc->sc_flags & SCF_CHAN_NOSLOT) { 1181 1.42 bouyer /* chip has been reset, all slots are free now */ 1182 1.42 bouyer sc->sc_flags &= ~SCF_CHAN_NOSLOT; 1183 1.53 bouyer scsipi_channel_thaw(&sc->sc_c.sc_chan, 1); 1184 1.42 bouyer } 1185 1.36 bouyer /* 1186 1.70 wiz * Process all commands: first commands being executed 1187 1.36 bouyer */ 1188 1.53 bouyer for (target = 0; target < sc->sc_c.sc_chan.chan_ntargets; 1189 1.7 bouyer target++) { 1190 1.53 bouyer if (sc->sc_c.targets[target] == NULL) 1191 1.7 bouyer continue; 1192 1.7 bouyer for (lun = 0; lun < 8; lun++) { 1193 1.78 perry struct siop_target *siop_target = 1194 1.53 bouyer (struct siop_target *)sc->sc_c.targets[target]; 1195 1.53 bouyer siop_lun = siop_target->siop_lun[lun]; 1196 1.31 bouyer if (siop_lun == NULL) 1197 1.31 bouyer continue; 1198 1.35 bouyer for (tag = 0; tag < 1199 1.53 bouyer ((sc->sc_c.targets[target]->flags & TARF_TAG) ? 1200 1.36 bouyer SIOP_NTAG : 1); 1201 1.35 bouyer tag++) { 1202 1.35 bouyer siop_cmd = siop_lun->siop_tag[tag].active; 1203 1.35 bouyer if (siop_cmd == NULL) 1204 1.35 bouyer continue; 1205 1.53 bouyer scsipi_printaddr(siop_cmd->cmd_c.xs->xs_periph); 1206 1.42 bouyer printf("command with tag id %d reset\n", tag); 1207 1.53 bouyer siop_cmd->cmd_c.xs->error = 1208 1.53 bouyer (siop_cmd->cmd_c.flags & CMDFL_TIMEOUT) ? 1209 1.93 tsutsui XS_TIMEOUT : XS_RESET; 1210 1.53 bouyer siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK; 1211 1.35 bouyer siop_lun->siop_tag[tag].active = NULL; 1212 1.53 bouyer siop_cmd->cmd_c.status = CMDST_DONE; 1213 1.42 bouyer siop_scsicmd_end(siop_cmd); 1214 1.35 bouyer } 1215 1.2 bouyer } 1216 1.53 bouyer sc->sc_c.targets[target]->status = TARST_ASYNC; 1217 1.53 bouyer sc->sc_c.targets[target]->flags &= ~TARF_ISWIDE; 1218 1.53 bouyer sc->sc_c.targets[target]->period = 1219 1.53 bouyer sc->sc_c.targets[target]->offset = 0; 1220 1.53 bouyer siop_update_xfer_mode(&sc->sc_c, target); 1221 1.31 bouyer } 1222 1.42 bouyer 1223 1.53 bouyer scsipi_async_event(&sc->sc_c.sc_chan, ASYNC_EVENT_RESET, NULL); 1224 1.1 bouyer } 1225 1.1 bouyer 1226 1.42 bouyer void 1227 1.92 tsutsui siop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 1228 1.92 tsutsui void *arg) 1229 1.42 bouyer { 1230 1.1 bouyer struct scsipi_xfer *xs; 1231 1.42 bouyer struct scsipi_periph *periph; 1232 1.91 tsutsui struct siop_softc *sc = device_private(chan->chan_adapter->adapt_dev); 1233 1.1 bouyer struct siop_cmd *siop_cmd; 1234 1.53 bouyer struct siop_target *siop_target; 1235 1.1 bouyer int s, error, i; 1236 1.42 bouyer int target; 1237 1.42 bouyer int lun; 1238 1.42 bouyer 1239 1.42 bouyer switch (req) { 1240 1.42 bouyer case ADAPTER_REQ_RUN_XFER: 1241 1.42 bouyer xs = arg; 1242 1.42 bouyer periph = xs->xs_periph; 1243 1.42 bouyer target = periph->periph_target; 1244 1.42 bouyer lun = periph->periph_lun; 1245 1.1 bouyer 1246 1.42 bouyer s = splbio(); 1247 1.35 bouyer #ifdef SIOP_DEBUG_SCHED 1248 1.42 bouyer printf("starting cmd for %d:%d\n", target, lun); 1249 1.1 bouyer #endif 1250 1.42 bouyer siop_cmd = TAILQ_FIRST(&sc->free_list); 1251 1.42 bouyer if (siop_cmd == NULL) { 1252 1.42 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1253 1.42 bouyer scsipi_done(xs); 1254 1.42 bouyer splx(s); 1255 1.42 bouyer return; 1256 1.16 bouyer } 1257 1.47 bouyer TAILQ_REMOVE(&sc->free_list, siop_cmd, next); 1258 1.1 bouyer #ifdef DIAGNOSTIC 1259 1.53 bouyer if (siop_cmd->cmd_c.status != CMDST_FREE) 1260 1.42 bouyer panic("siop_scsicmd: new cmd not free"); 1261 1.1 bouyer #endif 1262 1.92 tsutsui siop_target = (struct siop_target *)sc->sc_c.targets[target]; 1263 1.53 bouyer if (siop_target == NULL) { 1264 1.35 bouyer #ifdef SIOP_DEBUG 1265 1.42 bouyer printf("%s: alloc siop_target for target %d\n", 1266 1.92 tsutsui device_xname(sc->sc_c.sc_dev), target); 1267 1.31 bouyer #endif 1268 1.53 bouyer sc->sc_c.targets[target] = 1269 1.42 bouyer malloc(sizeof(struct siop_target), 1270 1.86 skrll M_DEVBUF, M_NOWAIT|M_ZERO); 1271 1.53 bouyer if (sc->sc_c.targets[target] == NULL) { 1272 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1273 1.92 tsutsui "can't malloc memory for " 1274 1.87 cegger "target %d\n", target); 1275 1.42 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1276 1.42 bouyer scsipi_done(xs); 1277 1.95 jakllsch TAILQ_INSERT_TAIL(&sc->free_list, 1278 1.95 jakllsch siop_cmd, next); 1279 1.42 bouyer splx(s); 1280 1.42 bouyer return; 1281 1.42 bouyer } 1282 1.53 bouyer siop_target = 1283 1.92 tsutsui (struct siop_target *)sc->sc_c.targets[target]; 1284 1.53 bouyer siop_target->target_c.status = TARST_PROBING; 1285 1.53 bouyer siop_target->target_c.flags = 0; 1286 1.53 bouyer siop_target->target_c.id = 1287 1.53 bouyer sc->sc_c.clock_div << 24; /* scntl3 */ 1288 1.53 bouyer siop_target->target_c.id |= target << 16; /* id */ 1289 1.53 bouyer /* siop_target->target_c.id |= 0x0 << 8; scxfer is 0 */ 1290 1.42 bouyer 1291 1.42 bouyer /* get a lun switch script */ 1292 1.53 bouyer siop_target->lunsw = siop_get_lunsw(sc); 1293 1.53 bouyer if (siop_target->lunsw == NULL) { 1294 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1295 1.92 tsutsui "can't alloc lunsw for target %d\n", 1296 1.87 cegger target); 1297 1.42 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1298 1.42 bouyer scsipi_done(xs); 1299 1.95 jakllsch TAILQ_INSERT_TAIL(&sc->free_list, 1300 1.95 jakllsch siop_cmd, next); 1301 1.42 bouyer splx(s); 1302 1.42 bouyer return; 1303 1.42 bouyer } 1304 1.42 bouyer for (i=0; i < 8; i++) 1305 1.53 bouyer siop_target->siop_lun[i] = NULL; 1306 1.42 bouyer siop_add_reselsw(sc, target); 1307 1.7 bouyer } 1308 1.53 bouyer if (siop_target->siop_lun[lun] == NULL) { 1309 1.53 bouyer siop_target->siop_lun[lun] = 1310 1.49 tsutsui malloc(sizeof(struct siop_lun), M_DEVBUF, 1311 1.49 tsutsui M_NOWAIT|M_ZERO); 1312 1.53 bouyer if (siop_target->siop_lun[lun] == NULL) { 1313 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1314 1.92 tsutsui "can't alloc siop_lun for " 1315 1.42 bouyer "target %d lun %d\n", 1316 1.87 cegger target, lun); 1317 1.42 bouyer xs->error = XS_RESOURCE_SHORTAGE; 1318 1.42 bouyer scsipi_done(xs); 1319 1.95 jakllsch TAILQ_INSERT_TAIL(&sc->free_list, 1320 1.95 jakllsch siop_cmd, next); 1321 1.42 bouyer splx(s); 1322 1.42 bouyer return; 1323 1.42 bouyer } 1324 1.42 bouyer } 1325 1.53 bouyer siop_cmd->cmd_c.siop_target = sc->sc_c.targets[target]; 1326 1.53 bouyer siop_cmd->cmd_c.xs = xs; 1327 1.53 bouyer siop_cmd->cmd_c.flags = 0; 1328 1.53 bouyer siop_cmd->cmd_c.status = CMDST_READY; 1329 1.42 bouyer 1330 1.42 bouyer /* load the DMA maps */ 1331 1.53 bouyer error = bus_dmamap_load(sc->sc_c.sc_dmat, 1332 1.53 bouyer siop_cmd->cmd_c.dmamap_cmd, 1333 1.42 bouyer xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); 1334 1.1 bouyer if (error) { 1335 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1336 1.92 tsutsui "unable to load cmd DMA map: %d\n", 1337 1.87 cegger error); 1338 1.95 jakllsch xs->error = (error == EAGAIN) ? 1339 1.95 jakllsch XS_RESOURCE_SHORTAGE : XS_DRIVER_STUFFUP; 1340 1.42 bouyer scsipi_done(xs); 1341 1.95 jakllsch siop_cmd->cmd_c.status = CMDST_FREE; 1342 1.95 jakllsch TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); 1343 1.31 bouyer splx(s); 1344 1.42 bouyer return; 1345 1.42 bouyer } 1346 1.42 bouyer if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 1347 1.53 bouyer error = bus_dmamap_load(sc->sc_c.sc_dmat, 1348 1.53 bouyer siop_cmd->cmd_c.dmamap_data, xs->data, xs->datalen, 1349 1.46 thorpej NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING | 1350 1.46 thorpej ((xs->xs_control & XS_CTL_DATA_IN) ? 1351 1.46 thorpej BUS_DMA_READ : BUS_DMA_WRITE)); 1352 1.42 bouyer if (error) { 1353 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1354 1.96 jakllsch "unable to load data DMA map: %d\n", 1355 1.87 cegger error); 1356 1.95 jakllsch xs->error = (error == EAGAIN) ? 1357 1.95 jakllsch XS_RESOURCE_SHORTAGE : XS_DRIVER_STUFFUP; 1358 1.42 bouyer scsipi_done(xs); 1359 1.53 bouyer bus_dmamap_unload(sc->sc_c.sc_dmat, 1360 1.53 bouyer siop_cmd->cmd_c.dmamap_cmd); 1361 1.95 jakllsch siop_cmd->cmd_c.status = CMDST_FREE; 1362 1.95 jakllsch TAILQ_INSERT_TAIL(&sc->free_list, 1363 1.95 jakllsch siop_cmd, next); 1364 1.42 bouyer splx(s); 1365 1.42 bouyer return; 1366 1.42 bouyer } 1367 1.53 bouyer bus_dmamap_sync(sc->sc_c.sc_dmat, 1368 1.53 bouyer siop_cmd->cmd_c.dmamap_data, 0, 1369 1.53 bouyer siop_cmd->cmd_c.dmamap_data->dm_mapsize, 1370 1.42 bouyer (xs->xs_control & XS_CTL_DATA_IN) ? 1371 1.42 bouyer BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1372 1.42 bouyer } 1373 1.53 bouyer bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_cmd, 0, 1374 1.53 bouyer siop_cmd->cmd_c.dmamap_cmd->dm_mapsize, 1375 1.53 bouyer BUS_DMASYNC_PREWRITE); 1376 1.42 bouyer 1377 1.55 bouyer if (xs->xs_tag_type) { 1378 1.55 bouyer /* use tag_id + 1, tag 0 is reserved for untagged cmds*/ 1379 1.55 bouyer siop_cmd->cmd_c.tag = xs->xs_tag_id + 1; 1380 1.55 bouyer } else { 1381 1.55 bouyer siop_cmd->cmd_c.tag = 0; 1382 1.55 bouyer } 1383 1.53 bouyer siop_setuptables(&siop_cmd->cmd_c); 1384 1.79 bouyer siop_cmd->saved_offset = SIOP_NOOFFSET; 1385 1.53 bouyer siop_table_sync(siop_cmd, 1386 1.53 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1387 1.42 bouyer siop_start(sc, siop_cmd); 1388 1.42 bouyer if (xs->xs_control & XS_CTL_POLL) { 1389 1.42 bouyer /* poll for command completion */ 1390 1.42 bouyer while ((xs->xs_status & XS_STS_DONE) == 0) { 1391 1.42 bouyer delay(1000); 1392 1.42 bouyer siop_intr(sc); 1393 1.42 bouyer } 1394 1.1 bouyer } 1395 1.42 bouyer splx(s); 1396 1.42 bouyer return; 1397 1.1 bouyer 1398 1.42 bouyer case ADAPTER_REQ_GROW_RESOURCES: 1399 1.47 bouyer #ifdef SIOP_DEBUG 1400 1.92 tsutsui printf("%s grow resources (%d)\n", 1401 1.92 tsutsui device_xname(sc->sc_c.sc_dev), 1402 1.53 bouyer sc->sc_c.sc_adapt.adapt_openings); 1403 1.47 bouyer #endif 1404 1.47 bouyer siop_morecbd(sc); 1405 1.42 bouyer return; 1406 1.35 bouyer 1407 1.42 bouyer case ADAPTER_REQ_SET_XFER_MODE: 1408 1.92 tsutsui { 1409 1.42 bouyer struct scsipi_xfer_mode *xm = arg; 1410 1.53 bouyer if (sc->sc_c.targets[xm->xm_target] == NULL) 1411 1.42 bouyer return; 1412 1.42 bouyer s = splbio(); 1413 1.42 bouyer if (xm->xm_mode & PERIPH_CAP_TQING) 1414 1.53 bouyer sc->sc_c.targets[xm->xm_target]->flags |= TARF_TAG; 1415 1.42 bouyer if ((xm->xm_mode & PERIPH_CAP_WIDE16) && 1416 1.53 bouyer (sc->sc_c.features & SF_BUS_WIDE)) 1417 1.53 bouyer sc->sc_c.targets[xm->xm_target]->flags |= TARF_WIDE; 1418 1.42 bouyer if (xm->xm_mode & PERIPH_CAP_SYNC) 1419 1.53 bouyer sc->sc_c.targets[xm->xm_target]->flags |= TARF_SYNC; 1420 1.42 bouyer if ((xm->xm_mode & (PERIPH_CAP_SYNC | PERIPH_CAP_WIDE16)) || 1421 1.53 bouyer sc->sc_c.targets[xm->xm_target]->status == TARST_PROBING) 1422 1.53 bouyer sc->sc_c.targets[xm->xm_target]->status = 1423 1.42 bouyer TARST_ASYNC; 1424 1.42 bouyer 1425 1.53 bouyer for (lun = 0; lun < sc->sc_c.sc_chan.chan_nluns; lun++) { 1426 1.61 thorpej if (scsipi_lookup_periph(chan, 1427 1.61 thorpej xm->xm_target, lun) != NULL) { 1428 1.42 bouyer /* allocate a lun sw entry for this device */ 1429 1.42 bouyer siop_add_dev(sc, xm->xm_target, lun); 1430 1.61 thorpej } 1431 1.31 bouyer } 1432 1.42 bouyer 1433 1.14 bouyer splx(s); 1434 1.92 tsutsui } 1435 1.42 bouyer } 1436 1.1 bouyer } 1437 1.1 bouyer 1438 1.42 bouyer static void 1439 1.88 dsl siop_start(struct siop_softc *sc, struct siop_cmd *siop_cmd) 1440 1.1 bouyer { 1441 1.31 bouyer struct siop_lun *siop_lun; 1442 1.53 bouyer struct siop_xfer *siop_xfer; 1443 1.92 tsutsui uint32_t dsa; 1444 1.1 bouyer int timeout; 1445 1.42 bouyer int target, lun, slot; 1446 1.2 bouyer 1447 1.2 bouyer /* 1448 1.2 bouyer * first make sure to read valid data 1449 1.2 bouyer */ 1450 1.35 bouyer siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1451 1.1 bouyer 1452 1.2 bouyer /* 1453 1.10 bouyer * The queue management here is a bit tricky: the script always looks 1454 1.78 perry * at the slot from first to last, so if we always use the first 1455 1.10 bouyer * free slot commands can stay at the tail of the queue ~forever. 1456 1.10 bouyer * The algorithm used here is to restart from the head when we know 1457 1.10 bouyer * that the queue is empty, and only add commands after the last one. 1458 1.10 bouyer * When we're at the end of the queue wait for the script to clear it. 1459 1.10 bouyer * The best thing to do here would be to implement a circular queue, 1460 1.10 bouyer * but using only 53c720 features this can be "interesting". 1461 1.10 bouyer * A mid-way solution could be to implement 2 queues and swap orders. 1462 1.2 bouyer */ 1463 1.29 bouyer slot = sc->sc_currschedslot; 1464 1.10 bouyer /* 1465 1.35 bouyer * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is 1466 1.35 bouyer * free. As this is the last used slot, all previous slots are free, 1467 1.42 bouyer * we can restart from 0. 1468 1.10 bouyer */ 1469 1.35 bouyer if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) == 1470 1.35 bouyer 0x80000000) { 1471 1.42 bouyer slot = sc->sc_currschedslot = 0; 1472 1.10 bouyer } else { 1473 1.10 bouyer slot++; 1474 1.10 bouyer } 1475 1.53 bouyer target = siop_cmd->cmd_c.xs->xs_periph->periph_target; 1476 1.53 bouyer lun = siop_cmd->cmd_c.xs->xs_periph->periph_lun; 1477 1.53 bouyer siop_lun = 1478 1.53 bouyer ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun]; 1479 1.42 bouyer /* if non-tagged command active, panic: this shouldn't happen */ 1480 1.42 bouyer if (siop_lun->siop_tag[0].active != NULL) { 1481 1.42 bouyer panic("siop_start: tagged cmd while untagged running"); 1482 1.42 bouyer } 1483 1.31 bouyer #ifdef DIAGNOSTIC 1484 1.42 bouyer /* sanity check the tag if needed */ 1485 1.53 bouyer if (siop_cmd->cmd_c.flags & CMDFL_TAG) { 1486 1.53 bouyer if (siop_lun->siop_tag[siop_cmd->cmd_c.tag].active != NULL) 1487 1.42 bouyer panic("siop_start: tag not free"); 1488 1.53 bouyer if (siop_cmd->cmd_c.tag >= SIOP_NTAG) { 1489 1.53 bouyer scsipi_printaddr(siop_cmd->cmd_c.xs->xs_periph); 1490 1.53 bouyer printf(": tag id %d\n", siop_cmd->cmd_c.tag); 1491 1.42 bouyer panic("siop_start: invalid tag id"); 1492 1.42 bouyer } 1493 1.42 bouyer } 1494 1.42 bouyer #endif 1495 1.42 bouyer /* 1496 1.42 bouyer * find a free scheduler slot and load it. 1497 1.42 bouyer */ 1498 1.42 bouyer for (; slot < SIOP_NSLOTS; slot++) { 1499 1.35 bouyer /* 1500 1.42 bouyer * If cmd if 0x80000000 the slot is free 1501 1.35 bouyer */ 1502 1.42 bouyer if (siop_script_read(sc, 1503 1.42 bouyer (Ent_script_sched_slot0 / 4) + slot * 2) == 1504 1.42 bouyer 0x80000000) 1505 1.42 bouyer break; 1506 1.42 bouyer } 1507 1.42 bouyer if (slot == SIOP_NSLOTS) { 1508 1.39 bouyer /* 1509 1.42 bouyer * no more free slot, no need to continue. freeze the queue 1510 1.42 bouyer * and requeue this command. 1511 1.39 bouyer */ 1512 1.53 bouyer scsipi_channel_freeze(&sc->sc_c.sc_chan, 1); 1513 1.42 bouyer sc->sc_flags |= SCF_CHAN_NOSLOT; 1514 1.53 bouyer siop_cmd->cmd_c.xs->error = XS_REQUEUE; 1515 1.53 bouyer siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK; 1516 1.42 bouyer siop_scsicmd_end(siop_cmd); 1517 1.42 bouyer return; 1518 1.42 bouyer } 1519 1.35 bouyer #ifdef SIOP_DEBUG_SCHED 1520 1.42 bouyer printf("using slot %d for DSA 0x%lx\n", slot, 1521 1.53 bouyer (u_long)siop_cmd->cmd_c.dsa); 1522 1.31 bouyer #endif 1523 1.42 bouyer /* mark command as active */ 1524 1.53 bouyer if (siop_cmd->cmd_c.status == CMDST_READY) 1525 1.53 bouyer siop_cmd->cmd_c.status = CMDST_ACTIVE; 1526 1.42 bouyer else 1527 1.42 bouyer panic("siop_start: bad status"); 1528 1.53 bouyer siop_lun->siop_tag[siop_cmd->cmd_c.tag].active = siop_cmd; 1529 1.42 bouyer /* patch scripts with DSA addr */ 1530 1.53 bouyer dsa = siop_cmd->cmd_c.dsa; 1531 1.42 bouyer /* first reselect switch, if we have an entry */ 1532 1.53 bouyer if (siop_lun->siop_tag[siop_cmd->cmd_c.tag].reseloff > 0) 1533 1.42 bouyer siop_script_write(sc, 1534 1.53 bouyer siop_lun->siop_tag[siop_cmd->cmd_c.tag].reseloff + 1, 1535 1.53 bouyer dsa + sizeof(struct siop_common_xfer) + 1536 1.42 bouyer Ent_ldsa_reload_dsa); 1537 1.42 bouyer /* CMD script: MOVE MEMORY addr */ 1538 1.53 bouyer siop_xfer = (struct siop_xfer*)siop_cmd->cmd_tables; 1539 1.78 perry siop_xfer->resel[E_ldsa_abs_slot_Used[0]] = 1540 1.92 tsutsui siop_htoc32(&sc->sc_c, sc->sc_c.sc_scriptaddr + 1541 1.92 tsutsui Ent_script_sched_slot0 + slot * 8); 1542 1.86 skrll siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); 1543 1.42 bouyer /* scheduler slot: JUMP ldsa_select */ 1544 1.42 bouyer siop_script_write(sc, 1545 1.42 bouyer (Ent_script_sched_slot0 / 4) + slot * 2 + 1, 1546 1.53 bouyer dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_select); 1547 1.42 bouyer /* handle timeout */ 1548 1.53 bouyer if ((siop_cmd->cmd_c.xs->xs_control & XS_CTL_POLL) == 0) { 1549 1.42 bouyer /* start exire timer */ 1550 1.53 bouyer timeout = mstohz(siop_cmd->cmd_c.xs->timeout); 1551 1.42 bouyer if (timeout == 0) 1552 1.42 bouyer timeout = 1; 1553 1.53 bouyer callout_reset( &siop_cmd->cmd_c.xs->xs_callout, 1554 1.42 bouyer timeout, siop_timeout, siop_cmd); 1555 1.36 bouyer } 1556 1.42 bouyer /* 1557 1.42 bouyer * Change JUMP cmd so that this slot will be handled 1558 1.42 bouyer */ 1559 1.42 bouyer siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2, 1560 1.42 bouyer 0x80080000); 1561 1.42 bouyer sc->sc_currschedslot = slot; 1562 1.36 bouyer 1563 1.2 bouyer /* make sure SCRIPT processor will read valid data */ 1564 1.35 bouyer siop_script_sync(sc,BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1565 1.2 bouyer /* Signal script it has some work to do */ 1566 1.53 bouyer bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, 1567 1.53 bouyer SIOP_ISTAT, ISTAT_SIGP); 1568 1.2 bouyer /* and wait for IRQ */ 1569 1.1 bouyer } 1570 1.1 bouyer 1571 1.1 bouyer void 1572 1.88 dsl siop_timeout(void *v) 1573 1.1 bouyer { 1574 1.1 bouyer struct siop_cmd *siop_cmd = v; 1575 1.53 bouyer struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc; 1576 1.1 bouyer int s; 1577 1.1 bouyer 1578 1.53 bouyer scsipi_printaddr(siop_cmd->cmd_c.xs->xs_periph); 1579 1.72 bouyer printf("command timeout, CDB: "); 1580 1.72 bouyer scsipi_print_cdb(siop_cmd->cmd_c.xs->cmd); 1581 1.71 bouyer printf("\n"); 1582 1.1 bouyer 1583 1.1 bouyer s = splbio(); 1584 1.1 bouyer /* reset the scsi bus */ 1585 1.53 bouyer siop_resetbus(&sc->sc_c); 1586 1.1 bouyer 1587 1.12 soren /* deactivate callout */ 1588 1.53 bouyer callout_stop(&siop_cmd->cmd_c.xs->xs_callout); 1589 1.31 bouyer /* mark command as being timed out; siop_intr will handle it */ 1590 1.1 bouyer /* 1591 1.1 bouyer * mark command has being timed out and just return; 1592 1.1 bouyer * the bus reset will generate an interrupt, 1593 1.1 bouyer * it will be handled in siop_intr() 1594 1.1 bouyer */ 1595 1.53 bouyer siop_cmd->cmd_c.flags |= CMDFL_TIMEOUT; 1596 1.1 bouyer splx(s); 1597 1.1 bouyer } 1598 1.2 bouyer 1599 1.2 bouyer void 1600 1.88 dsl siop_dump_script(struct siop_softc *sc) 1601 1.2 bouyer { 1602 1.2 bouyer int i; 1603 1.92 tsutsui 1604 1.37 thorpej for (i = 0; i < PAGE_SIZE / 4; i += 2) { 1605 1.4 bouyer printf("0x%04x: 0x%08x 0x%08x", i * 4, 1606 1.97 jakllsch siop_script_read(sc, i), 1607 1.97 jakllsch siop_script_read(sc, i + 1)); 1608 1.97 jakllsch if ((siop_script_read(sc, i) & 0xe0000000) == 0xc0000000) { 1609 1.2 bouyer i++; 1610 1.97 jakllsch printf(" 0x%08x", siop_script_read(sc, i + 1)); 1611 1.2 bouyer } 1612 1.2 bouyer printf("\n"); 1613 1.2 bouyer } 1614 1.16 bouyer } 1615 1.16 bouyer 1616 1.47 bouyer void 1617 1.88 dsl siop_morecbd(struct siop_softc *sc) 1618 1.16 bouyer { 1619 1.86 skrll int error, off, i, j, s; 1620 1.16 bouyer bus_dma_segment_t seg; 1621 1.16 bouyer int rseg; 1622 1.16 bouyer struct siop_cbd *newcbd; 1623 1.53 bouyer struct siop_xfer *xfer; 1624 1.31 bouyer bus_addr_t dsa; 1625 1.92 tsutsui uint32_t *scr; 1626 1.16 bouyer 1627 1.16 bouyer /* allocate a new list head */ 1628 1.49 tsutsui newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT|M_ZERO); 1629 1.16 bouyer if (newcbd == NULL) { 1630 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1631 1.92 tsutsui "can't allocate memory for command descriptors head\n"); 1632 1.47 bouyer return; 1633 1.16 bouyer } 1634 1.16 bouyer 1635 1.16 bouyer /* allocate cmd list */ 1636 1.49 tsutsui newcbd->cmds = malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, 1637 1.49 tsutsui M_DEVBUF, M_NOWAIT|M_ZERO); 1638 1.16 bouyer if (newcbd->cmds == NULL) { 1639 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1640 1.92 tsutsui "can't allocate memory for command descriptors\n"); 1641 1.16 bouyer goto bad3; 1642 1.16 bouyer } 1643 1.92 tsutsui error = bus_dmamem_alloc(sc->sc_c.sc_dmat, PAGE_SIZE, PAGE_SIZE, 1644 1.92 tsutsui 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 1645 1.16 bouyer if (error) { 1646 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1647 1.92 tsutsui "unable to allocate cbd DMA memory, error = %d\n", 1648 1.87 cegger error); 1649 1.16 bouyer goto bad2; 1650 1.16 bouyer } 1651 1.53 bouyer error = bus_dmamem_map(sc->sc_c.sc_dmat, &seg, rseg, PAGE_SIZE, 1652 1.83 christos (void **)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 1653 1.16 bouyer if (error) { 1654 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1655 1.92 tsutsui "unable to map cbd DMA memory, error = %d\n", 1656 1.87 cegger error); 1657 1.16 bouyer goto bad2; 1658 1.16 bouyer } 1659 1.53 bouyer error = bus_dmamap_create(sc->sc_c.sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0, 1660 1.16 bouyer BUS_DMA_NOWAIT, &newcbd->xferdma); 1661 1.16 bouyer if (error) { 1662 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1663 1.92 tsutsui "unable to create cbd DMA map, error = %d\n", 1664 1.87 cegger error); 1665 1.16 bouyer goto bad1; 1666 1.16 bouyer } 1667 1.92 tsutsui error = bus_dmamap_load(sc->sc_c.sc_dmat, newcbd->xferdma, 1668 1.92 tsutsui newcbd->xfers, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); 1669 1.16 bouyer if (error) { 1670 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1671 1.92 tsutsui "unable to load cbd DMA map, error = %d\n", 1672 1.87 cegger error); 1673 1.16 bouyer goto bad0; 1674 1.16 bouyer } 1675 1.97 jakllsch #ifdef SIOP_DEBUG 1676 1.92 tsutsui printf("%s: alloc newcdb at PHY addr 0x%lx\n", 1677 1.92 tsutsui device_xname(sc->sc_c.sc_dev), 1678 1.31 bouyer (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr); 1679 1.31 bouyer #endif 1680 1.86 skrll off = (sc->sc_c.features & SF_CHIP_BE) ? 3 : 0; 1681 1.16 bouyer for (i = 0; i < SIOP_NCMDPB; i++) { 1682 1.53 bouyer error = bus_dmamap_create(sc->sc_c.sc_dmat, MAXPHYS, SIOP_NSG, 1683 1.16 bouyer MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1684 1.53 bouyer &newcbd->cmds[i].cmd_c.dmamap_data); 1685 1.16 bouyer if (error) { 1686 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1687 1.92 tsutsui "unable to create data DMA map for cbd: " 1688 1.87 cegger "error %d\n", error); 1689 1.16 bouyer goto bad0; 1690 1.16 bouyer } 1691 1.53 bouyer error = bus_dmamap_create(sc->sc_c.sc_dmat, 1692 1.16 bouyer sizeof(struct scsipi_generic), 1, 1693 1.16 bouyer sizeof(struct scsipi_generic), 0, 1694 1.16 bouyer BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1695 1.53 bouyer &newcbd->cmds[i].cmd_c.dmamap_cmd); 1696 1.16 bouyer if (error) { 1697 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1698 1.92 tsutsui "unable to create cmd DMA map for cbd %d\n", error); 1699 1.16 bouyer goto bad0; 1700 1.16 bouyer } 1701 1.53 bouyer newcbd->cmds[i].cmd_c.siop_sc = &sc->sc_c; 1702 1.16 bouyer newcbd->cmds[i].siop_cbdp = newcbd; 1703 1.53 bouyer xfer = &newcbd->xfers[i]; 1704 1.53 bouyer newcbd->cmds[i].cmd_tables = (struct siop_common_xfer *)xfer; 1705 1.53 bouyer memset(newcbd->cmds[i].cmd_tables, 0, sizeof(struct siop_xfer)); 1706 1.53 bouyer dsa = newcbd->xferdma->dm_segs[0].ds_addr + 1707 1.16 bouyer i * sizeof(struct siop_xfer); 1708 1.53 bouyer newcbd->cmds[i].cmd_c.dsa = dsa; 1709 1.53 bouyer newcbd->cmds[i].cmd_c.status = CMDST_FREE; 1710 1.86 skrll xfer->siop_tables.t_msgout.count= siop_htoc32(&sc->sc_c, 1); 1711 1.86 skrll xfer->siop_tables.t_msgout.addr = siop_htoc32(&sc->sc_c, dsa); 1712 1.86 skrll xfer->siop_tables.t_msgin.count= siop_htoc32(&sc->sc_c, 1); 1713 1.86 skrll xfer->siop_tables.t_msgin.addr = siop_htoc32(&sc->sc_c, 1714 1.86 skrll dsa + offsetof(struct siop_common_xfer, msg_in)); 1715 1.86 skrll xfer->siop_tables.t_extmsgin.count= siop_htoc32(&sc->sc_c, 2); 1716 1.86 skrll xfer->siop_tables.t_extmsgin.addr = siop_htoc32(&sc->sc_c, 1717 1.86 skrll dsa + offsetof(struct siop_common_xfer, msg_in) + 1); 1718 1.86 skrll xfer->siop_tables.t_extmsgdata.addr = siop_htoc32(&sc->sc_c, 1719 1.86 skrll dsa + offsetof(struct siop_common_xfer, msg_in) + 3); 1720 1.86 skrll xfer->siop_tables.t_status.count= siop_htoc32(&sc->sc_c, 1); 1721 1.86 skrll xfer->siop_tables.t_status.addr = siop_htoc32(&sc->sc_c, 1722 1.86 skrll dsa + offsetof(struct siop_common_xfer, status) + off); 1723 1.35 bouyer /* The select/reselect script */ 1724 1.53 bouyer scr = &xfer->resel[0]; 1725 1.92 tsutsui for (j = 0; j < __arraycount(load_dsa); j++) 1726 1.86 skrll scr[j] = siop_htoc32(&sc->sc_c, load_dsa[j]); 1727 1.31 bouyer /* 1728 1.31 bouyer * 0x78000000 is a 'move data8 to reg'. data8 is the second 1729 1.31 bouyer * octet, reg offset is the third. 1730 1.31 bouyer */ 1731 1.86 skrll scr[Ent_rdsa0 / 4] = siop_htoc32(&sc->sc_c, 1732 1.86 skrll 0x78100000 | ((dsa & 0x000000ff) << 8)); 1733 1.86 skrll scr[Ent_rdsa1 / 4] = siop_htoc32(&sc->sc_c, 1734 1.86 skrll 0x78110000 | ( dsa & 0x0000ff00 )); 1735 1.86 skrll scr[Ent_rdsa2 / 4] = siop_htoc32(&sc->sc_c, 1736 1.86 skrll 0x78120000 | ((dsa & 0x00ff0000) >> 8)); 1737 1.86 skrll scr[Ent_rdsa3 / 4] = siop_htoc32(&sc->sc_c, 1738 1.86 skrll 0x78130000 | ((dsa & 0xff000000) >> 16)); 1739 1.86 skrll scr[E_ldsa_abs_reselected_Used[0]] = siop_htoc32(&sc->sc_c, 1740 1.86 skrll sc->sc_c.sc_scriptaddr + Ent_reselected); 1741 1.86 skrll scr[E_ldsa_abs_reselect_Used[0]] = siop_htoc32(&sc->sc_c, 1742 1.86 skrll sc->sc_c.sc_scriptaddr + Ent_reselect); 1743 1.86 skrll scr[E_ldsa_abs_selected_Used[0]] = siop_htoc32(&sc->sc_c, 1744 1.86 skrll sc->sc_c.sc_scriptaddr + Ent_selected); 1745 1.86 skrll scr[E_ldsa_abs_data_Used[0]] = siop_htoc32(&sc->sc_c, 1746 1.86 skrll dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data); 1747 1.35 bouyer /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */ 1748 1.86 skrll scr[Ent_ldsa_data / 4] = siop_htoc32(&sc->sc_c, 0x80000000); 1749 1.50 bouyer s = splbio(); 1750 1.16 bouyer TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next); 1751 1.50 bouyer splx(s); 1752 1.35 bouyer #ifdef SIOP_DEBUG 1753 1.83 christos printf("tables[%d]: in=0x%x out=0x%x status=0x%x\n", i, 1754 1.86 skrll siop_ctoh32(&sc->sc_c, 1755 1.86 skrll newcbd->cmds[i].cmd_tables->t_msgin.addr), 1756 1.86 skrll siop_ctoh32(&sc->sc_c, 1757 1.86 skrll newcbd->cmds[i].cmd_tables->t_msgout.addr), 1758 1.86 skrll siop_ctoh32(&sc->sc_c, 1759 1.86 skrll newcbd->cmds[i].cmd_tables->t_status.addr)); 1760 1.16 bouyer #endif 1761 1.16 bouyer } 1762 1.50 bouyer s = splbio(); 1763 1.16 bouyer TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next); 1764 1.53 bouyer sc->sc_c.sc_adapt.adapt_openings += SIOP_NCMDPB; 1765 1.50 bouyer splx(s); 1766 1.47 bouyer return; 1767 1.16 bouyer bad0: 1768 1.53 bouyer bus_dmamap_unload(sc->sc_c.sc_dmat, newcbd->xferdma); 1769 1.53 bouyer bus_dmamap_destroy(sc->sc_c.sc_dmat, newcbd->xferdma); 1770 1.16 bouyer bad1: 1771 1.53 bouyer bus_dmamem_free(sc->sc_c.sc_dmat, &seg, rseg); 1772 1.16 bouyer bad2: 1773 1.16 bouyer free(newcbd->cmds, M_DEVBUF); 1774 1.16 bouyer bad3: 1775 1.16 bouyer free(newcbd, M_DEVBUF); 1776 1.2 bouyer } 1777 1.2 bouyer 1778 1.31 bouyer struct siop_lunsw * 1779 1.88 dsl siop_get_lunsw(struct siop_softc *sc) 1780 1.31 bouyer { 1781 1.31 bouyer struct siop_lunsw *lunsw; 1782 1.31 bouyer int i; 1783 1.31 bouyer 1784 1.92 tsutsui if (sc->script_free_lo + __arraycount(lun_switch) >= sc->script_free_hi) 1785 1.35 bouyer return NULL; 1786 1.31 bouyer lunsw = TAILQ_FIRST(&sc->lunsw_list); 1787 1.31 bouyer if (lunsw != NULL) { 1788 1.35 bouyer #ifdef SIOP_DEBUG 1789 1.31 bouyer printf("siop_get_lunsw got lunsw at offset %d\n", 1790 1.31 bouyer lunsw->lunsw_off); 1791 1.31 bouyer #endif 1792 1.31 bouyer TAILQ_REMOVE(&sc->lunsw_list, lunsw, next); 1793 1.31 bouyer return lunsw; 1794 1.31 bouyer } 1795 1.49 tsutsui lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT|M_ZERO); 1796 1.31 bouyer if (lunsw == NULL) 1797 1.31 bouyer return NULL; 1798 1.35 bouyer #ifdef SIOP_DEBUG 1799 1.35 bouyer printf("allocating lunsw at offset %d\n", sc->script_free_lo); 1800 1.31 bouyer #endif 1801 1.53 bouyer if (sc->sc_c.features & SF_CHIP_RAM) { 1802 1.53 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 1803 1.35 bouyer sc->script_free_lo * 4, lun_switch, 1804 1.92 tsutsui __arraycount(lun_switch)); 1805 1.53 bouyer bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 1806 1.35 bouyer (sc->script_free_lo + E_abs_lunsw_return_Used[0]) * 4, 1807 1.53 bouyer sc->sc_c.sc_scriptaddr + Ent_lunsw_return); 1808 1.31 bouyer } else { 1809 1.92 tsutsui for (i = 0; i < __arraycount(lun_switch); i++) 1810 1.53 bouyer sc->sc_c.sc_script[sc->script_free_lo + i] = 1811 1.86 skrll siop_htoc32(&sc->sc_c, lun_switch[i]); 1812 1.53 bouyer sc->sc_c.sc_script[ 1813 1.78 perry sc->script_free_lo + E_abs_lunsw_return_Used[0]] = 1814 1.86 skrll siop_htoc32(&sc->sc_c, 1815 1.86 skrll sc->sc_c.sc_scriptaddr + Ent_lunsw_return); 1816 1.31 bouyer } 1817 1.35 bouyer lunsw->lunsw_off = sc->script_free_lo; 1818 1.92 tsutsui lunsw->lunsw_size = __arraycount(lun_switch); 1819 1.35 bouyer sc->script_free_lo += lunsw->lunsw_size; 1820 1.35 bouyer siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1821 1.31 bouyer return lunsw; 1822 1.31 bouyer } 1823 1.31 bouyer 1824 1.31 bouyer void 1825 1.88 dsl siop_add_reselsw(struct siop_softc *sc, int target) 1826 1.31 bouyer { 1827 1.65 bouyer int i, j; 1828 1.53 bouyer struct siop_target *siop_target; 1829 1.31 bouyer struct siop_lun *siop_lun; 1830 1.53 bouyer 1831 1.53 bouyer siop_target = (struct siop_target *)sc->sc_c.targets[target]; 1832 1.32 bouyer /* 1833 1.32 bouyer * add an entry to resel switch 1834 1.32 bouyer */ 1835 1.32 bouyer siop_script_sync(sc, BUS_DMASYNC_POSTWRITE); 1836 1.31 bouyer for (i = 0; i < 15; i++) { 1837 1.53 bouyer siop_target->reseloff = Ent_resel_targ0 / 4 + i * 2; 1838 1.53 bouyer if ((siop_script_read(sc, siop_target->reseloff) & 0xff) 1839 1.31 bouyer == 0xff) { /* it's free */ 1840 1.35 bouyer #ifdef SIOP_DEBUG 1841 1.31 bouyer printf("siop: target %d slot %d offset %d\n", 1842 1.53 bouyer target, i, siop_target->reseloff); 1843 1.31 bouyer #endif 1844 1.31 bouyer /* JUMP abs_foo, IF target | 0x80; */ 1845 1.53 bouyer siop_script_write(sc, siop_target->reseloff, 1846 1.31 bouyer 0x800c0080 | target); 1847 1.53 bouyer siop_script_write(sc, siop_target->reseloff + 1, 1848 1.53 bouyer sc->sc_c.sc_scriptaddr + 1849 1.53 bouyer siop_target->lunsw->lunsw_off * 4 + 1850 1.33 bouyer Ent_lun_switch_entry); 1851 1.31 bouyer break; 1852 1.31 bouyer } 1853 1.31 bouyer } 1854 1.31 bouyer if (i == 15) /* no free slot, shouldn't happen */ 1855 1.31 bouyer panic("siop: resel switch full"); 1856 1.31 bouyer 1857 1.35 bouyer sc->sc_ntargets++; 1858 1.31 bouyer for (i = 0; i < 8; i++) { 1859 1.53 bouyer siop_lun = siop_target->siop_lun[i]; 1860 1.35 bouyer if (siop_lun == NULL) 1861 1.35 bouyer continue; 1862 1.35 bouyer if (siop_lun->reseloff > 0) { 1863 1.35 bouyer siop_lun->reseloff = 0; 1864 1.65 bouyer for (j = 0; j < SIOP_NTAG; j++) 1865 1.65 bouyer siop_lun->siop_tag[j].reseloff = 0; 1866 1.35 bouyer siop_add_dev(sc, target, i); 1867 1.35 bouyer } 1868 1.31 bouyer } 1869 1.53 bouyer siop_update_scntl3(sc, sc->sc_c.targets[target]); 1870 1.32 bouyer siop_script_sync(sc, BUS_DMASYNC_PREWRITE); 1871 1.31 bouyer } 1872 1.31 bouyer 1873 1.31 bouyer void 1874 1.92 tsutsui siop_update_scntl3(struct siop_softc *sc, 1875 1.92 tsutsui struct siop_common_target *_siop_target) 1876 1.31 bouyer { 1877 1.53 bouyer struct siop_target *siop_target = (struct siop_target *)_siop_target; 1878 1.92 tsutsui 1879 1.31 bouyer /* MOVE target->id >> 24 TO SCNTL3 */ 1880 1.31 bouyer siop_script_write(sc, 1881 1.31 bouyer siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4), 1882 1.53 bouyer 0x78030000 | ((siop_target->target_c.id >> 16) & 0x0000ff00)); 1883 1.31 bouyer /* MOVE target->id >> 8 TO SXFER */ 1884 1.31 bouyer siop_script_write(sc, 1885 1.31 bouyer siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2, 1886 1.53 bouyer 0x78050000 | (siop_target->target_c.id & 0x0000ff00)); 1887 1.32 bouyer siop_script_sync(sc, BUS_DMASYNC_PREWRITE); 1888 1.31 bouyer } 1889 1.31 bouyer 1890 1.35 bouyer void 1891 1.88 dsl siop_add_dev(struct siop_softc *sc, int target, int lun) 1892 1.35 bouyer { 1893 1.35 bouyer struct siop_lunsw *lunsw; 1894 1.53 bouyer struct siop_target *siop_target = 1895 1.53 bouyer (struct siop_target *)sc->sc_c.targets[target]; 1896 1.53 bouyer struct siop_lun *siop_lun = siop_target->siop_lun[lun]; 1897 1.35 bouyer int i, ntargets; 1898 1.35 bouyer 1899 1.35 bouyer if (siop_lun->reseloff > 0) 1900 1.35 bouyer return; 1901 1.53 bouyer lunsw = siop_target->lunsw; 1902 1.35 bouyer if ((lunsw->lunsw_off + lunsw->lunsw_size) < sc->script_free_lo) { 1903 1.35 bouyer /* 1904 1.35 bouyer * can't extend this slot. Probably not worth trying to deal 1905 1.35 bouyer * with this case 1906 1.35 bouyer */ 1907 1.97 jakllsch #ifdef SIOP_DEBUG 1908 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1909 1.92 tsutsui "%d:%d: can't allocate a lun sw slot\n", target, lun); 1910 1.35 bouyer #endif 1911 1.35 bouyer return; 1912 1.35 bouyer } 1913 1.35 bouyer /* count how many free targets we still have to probe */ 1914 1.53 bouyer ntargets = sc->sc_c.sc_chan.chan_ntargets - 1 - sc->sc_ntargets; 1915 1.35 bouyer 1916 1.35 bouyer /* 1917 1.70 wiz * we need 8 bytes for the lun sw additional entry, and 1918 1.35 bouyer * eventually sizeof(tag_switch) for the tag switch entry. 1919 1.64 wiz * Keep enough free space for the free targets that could be 1920 1.35 bouyer * probed later. 1921 1.35 bouyer */ 1922 1.35 bouyer if (sc->script_free_lo + 2 + 1923 1.92 tsutsui (ntargets * __arraycount(lun_switch)) >= 1924 1.53 bouyer ((siop_target->target_c.flags & TARF_TAG) ? 1925 1.92 tsutsui sc->script_free_hi - __arraycount(tag_switch) : 1926 1.35 bouyer sc->script_free_hi)) { 1927 1.35 bouyer /* 1928 1.64 wiz * not enough space, probably not worth dealing with it. 1929 1.35 bouyer * We can hold 13 tagged-queuing capable devices in the 4k RAM. 1930 1.35 bouyer */ 1931 1.97 jakllsch #ifdef SIOP_DEBUG 1932 1.92 tsutsui aprint_error_dev(sc->sc_c.sc_dev, 1933 1.92 tsutsui "%d:%d: not enough memory for a lun sw slot\n", 1934 1.92 tsutsui target, lun); 1935 1.35 bouyer #endif 1936 1.35 bouyer return; 1937 1.35 bouyer } 1938 1.35 bouyer #ifdef SIOP_DEBUG 1939 1.35 bouyer printf("%s:%d:%d: allocate lun sw entry\n", 1940 1.91 tsutsui device_xname(sc->sc_c.sc_dev), target, lun); 1941 1.35 bouyer #endif 1942 1.35 bouyer /* INT int_resellun */ 1943 1.35 bouyer siop_script_write(sc, sc->script_free_lo, 0x98080000); 1944 1.35 bouyer siop_script_write(sc, sc->script_free_lo + 1, A_int_resellun); 1945 1.35 bouyer /* Now the slot entry: JUMP abs_foo, IF lun */ 1946 1.35 bouyer siop_script_write(sc, sc->script_free_lo - 2, 1947 1.35 bouyer 0x800c0000 | lun); 1948 1.35 bouyer siop_script_write(sc, sc->script_free_lo - 1, 0); 1949 1.35 bouyer siop_lun->reseloff = sc->script_free_lo - 2; 1950 1.35 bouyer lunsw->lunsw_size += 2; 1951 1.35 bouyer sc->script_free_lo += 2; 1952 1.53 bouyer if (siop_target->target_c.flags & TARF_TAG) { 1953 1.35 bouyer /* we need a tag switch */ 1954 1.92 tsutsui sc->script_free_hi -= __arraycount(tag_switch); 1955 1.53 bouyer if (sc->sc_c.features & SF_CHIP_RAM) { 1956 1.53 bouyer bus_space_write_region_4(sc->sc_c.sc_ramt, 1957 1.53 bouyer sc->sc_c.sc_ramh, 1958 1.35 bouyer sc->script_free_hi * 4, tag_switch, 1959 1.92 tsutsui __arraycount(tag_switch)); 1960 1.35 bouyer } else { 1961 1.92 tsutsui for(i = 0; i < __arraycount(tag_switch); i++) { 1962 1.78 perry sc->sc_c.sc_script[sc->script_free_hi + i] = 1963 1.86 skrll siop_htoc32(&sc->sc_c, tag_switch[i]); 1964 1.35 bouyer } 1965 1.35 bouyer } 1966 1.78 perry siop_script_write(sc, 1967 1.35 bouyer siop_lun->reseloff + 1, 1968 1.53 bouyer sc->sc_c.sc_scriptaddr + sc->script_free_hi * 4 + 1969 1.35 bouyer Ent_tag_switch_entry); 1970 1.35 bouyer 1971 1.35 bouyer for (i = 0; i < SIOP_NTAG; i++) { 1972 1.35 bouyer siop_lun->siop_tag[i].reseloff = 1973 1.35 bouyer sc->script_free_hi + (Ent_resel_tag0 / 4) + i * 2; 1974 1.35 bouyer } 1975 1.35 bouyer } else { 1976 1.35 bouyer /* non-tag case; just work with the lun switch */ 1977 1.78 perry siop_lun->siop_tag[0].reseloff = 1978 1.53 bouyer siop_target->siop_lun[lun]->reseloff; 1979 1.35 bouyer } 1980 1.35 bouyer siop_script_sync(sc, BUS_DMASYNC_PREWRITE); 1981 1.35 bouyer } 1982 1.35 bouyer 1983 1.35 bouyer void 1984 1.88 dsl siop_del_dev(struct siop_softc *sc, int target, int lun) 1985 1.35 bouyer { 1986 1.35 bouyer int i; 1987 1.53 bouyer struct siop_target *siop_target; 1988 1.87 cegger 1989 1.35 bouyer #ifdef SIOP_DEBUG 1990 1.87 cegger printf("%s:%d:%d: free lun sw entry\n", 1991 1.91 tsutsui device_xname(sc->sc_c.sc_dev), target, lun); 1992 1.35 bouyer #endif 1993 1.53 bouyer if (sc->sc_c.targets[target] == NULL) 1994 1.35 bouyer return; 1995 1.53 bouyer siop_target = (struct siop_target *)sc->sc_c.targets[target]; 1996 1.53 bouyer free(siop_target->siop_lun[lun], M_DEVBUF); 1997 1.53 bouyer siop_target->siop_lun[lun] = NULL; 1998 1.35 bouyer /* XXX compact sw entry too ? */ 1999 1.35 bouyer /* check if we can free the whole target */ 2000 1.35 bouyer for (i = 0; i < 8; i++) { 2001 1.53 bouyer if (siop_target->siop_lun[i] != NULL) 2002 1.35 bouyer return; 2003 1.35 bouyer } 2004 1.35 bouyer #ifdef SIOP_DEBUG 2005 1.35 bouyer printf("%s: free siop_target for target %d lun %d lunsw offset %d\n", 2006 1.91 tsutsui device_xname(sc->sc_c.sc_dev), target, lun, 2007 1.83 christos siop_target->lunsw->lunsw_off); 2008 1.35 bouyer #endif 2009 1.35 bouyer /* 2010 1.35 bouyer * nothing here, free the target struct and resel 2011 1.35 bouyer * switch entry 2012 1.35 bouyer */ 2013 1.53 bouyer siop_script_write(sc, siop_target->reseloff, 0x800c00ff); 2014 1.35 bouyer siop_script_sync(sc, BUS_DMASYNC_PREWRITE); 2015 1.53 bouyer TAILQ_INSERT_TAIL(&sc->lunsw_list, siop_target->lunsw, next); 2016 1.53 bouyer free(sc->sc_c.targets[target], M_DEVBUF); 2017 1.53 bouyer sc->sc_c.targets[target] = NULL; 2018 1.35 bouyer sc->sc_ntargets--; 2019 1.35 bouyer } 2020 1.35 bouyer 2021 1.2 bouyer #ifdef SIOP_STATS 2022 1.2 bouyer void 2023 1.90 cegger siop_printstats(void) 2024 1.2 bouyer { 2025 1.92 tsutsui 2026 1.2 bouyer printf("siop_stat_intr %d\n", siop_stat_intr); 2027 1.2 bouyer printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer); 2028 1.2 bouyer printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc); 2029 1.2 bouyer printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp); 2030 1.79 bouyer printf("siop_stat_intr_saveoffset %d\n", siop_stat_intr_saveoffset); 2031 1.2 bouyer printf("siop_stat_intr_done %d\n", siop_stat_intr_done); 2032 1.35 bouyer printf("siop_stat_intr_lunresel %d\n", siop_stat_intr_lunresel); 2033 1.36 bouyer printf("siop_stat_intr_qfull %d\n", siop_stat_intr_qfull); 2034 1.2 bouyer } 2035 1.2 bouyer #endif 2036