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