siop.c revision 1.23
1/* $NetBSD: siop.c,v 1.23 2000/06/26 14:21:10 mrg 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 <machine/endian.h> 43#include <machine/bus.h> 44 45#include <vm/vm.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#undef DEBUG 60#undef DEBUG_DR 61#undef DEBUG_INTR 62#undef DEBUG_SHED 63#undef DUMP_SCRIPT 64 65#define SIOP_STATS 66 67#ifndef SIOP_DEFAULT_TARGET 68#define SIOP_DEFAULT_TARGET 7 69#endif 70 71/* number of cmd descriptors per block */ 72#define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer)) 73 74void siop_reset __P((struct siop_softc *)); 75void siop_handle_reset __P((struct siop_softc *)); 76void siop_scsicmd_end __P((struct siop_cmd *)); 77void siop_start __P((struct siop_softc *)); 78void siop_timeout __P((void *)); 79int siop_scsicmd __P((struct scsipi_xfer *)); 80void siop_dump_script __P((struct siop_softc *)); 81int siop_morecbd __P((struct siop_softc *)); 82 83struct scsipi_adapter siop_adapter = { 84 0, 85 siop_scsicmd, 86 siop_minphys, 87 siop_ioctl, 88 NULL, 89 NULL, 90}; 91 92struct scsipi_device siop_dev = { 93 NULL, 94 NULL, 95 NULL, 96 NULL, 97}; 98 99#ifdef SIOP_STATS 100static int siop_stat_intr = 0; 101static int siop_stat_intr_shortxfer = 0; 102static int siop_stat_intr_sdp = 0; 103static int siop_stat_intr_done = 0; 104static int siop_stat_intr_reselect = 0; 105static int siop_stat_intr_xferdisc = 0; 106void siop_printstats __P((void)); 107#define INCSTAT(x) x++ 108#else 109#define INCSTAT(x) 110#endif 111 112static __inline__ void siop_table_sync __P((struct siop_cmd *, int)); 113static __inline__ void 114siop_table_sync(siop_cmd, ops) 115 struct siop_cmd *siop_cmd; 116 int ops; 117{ 118 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 119 bus_addr_t offset; 120 121 offset = siop_cmd->dsa - 122 siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr; 123 bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset, 124 sizeof(struct siop_xfer), ops); 125} 126 127static __inline__ void siop_shed_sync __P((struct siop_softc *, int)); 128static __inline__ void 129siop_shed_sync(sc, ops) 130 struct siop_softc *sc; 131 int ops; 132{ 133 bus_dmamap_sync(sc->sc_dmat, sc->sc_sheddma, 0, NBPG, ops); 134} 135 136void 137siop_attach(sc) 138 struct siop_softc *sc; 139{ 140 int error, i; 141 bus_dma_segment_t seg; 142 int rseg; 143 144 /* 145 * Allocate DMA-safe memory for the script and script scheduler 146 * and map it. 147 */ 148 if ((sc->features & SF_CHIP_RAM) == 0) { 149 error = bus_dmamem_alloc(sc->sc_dmat, NBPG, 150 NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 151 if (error) { 152 printf("%s: unable to allocate script DMA memory, " 153 "error = %d\n", sc->sc_dev.dv_xname, error); 154 return; 155 } 156 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG, 157 (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 158 if (error) { 159 printf("%s: unable to map script DMA memory, " 160 "error = %d\n", sc->sc_dev.dv_xname, error); 161 return; 162 } 163 error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, 164 NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma); 165 if (error) { 166 printf("%s: unable to create script DMA map, " 167 "error = %d\n", sc->sc_dev.dv_xname, error); 168 return; 169 } 170 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, 171 sc->sc_script, 172 NBPG, NULL, BUS_DMA_NOWAIT); 173 if (error) { 174 printf("%s: unable to load script DMA map, " 175 "error = %d\n", sc->sc_dev.dv_xname, error); 176 return; 177 } 178 sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr; 179 } 180 error = bus_dmamem_alloc(sc->sc_dmat, NBPG, 181 NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT); 182 if (error) { 183 printf("%s: unable to allocate scheduler DMA memory, " 184 "error = %d\n", sc->sc_dev.dv_xname, error); 185 return; 186 } 187 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG, 188 (caddr_t *)&sc->sc_shed, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 189 if (error) { 190 printf("%s: unable to map scheduler DMA memory, error = %d\n", 191 sc->sc_dev.dv_xname, error); 192 return; 193 } 194 error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, 195 NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_sheddma); 196 if (error) { 197 printf("%s: unable to create scheduler DMA map, error = %d\n", 198 sc->sc_dev.dv_xname, error); 199 return; 200 } 201 error = bus_dmamap_load(sc->sc_dmat, sc->sc_sheddma, sc->sc_shed, 202 NBPG, NULL, BUS_DMA_NOWAIT); 203 if (error) { 204 printf("%s: unable to load scheduler DMA map, error = %d\n", 205 sc->sc_dev.dv_xname, error); 206 return; 207 } 208 TAILQ_INIT(&sc->free_list); 209 TAILQ_INIT(&sc->cmds); 210 /* compute number of scheduler slots */ 211 sc->sc_nshedslots = ( 212 NBPG /* memory size allocated for scheduler */ 213 - sizeof(endslot_script) /* memory needed at end of scheduler */ 214 ) / (sizeof(slot_script) - 8); 215 sc->sc_currshedslot = 0; 216#ifdef DEBUG 217 printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n", 218 sc->sc_dev.dv_xname, (int)sizeof(siop_script), 219 sc->sc_scriptaddr, sc->sc_script, sc->sc_nshedslots); 220#endif 221 222 sc->sc_link.adapter_softc = sc; 223 sc->sc_link.openings = 1; 224 sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; 225 sc->sc_link.scsipi_scsi.max_target = 226 (sc->features & SF_BUS_WIDE) ? 15 : 7; 227 sc->sc_link.scsipi_scsi.max_lun = 7; 228 sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt, 229 sc->sc_rh, SIOP_SCID); 230 if (sc->sc_link.scsipi_scsi.adapter_target == 0 || 231 sc->sc_link.scsipi_scsi.adapter_target > 232 sc->sc_link.scsipi_scsi.max_target) 233 sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET; 234 sc->sc_link.type = BUS_SCSI; 235 sc->sc_link.adapter = &siop_adapter; 236 sc->sc_link.device = &siop_dev; 237 sc->sc_link.flags = 0; 238 239 for (i = 0; i < 16; i++) 240 sc->targets[i] = NULL; 241 242 /* find min/max sync period for this chip */ 243 sc->maxsync = 0; 244 sc->minsync = 255; 245 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) { 246 if (sc->clock_period != scf_period[i].clock) 247 continue; 248 if (sc->maxsync < scf_period[i].period) 249 sc->maxsync = scf_period[i].period; 250 if (sc->minsync > scf_period[i].period) 251 sc->minsync = scf_period[i].period; 252 } 253 if (sc->maxsync == 255 || sc->minsync == 0) 254 panic("siop: can't find my sync parameters\n"); 255 siop_reset(sc); 256#ifdef DUMP_SCRIPT 257 siop_dump_script(sc); 258#endif 259 260 config_found((struct device*)sc, &sc->sc_link, scsiprint); 261} 262 263void 264siop_reset(sc) 265 struct siop_softc *sc; 266{ 267 int i, j; 268 u_int32_t *scr; 269 bus_addr_t physaddr; 270 271 siop_common_reset(sc); 272 273 /* copy and patch the script */ 274 if (sc->features & SF_CHIP_RAM) { 275 bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0, 276 siop_script, sizeof(siop_script) / sizeof(siop_script[0])); 277 for (j = 0; j < 278 (sizeof(E_script_abs_shed_Used) / 279 sizeof(E_script_abs_shed_Used[0])); 280 j++) { 281 bus_space_write_4(sc->sc_ramt, sc->sc_ramh, 282 E_script_abs_shed_Used[j] * 4, 283 sc->sc_sheddma->dm_segs[0].ds_addr); 284 } 285 } else { 286 for (j = 0; 287 j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) { 288 sc->sc_script[j] = htole32(siop_script[j]); 289 } 290 for (j = 0; j < 291 (sizeof(E_script_abs_shed_Used) / 292 sizeof(E_script_abs_shed_Used[0])); 293 j++) { 294 sc->sc_script[E_script_abs_shed_Used[j]] = 295 htole32(sc->sc_sheddma->dm_segs[0].ds_addr); 296 } 297 } 298 /* copy and init the scheduler slots script */ 299 for (i = 0; i < sc->sc_nshedslots; i++) { 300 scr = &sc->sc_shed[(Ent_nextslot / 4) * i]; 301 physaddr = sc->sc_sheddma->dm_segs[0].ds_addr + 302 Ent_nextslot * i; 303 for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0])); 304 j++) { 305 scr[j] = htole32(slot_script[j]); 306 } 307 /* 308 * save current jump offset and patch MOVE MEMORY operands 309 * to restore it. 310 */ 311 scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1]; 312 scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4); 313 scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr + 314 Ent_slotdata + 4); 315 /* JUMP selected, in main script */ 316 scr[E_slot_abs_selected_Used[0]] = 317 htole32(sc->sc_scriptaddr + Ent_selected); 318 /* JUMP addr if SELECT fail */ 319 scr[E_slot_abs_reselect_Used[0]] = 320 htole32(sc->sc_scriptaddr + Ent_reselect); 321 } 322 /* Now the final JUMP */ 323 scr = &sc->sc_shed[(Ent_nextslot / 4) * sc->sc_nshedslots]; 324 for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0])); 325 j++) { 326 scr[j] = htole32(endslot_script[j]); 327 } 328 scr[E_endslot_abs_reselect_Used[0]] = 329 htole32(sc->sc_scriptaddr + Ent_reselect); 330 331 /* start script */ 332 if ((sc->features & SF_CHIP_RAM) == 0) { 333 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG, 334 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 335 } 336 siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 337 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, 338 sc->sc_scriptaddr + Ent_reselect); 339} 340 341#if 0 342#define CALL_SCRIPT(ent) do {\ 343 printf ("start script DSA 0x%lx DSP 0x%lx\n", \ 344 siop_cmd->dsa, \ 345 sc->sc_scriptaddr + ent); \ 346bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \ 347} while (0) 348#else 349#define CALL_SCRIPT(ent) do {\ 350bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \ 351} while (0) 352#endif 353 354int 355siop_intr(v) 356 void *v; 357{ 358 struct siop_softc *sc = v; 359 struct siop_target *siop_target; 360 struct siop_cmd *siop_cmd; 361 struct scsipi_xfer *xs; 362 int istat, sist0, sist1, sstat1, dstat, scntl1; 363 u_int32_t irqcode; 364 int need_reset = 0; 365 int offset, target, lun; 366 bus_addr_t dsa; 367 struct siop_cbd *cbdp; 368 369 istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT); 370 if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) 371 return 0; 372 INCSTAT(siop_stat_intr); 373 if (istat & ISTAT_INTF) { 374 printf("INTRF\n"); 375 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF); 376 } 377 /* use DSA to find the current siop_cmd */ 378 dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA); 379 for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL; 380 cbdp = TAILQ_NEXT(cbdp, next)) { 381 if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr && 382 dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) { 383 dsa -= cbdp->xferdma->dm_segs[0].ds_addr; 384 siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)]; 385 siop_table_sync(siop_cmd, 386 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 387 break; 388 } 389 } 390 if (cbdp == NULL) { 391 siop_cmd = NULL; 392 } 393 if (istat & ISTAT_DIP) { 394 u_int32_t *p; 395 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT); 396 if (dstat & DSTAT_SSI) { 397 printf("single step dsp 0x%08x dsa 0x08%x\n", 398 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 399 sc->sc_scriptaddr), 400 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); 401 if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 && 402 (istat & ISTAT_SIP) == 0) { 403 bus_space_write_1(sc->sc_rt, sc->sc_rh, 404 SIOP_DCNTL, bus_space_read_1(sc->sc_rt, 405 sc->sc_rh, SIOP_DCNTL) | DCNTL_STD); 406 } 407 return 1; 408 } 409 if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) { 410 printf("DMA IRQ:"); 411 if (dstat & DSTAT_IID) 412 printf(" Illegal instruction"); 413 if (dstat & DSTAT_ABRT) 414 printf(" abort"); 415 if (dstat & DSTAT_BF) 416 printf(" bus fault"); 417 if (dstat & DSTAT_MDPE) 418 printf(" parity"); 419 if (dstat & DSTAT_DFE) 420 printf(" dma fifo empty"); 421 printf(", DSP=0x%x DSA=0x%x: ", 422 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 423 sc->sc_scriptaddr), 424 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); 425 p = sc->sc_script + 426 (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 427 sc->sc_scriptaddr - 8) / 4; 428 printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]), 429 le32toh(p[2]), le32toh(p[3])); 430 if (siop_cmd) 431 printf("last msg_in=0x%x status=0x%x\n", 432 siop_cmd->siop_table->msg_in[0], 433 le32toh(siop_cmd->siop_table->status)); 434 else 435 printf("%s: current DSA invalid\n", 436 sc->sc_dev.dv_xname); 437 need_reset = 1; 438 } 439 } 440 if (istat & ISTAT_SIP) { 441 /* 442 * SCSI interrupt. If current command is not active, 443 * we don't need siop_cmd 444 */ 445 if (siop_cmd && siop_cmd->status != CMDST_ACTIVE && 446 siop_cmd->status != CMDST_SENSE_ACTIVE) { 447 siop_cmd = NULL; 448 } 449 if (istat & ISTAT_DIP) 450 delay(10); 451 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0); 452 delay(10); 453 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1); 454 sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1); 455#ifdef DEBUG_INTR 456 printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x " 457 "DSA=0x%x DSP=0x%lx\n", sist0, sist1, 458 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), 459 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), 460 (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 461 sc->sc_scriptaddr)); 462#endif 463 if (siop_cmd) { 464 xs = siop_cmd->xs; 465 siop_target = siop_cmd->siop_target; 466 } 467 if (sist0 & SIST0_RST) { 468 siop_handle_reset(sc); 469 siop_start(sc); 470 /* no table to flush here */ 471 return 1; 472 } 473 if (sist0 & SIST0_SGE) { 474 if (siop_cmd) 475 scsi_print_addr(xs->sc_link); 476 else 477 printf("%s:", sc->sc_dev.dv_xname); 478 printf("scsi gross error\n"); 479 goto reset; 480 } 481 if ((sist0 & SIST0_MA) && need_reset == 0) { 482 if (siop_cmd) { 483 int scratcha0; 484 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, 485 SIOP_DSTAT); 486 /* 487 * first restore DSA, in case we were in a S/G 488 * operation. 489 */ 490 bus_space_write_4(sc->sc_rt, sc->sc_rh, 491 SIOP_DSA, siop_cmd->dsa); 492 scratcha0 = bus_space_read_1(sc->sc_rt, 493 sc->sc_rh, SIOP_SCRATCHA); 494 switch (sstat1 & SSTAT1_PHASE_MASK) { 495 case SSTAT1_PHASE_STATUS: 496 /* 497 * previous phase may be aborted for any reason 498 * ( for example, the target has less data to 499 * transfer than requested). Just go to status 500 * and the command should terminate. 501 */ 502 INCSTAT(siop_stat_intr_shortxfer); 503 CALL_SCRIPT(Ent_status); 504 if ((dstat & DSTAT_DFE) == 0) 505 siop_clearfifo(sc); 506 /* no table to flush here */ 507 return 1; 508 case SSTAT1_PHASE_MSGIN: 509 /* 510 * target may be ready to disconnect 511 * Save data pointers just in case. 512 */ 513 INCSTAT(siop_stat_intr_xferdisc); 514 if (scratcha0 & A_flag_data) 515 siop_sdp(siop_cmd); 516 else if ((dstat & DSTAT_DFE) == 0) 517 siop_clearfifo(sc); 518 bus_space_write_1(sc->sc_rt, sc->sc_rh, 519 SIOP_SCRATCHA, 520 scratcha0 & ~A_flag_data); 521 siop_table_sync(siop_cmd, 522 BUS_DMASYNC_PREREAD | 523 BUS_DMASYNC_PREWRITE); 524 CALL_SCRIPT(Ent_msgin); 525 return 1; 526 } 527 printf("%s: unexpected phase mismatch %d\n", 528 sc->sc_dev.dv_xname, 529 sstat1 & SSTAT1_PHASE_MASK); 530 } else { 531 printf("%s: phase mismatch without command\n", 532 sc->sc_dev.dv_xname); 533 } 534 need_reset = 1; 535 } 536 if (sist0 & SIST0_PAR) { 537 /* parity error, reset */ 538 if (siop_cmd) 539 scsi_print_addr(xs->sc_link); 540 else 541 printf("%s:", sc->sc_dev.dv_xname); 542 printf("parity error\n"); 543 goto reset; 544 } 545 if ((sist1 & SIST1_STO) && need_reset == 0) { 546 /* selection time out, assume there's no device here */ 547 if (siop_cmd) { 548 siop_cmd->status = CMDST_DONE; 549 xs->error = XS_SELTIMEOUT; 550 goto end; 551 } else { 552 printf("%s: selection timeout without " 553 "command\n", sc->sc_dev.dv_xname); 554 need_reset = 1; 555 } 556 } 557 if (sist0 & SIST0_UDC) { 558 /* 559 * unexpected disconnect. Usually the target signals 560 * a fatal condition this way. Attempt to get sense. 561 */ 562 if (siop_cmd) 563 goto check_sense; 564 printf("%s: unexpected disconnect without " 565 "command\n", sc->sc_dev.dv_xname); 566 goto reset; 567 } 568 if (sist1 & SIST1_SBMC) { 569 /* SCSI bus mode change */ 570 if (siop_modechange(sc) == 0 || need_reset == 1) 571 goto reset; 572 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { 573 /* 574 * we have a script interrupt, it will 575 * restart the script. 576 */ 577 goto scintr; 578 } 579 /* 580 * else we have to restart it ourselve, at the 581 * interrupted instruction. 582 */ 583 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, 584 bus_space_read_4(sc->sc_rt, sc->sc_rh, 585 SIOP_DSP) - 8); 586 return 1; 587 } 588 /* Else it's an unhandled exeption (for now). */ 589 printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x " 590 "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, 591 sist0, sist1, 592 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), 593 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), 594 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 595 sc->sc_scriptaddr)); 596 if (siop_cmd) { 597 siop_cmd->status = CMDST_DONE; 598 xs->error = XS_SELTIMEOUT; 599 goto end; 600 } 601 need_reset = 1; 602 } 603 if (need_reset) { 604reset: 605 /* fatal error, reset the bus */ 606 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 607 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 608 scntl1 | SCNTL1_RST); 609 /* minimum 25 us, more time won't hurt */ 610 delay(100); 611 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 612 /* no table to flush here */ 613 return 1; 614 } 615 616scintr: 617 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ 618 irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh, 619 SIOP_DSPS); 620#ifdef DEBUG_INTR 621 printf("script interrupt 0x%x\n", irqcode); 622#endif 623 if (siop_cmd == NULL) { 624 printf("%s: script interrupt (0x%x) with invalid " 625 "DSA !!!\n", sc->sc_dev.dv_xname, irqcode); 626 goto reset; 627 } 628 /* 629 * an inactive command is only valid if it's a reselect 630 * interrupt: we'll change siop_cmd to point to the rigth one 631 * just here 632 */ 633 if (irqcode != A_int_resel && irqcode != A_int_reseltag && 634 siop_cmd->status != CMDST_ACTIVE && 635 siop_cmd->status != CMDST_SENSE_ACTIVE) { 636 printf("%s: Aie, no command (IRQ code 0x%x current " 637 "status %d) !\n", sc->sc_dev.dv_xname, 638 irqcode, siop_cmd->status); 639 xs = NULL; 640 } else { 641 xs = siop_cmd->xs; 642 siop_target = siop_cmd->siop_target; 643 } 644 switch(irqcode) { 645 case A_int_err: 646 printf("error, DSP=0x%x\n", 647 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, 648 SIOP_DSP) - sc->sc_scriptaddr)); 649 if (xs) { 650 xs->error = XS_SELTIMEOUT; 651 goto end; 652 } else { 653 goto reset; 654 } 655 case A_int_msgin: 656 if (siop_cmd->siop_table->msg_in[0] == 657 MSG_MESSAGE_REJECT) { 658 int msg, extmsg; 659 if (siop_cmd->siop_table->msg_out[0] & 0x80) { 660 /* 661 * message was part of a identify + 662 * something else. Identify shoudl't 663 * have been rejected. 664 */ 665 msg = siop_cmd->siop_table->msg_out[1]; 666 extmsg = 667 siop_cmd->siop_table->msg_out[3]; 668 } else { 669 msg = siop_cmd->siop_table->msg_out[0]; 670 extmsg = 671 siop_cmd->siop_table->msg_out[2]; 672 } 673 if (msg == MSG_MESSAGE_REJECT) { 674 /* MSG_REJECT for a MSG_REJECT !*/ 675 if (xs) 676 scsi_print_addr(xs->sc_link); 677 else 678 printf("%s: ", 679 sc->sc_dev.dv_xname); 680 printf("our reject message was " 681 "rejected\n"); 682 goto reset; 683 } 684 if (msg == MSG_EXTENDED && 685 extmsg == MSG_EXT_WDTR) { 686 /* WDTR rejected, initiate sync */ 687 printf("%s: target %d using 8bit " 688 "transfers\n", sc->sc_dev.dv_xname, 689 xs->sc_link->scsipi_scsi.target); 690 siop_target->status = TARST_SYNC_NEG; 691 siop_cmd->siop_table->msg_out[0] = 692 MSG_EXTENDED; 693 siop_cmd->siop_table->msg_out[1] = 694 MSG_EXT_SDTR_LEN; 695 siop_cmd->siop_table->msg_out[2] = 696 MSG_EXT_SDTR; 697 siop_cmd->siop_table->msg_out[3] = 698 sc->minsync; 699 siop_cmd->siop_table->msg_out[4] = 700 sc->maxoff; 701 siop_cmd->siop_table->t_msgout.count = 702 htole32(MSG_EXT_SDTR_LEN + 2); 703 siop_cmd->siop_table->t_msgout.addr = 704 htole32(siop_cmd->dsa); 705 siop_table_sync(siop_cmd, 706 BUS_DMASYNC_PREREAD | 707 BUS_DMASYNC_PREWRITE); 708 CALL_SCRIPT(Ent_send_msgout); 709 return 1; 710 } else if (msg == MSG_EXTENDED && 711 extmsg == MSG_EXT_SDTR) { 712 /* sync rejected */ 713 printf("%s: target %d asynchronous\n", 714 sc->sc_dev.dv_xname, 715 xs->sc_link->scsipi_scsi.target); 716 siop_cmd->siop_target->status = 717 TARST_OK; 718 /* no table to flush here */ 719 CALL_SCRIPT(Ent_msgin_ack); 720 return 1; 721 } 722 if (xs) 723 scsi_print_addr(xs->sc_link); 724 else 725 printf("%s: ", sc->sc_dev.dv_xname); 726 if (msg == MSG_EXTENDED) { 727 printf("scsi message reject, extended " 728 "message sent was 0x%x\n", extmsg); 729 } else { 730 printf("scsi message reject, message " 731 "sent was 0x%x\n", msg); 732 } 733 /* no table to flush here */ 734 CALL_SCRIPT(Ent_msgin_ack); 735 return 1; 736 } 737 if (xs) 738 scsi_print_addr(xs->sc_link); 739 else 740 printf("%s: ", sc->sc_dev.dv_xname); 741 printf("unhandled message 0x%x\n", 742 siop_cmd->siop_table->msg_in[0]); 743 siop_cmd->siop_table->t_msgout.count= htole32(1); 744 siop_cmd->siop_table->t_msgout.addr = 745 htole32(siop_cmd->dsa); 746 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT; 747 siop_table_sync(siop_cmd, 748 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 749 CALL_SCRIPT(Ent_send_msgout); 750 return 1; 751 case A_int_extmsgin: 752#ifdef DEBUG_INTR 753 printf("extended message: msg 0x%x len %d\n", 754 siop_cmd->siop_table->msg_in[2], 755 siop_cmd->siop_table->msg_in[1]); 756#endif 757 if (siop_cmd->siop_table->msg_in[1] > 6) 758 printf("%s: extended message too big (%d)\n", 759 sc->sc_dev.dv_xname, 760 siop_cmd->siop_table->msg_in[1]); 761 siop_cmd->siop_table->t_extmsgdata.count = 762 htole32(siop_cmd->siop_table->msg_in[1] - 1); 763 siop_cmd->siop_table->t_extmsgdata.addr = 764 htole32( 765 le32toh(siop_cmd->siop_table->t_extmsgin.addr) 766 + 2); 767 siop_table_sync(siop_cmd, 768 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 769 CALL_SCRIPT(Ent_get_extmsgdata); 770 return 1; 771 case A_int_extmsgdata: 772#ifdef DEBUG_INTR 773 { 774 int i; 775 printf("extended message: 0x%x, data:", 776 siop_cmd->siop_table->msg_in[2]); 777 for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1]; 778 i++) 779 printf(" 0x%x", 780 siop_cmd->siop_table->msg_in[i]); 781 printf("\n"); 782 } 783#endif 784 if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_WDTR) { 785 switch (siop_wdtr_neg(siop_cmd)) { 786 case SIOP_NEG_NOP: 787 break; 788 case SIOP_NEG_MSGOUT: 789 siop_table_sync(siop_cmd, 790 BUS_DMASYNC_PREREAD | 791 BUS_DMASYNC_PREWRITE); 792 CALL_SCRIPT(Ent_send_msgout); 793 break; 794 default: 795 panic("invalid retval from " 796 "siop_wdtr_neg()"); 797 } 798 return(1); 799 } 800 if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) { 801 switch (siop_sdtr_neg(siop_cmd)) { 802 case SIOP_NEG_NOP: 803 break; 804 case SIOP_NEG_MSGOUT: 805 siop_table_sync(siop_cmd, 806 BUS_DMASYNC_PREREAD | 807 BUS_DMASYNC_PREWRITE); 808 CALL_SCRIPT(Ent_send_msgout); 809 break; 810 case SIOP_NEG_ACK: 811 CALL_SCRIPT(Ent_msgin_ack); 812 break; 813 default: 814 panic("invalid retval from " 815 "siop_wdtr_neg()"); 816 } 817 return(1); 818 } 819 /* send a message reject */ 820 siop_cmd->siop_table->t_msgout.count = 821 htole32(1); 822 siop_cmd->siop_table->t_msgout.addr = 823 htole32(siop_cmd->dsa); 824 siop_cmd->siop_table->msg_out[0] = 825 MSG_MESSAGE_REJECT; 826 siop_table_sync(siop_cmd, 827 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 828 CALL_SCRIPT(Ent_send_msgout); 829 return 1; 830 case A_int_resel: /* reselected */ 831 case A_int_reseltag: /* reselected with tag */ 832 INCSTAT(siop_stat_intr_reselect); 833 if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) { 834 printf("%s: reselect without identify (%d)\n", 835 sc->sc_dev.dv_xname, 836 siop_cmd->siop_table->msg_in[0]); 837 goto reset; 838 } 839 target = bus_space_read_1(sc->sc_rt, 840 sc->sc_rh, SIOP_SCRATCHA); 841 if ((target & 0x80) == 0) { 842 printf("reselect without id (%d)\n", target); 843 goto reset; 844 } 845 target &= 0x0f; 846 lun = siop_cmd->siop_table->msg_in[0] & 0x07; 847#ifdef DEBUG_DR 848 printf("reselected by target %d lun %d\n", 849 target, lun); 850#endif 851 siop_cmd = 852 sc->targets[target]->active_list[lun].tqh_first; 853 if (siop_cmd == NULL) { 854 printf("%s: reselected without cmd\n", 855 sc->sc_dev.dv_xname); 856 goto reset; 857 } 858 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, 859 siop_cmd->dsa); 860 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 861 (sc->targets[target]->id >> 24) & 0xff); 862 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER, 863 (sc->targets[target]->id >> 8) & 0xff); 864 /* no table to flush */ 865 CALL_SCRIPT(Ent_selected); 866 return 1; 867 case A_int_disc: 868 INCSTAT(siop_stat_intr_sdp); 869 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, 870 SIOP_SCRATCHA + 1); 871#ifdef DEBUG_DR 872 printf("disconnect offset %d\n", offset); 873#endif 874 if (offset > SIOP_NSG) { 875 printf("%s: bad offset for disconnect (%d)\n", 876 sc->sc_dev.dv_xname, offset); 877 goto reset; 878 } 879 /* 880 * offset == SIOP_NSG may be a valid condition if 881 * we get a sdp when the xfer is done. 882 * Don't call memmove in this case. 883 */ 884 if (offset < SIOP_NSG) { 885 memmove(&siop_cmd->siop_table->data[0], 886 &siop_cmd->siop_table->data[offset], 887 (SIOP_NSG - offset) * sizeof(scr_table_t)); 888 siop_table_sync(siop_cmd, 889 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 890 } 891 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, 892 sc->sc_sheddma->dm_segs[0].ds_addr); 893 return 1; 894 case A_int_resfail: 895 printf("reselect failed\n"); 896 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, 897 sc->sc_sheddma->dm_segs[0].ds_addr); 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 bus_space_write_4(sc->sc_rt, sc->sc_rh, 905 SIOP_DSP, 906 sc->sc_sheddma->dm_segs[0].ds_addr); 907 siop_start(sc); 908 return 1; 909 } 910 if (siop_target->status == TARST_PROBING) 911 siop_target->status = TARST_ASYNC; 912#ifdef DEBUG_INTR 913 printf("done, DSA=0x%lx target id 0x%x last msg " 914 "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa, 915 le32toh(siop_cmd->siop_table->id), 916 siop_cmd->siop_table->msg_in[0], 917 le32toh(siop_cmd->siop_table->status)); 918#endif 919 INCSTAT(siop_stat_intr_done); 920 if (siop_cmd->status == CMDST_SENSE_ACTIVE) 921 siop_cmd->status = CMDST_SENSE_DONE; 922 else 923 siop_cmd->status = CMDST_DONE; 924 switch(le32toh(siop_cmd->siop_table->status)) { 925 case SCSI_OK: 926 xs->error = (siop_cmd->status == CMDST_DONE) ? 927 XS_NOERROR : XS_SENSE; 928 break; 929 case SCSI_BUSY: 930 xs->error = XS_BUSY; 931 break; 932 case SCSI_CHECK: 933check_sense: 934 if (siop_cmd->status == CMDST_SENSE_DONE) { 935 /* request sense on a request sense ? */ 936 printf("request sense failed\n"); 937 xs->error = XS_DRIVER_STUFFUP; 938 } else { 939 siop_cmd->status = CMDST_SENSE; 940 } 941 break; 942 case 0xff: 943 /* 944 * the status byte was not updated, cmd was 945 * aborted 946 */ 947 xs->error = XS_SELTIMEOUT; 948 break; 949 default: 950 xs->error = XS_DRIVER_STUFFUP; 951 } 952 goto end; 953 default: 954 printf("unknown irqcode %x\n", irqcode); 955 xs->error = XS_SELTIMEOUT; 956 goto end; 957 } 958 return 1; 959 } 960 /* We just should't get there */ 961 panic("siop_intr: I shouldn't be there !"); 962 return 1; 963end: 964 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, 965 sc->sc_sheddma->dm_segs[0].ds_addr); 966 lun = siop_cmd->xs->sc_link->scsipi_scsi.lun; 967 siop_scsicmd_end(siop_cmd); 968 if (siop_cmd->status == CMDST_FREE) { 969 TAILQ_REMOVE(&siop_target->active_list[lun], 970 siop_cmd, next); 971 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); 972 } 973 siop_start(sc); 974 return 1; 975} 976 977void 978siop_scsicmd_end(siop_cmd) 979 struct siop_cmd *siop_cmd; 980{ 981 struct scsipi_xfer *xs = siop_cmd->xs; 982 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 983 984 if (siop_cmd->status != CMDST_SENSE_DONE && 985 xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 986 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, 987 siop_cmd->dmamap_data->dm_mapsize, 988 (xs->xs_control & XS_CTL_DATA_IN) ? 989 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 990 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); 991 } 992 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); 993 if (siop_cmd->status == CMDST_SENSE) { 994 /* issue a request sense for this target */ 995 int error, i; 996 siop_cmd->rs_cmd.opcode = REQUEST_SENSE; 997 siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5; 998 siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0; 999 siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data); 1000 siop_cmd->rs_cmd.control = 0; 1001 siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/ 1002 siop_cmd->siop_table->t_msgout.count= htole32(1); 1003 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa); 1004 siop_cmd->siop_table->msg_out[0] = 1005 MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1); 1006 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, 1007 &siop_cmd->rs_cmd, sizeof(struct scsipi_sense), 1008 NULL, BUS_DMA_NOWAIT); 1009 if (error) { 1010 printf("%s: unable to load cmd DMA map: %d", 1011 sc->sc_dev.dv_xname, error); 1012 xs->error = XS_DRIVER_STUFFUP; 1013 goto out; 1014 } 1015 siop_cmd->siop_table->cmd.count = 1016 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); 1017 siop_cmd->siop_table->cmd.addr = 1018 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); 1019 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, 1020 &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data), 1021 NULL, BUS_DMA_NOWAIT); 1022 if (error) { 1023 printf("%s: unable to load sense DMA map: %d", 1024 sc->sc_dev.dv_xname, error); 1025 xs->error = XS_DRIVER_STUFFUP; 1026 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); 1027 goto out; 1028 } 1029 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 1030 siop_cmd->siop_table->data[i].count = 1031 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 1032 siop_cmd->siop_table->data[i].addr = 1033 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 1034 } 1035 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, 1036 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD); 1037 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, 1038 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); 1039 siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); 1040 return; 1041 } else if (siop_cmd->status == CMDST_SENSE_DONE) { 1042 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, 1043 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD); 1044 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); 1045 } 1046out: 1047 callout_stop(&siop_cmd->xs->xs_callout); 1048 siop_cmd->status = CMDST_FREE; 1049 xs->xs_status |= XS_STS_DONE; 1050 xs->resid = 0; 1051 if ((xs->xs_control & XS_CTL_POLL) == 0) 1052 scsipi_done (xs); 1053} 1054 1055/* 1056 * handle a bus reset: reset chip, unqueue all active commands and report 1057 * loosage to upper layer. 1058 * As the upper layer may requeue immediatly we have to first store 1059 * all active commands in a temporary queue. 1060 */ 1061void 1062siop_handle_reset(sc) 1063 struct siop_softc *sc; 1064{ 1065 struct cmd_list reset_list; 1066 struct siop_cmd *siop_cmd, *next_siop_cmd; 1067 int target, lun; 1068 /* 1069 * scsi bus reset. reset the chip and restart 1070 * the queue. Need to clean up all active commands 1071 */ 1072 printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname); 1073 /* stop, reset and restart the chip */ 1074 siop_reset(sc); 1075 TAILQ_INIT(&reset_list); 1076 /* find all active commands */ 1077 for (target = 0; target < sc->sc_link.scsipi_scsi.max_target; 1078 target++) { 1079 if (sc->targets[target] == NULL) 1080 continue; 1081 for (lun = 0; lun < 8; lun++) { 1082 for (siop_cmd = 1083 TAILQ_FIRST(&sc->targets[target]->active_list[lun]); 1084 siop_cmd != NULL; siop_cmd = next_siop_cmd) { 1085 next_siop_cmd = TAILQ_NEXT(siop_cmd, next); 1086 if (siop_cmd->status < CMDST_ACTIVE) 1087 continue; 1088 printf("cmd %p (target %d) in reset list\n", 1089 siop_cmd, target); 1090 TAILQ_REMOVE( 1091 &sc->targets[target]->active_list[lun], 1092 siop_cmd, next); 1093 TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); 1094 } 1095 } 1096 sc->targets[target]->status = TARST_ASYNC; 1097 sc->targets[target]->flags = ~(TARF_SYNC | TARF_WIDE); 1098 } 1099 for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL; 1100 siop_cmd = next_siop_cmd) { 1101 next_siop_cmd = TAILQ_NEXT(siop_cmd, next); 1102 siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ? 1103 XS_TIMEOUT : XS_RESET; 1104 printf("cmd %p about to be processed\n", siop_cmd); 1105 if (siop_cmd->status == CMDST_SENSE || 1106 siop_cmd->status == CMDST_SENSE_ACTIVE) 1107 siop_cmd->status = CMDST_SENSE_DONE; 1108 else 1109 siop_cmd->status = CMDST_DONE; 1110 TAILQ_REMOVE(&reset_list, siop_cmd, next); 1111 siop_scsicmd_end(siop_cmd); 1112 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); 1113 } 1114} 1115 1116int 1117siop_scsicmd(xs) 1118 struct scsipi_xfer *xs; 1119{ 1120 struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc; 1121 struct siop_cmd *siop_cmd; 1122 int s, error, i; 1123 int target = xs->sc_link->scsipi_scsi.target; 1124 int lun = xs->sc_link->scsipi_scsi.lun; 1125 1126 s = splbio(); 1127#ifdef DEBUG_SHED 1128 printf("starting cmd for %d:%d\n", target, lun); 1129#endif 1130 siop_cmd = sc->free_list.tqh_first; 1131 if (siop_cmd) { 1132 TAILQ_REMOVE(&sc->free_list, siop_cmd, next); 1133 } else { 1134 if (siop_morecbd(sc) == 0) { 1135 siop_cmd = sc->free_list.tqh_first; 1136#ifdef DIAGNOSTIC 1137 if (siop_cmd == NULL) 1138 panic("siop_morecbd succeed and does nothing"); 1139#endif 1140 TAILQ_REMOVE(&sc->free_list, siop_cmd, next); 1141 } 1142 } 1143 splx(s); 1144 if (siop_cmd == NULL) { 1145 xs->error = XS_DRIVER_STUFFUP; 1146 return(TRY_AGAIN_LATER); 1147 } 1148#ifdef DIAGNOSTIC 1149 if (siop_cmd->status != CMDST_FREE) 1150 panic("siop_scsicmd: new cmd not free"); 1151#endif 1152 if (sc->targets[target] == NULL) { 1153 sc->targets[target] = 1154 malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT); 1155 if (sc->targets[target] == NULL) { 1156 printf("%s: can't malloc memory for target %d\n", 1157 sc->sc_dev.dv_xname, target); 1158 xs->error = XS_DRIVER_STUFFUP; 1159 return(TRY_AGAIN_LATER); 1160 } 1161 sc->targets[target]->siop_sc = sc; 1162 sc->targets[target]->status = TARST_PROBING; 1163 sc->targets[target]->flags = 0; 1164 sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */ 1165 sc->targets[target]->id |= target << 16; /* id */ 1166 /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */ 1167 for (i = 0; i < 8; i++) 1168 TAILQ_INIT(&sc->targets[target]->active_list[i]); 1169 } 1170 siop_cmd->siop_target = sc->targets[target]; 1171 siop_cmd->xs = xs; 1172 siop_cmd->siop_table->id = htole32(sc->targets[target]->id); 1173 siop_cmd->siop_table->t_msgout.count= htole32(1); 1174 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa); 1175 memset(siop_cmd->siop_table->msg_out, 0, 8); 1176 siop_cmd->siop_table->msg_out[0] = MSG_IDENTIFY(lun, 1); 1177#if 0 1178 siop_cmd->siop_table->msg_out[1] = MSG_SIMPLE_Q_TAG; 1179 siop_cmd->siop_table->msg_out[2] = 0; 1180#endif 1181 if (sc->targets[target]->status == TARST_ASYNC) { 1182 if (sc->features & SF_BUS_WIDE) { 1183 sc->targets[target]->status = TARST_WIDE_NEG; 1184 siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED; 1185 siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR_LEN; 1186 siop_cmd->siop_table->msg_out[3] = MSG_EXT_WDTR; 1187 siop_cmd->siop_table->msg_out[4] = 1188 MSG_EXT_WDTR_BUS_16_BIT; 1189 siop_cmd->siop_table->t_msgout.count= 1190 htole32(MSG_EXT_WDTR_LEN + 2 + 1); 1191 } else { 1192 sc->targets[target]->status = TARST_SYNC_NEG; 1193 siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED; 1194 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR_LEN; 1195 siop_cmd->siop_table->msg_out[3] = MSG_EXT_SDTR; 1196 siop_cmd->siop_table->msg_out[4] = sc->minsync; 1197 siop_cmd->siop_table->msg_out[5] = sc->maxoff; 1198 siop_cmd->siop_table->t_msgout.count= 1199 htole32(MSG_EXT_SDTR_LEN + 2 +1); 1200 } 1201 } 1202 siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */ 1203 1204 /* load the DMA maps */ 1205 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, 1206 xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); 1207 if (error) { 1208 printf("%s: unable to load cmd DMA map: %d", 1209 sc->sc_dev.dv_xname, error); 1210 xs->error = XS_DRIVER_STUFFUP; 1211 return(TRY_AGAIN_LATER); 1212 } 1213 siop_cmd->siop_table->cmd.count = 1214 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len); 1215 siop_cmd->siop_table->cmd.addr = 1216 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr); 1217 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 1218 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, 1219 xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT); 1220 if (error) { 1221 printf("%s: unable to load cmd DMA map: %d", 1222 sc->sc_dev.dv_xname, error); 1223 xs->error = XS_DRIVER_STUFFUP; 1224 return(TRY_AGAIN_LATER); 1225 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); 1226 } 1227 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) { 1228 siop_cmd->siop_table->data[i].count = 1229 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len); 1230 siop_cmd->siop_table->data[i].addr = 1231 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr); 1232 } 1233 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, 1234 siop_cmd->dmamap_data->dm_mapsize, 1235 (xs->xs_control & XS_CTL_DATA_IN) ? 1236 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1237 } 1238 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, 1239 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); 1240 siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1241 1242 siop_cmd->status = CMDST_READY; 1243 s = splbio(); 1244 TAILQ_INSERT_TAIL(&sc->targets[target]->active_list[lun], 1245 siop_cmd, next); 1246 siop_start(sc); 1247 if (xs->xs_control & XS_CTL_POLL) { 1248 /* poll for command completion */ 1249 while ((xs->xs_status & XS_STS_DONE) == 0) 1250 siop_intr(sc); 1251 splx(s); 1252 return (COMPLETE); 1253 } 1254 splx(s); 1255 return (SUCCESSFULLY_QUEUED); 1256} 1257 1258void 1259siop_start(sc) 1260 struct siop_softc *sc; 1261{ 1262 struct siop_cmd *siop_cmd; 1263 u_int32_t *scr; 1264 u_int32_t dsa; 1265 int timeout; 1266 int target, lun, slot; 1267 int newcmd = 0; 1268 1269 /* 1270 * first make sure to read valid data 1271 */ 1272 siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1273 1274 /* 1275 * The queue management here is a bit tricky: the script always looks 1276 * at the slot from first to last, so if we always use the first 1277 * free slot commands can stay at the tail of the queue ~forever. 1278 * The algorithm used here is to restart from the head when we know 1279 * that the queue is empty, and only add commands after the last one. 1280 * When we're at the end of the queue wait for the script to clear it. 1281 * The best thing to do here would be to implement a circular queue, 1282 * but using only 53c720 features this can be "interesting". 1283 * A mid-way solution could be to implement 2 queues and swap orders. 1284 */ 1285 slot = sc->sc_currshedslot; 1286 scr = &sc->sc_shed[(Ent_nextslot / 4) * slot]; 1287 /* 1288 * if relative addr of first jump is not 0 the slot is free. As this is 1289 * the last used slot, all previous slots are free, we can restart 1290 * from 0. 1291 */ 1292 if (scr[Ent_slot / 4 + 1] != 0) { 1293 slot = sc->sc_currshedslot = 0; 1294 } else { 1295 slot++; 1296 } 1297 1298 for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target; 1299 target++) { 1300 if (sc->targets[target] == NULL) 1301 continue; 1302 for (lun = 0; lun < 8; lun++) { 1303 siop_cmd = 1304 sc->targets[target]->active_list[lun].tqh_first; 1305 if (siop_cmd == NULL) 1306 continue; 1307 if (siop_cmd->status != CMDST_READY && 1308 siop_cmd->status != CMDST_SENSE) 1309 continue; 1310 /* find a free scheduler slot and load it */ 1311 for (; slot < sc->sc_nshedslots; slot++) { 1312 scr = &sc->sc_shed[(Ent_nextslot / 4) * slot]; 1313 /* 1314 * if relative addr of first jump is 0 the 1315 * slot isn't free 1316 */ 1317 if (scr[Ent_slot / 4 + 1] == 0) 1318 continue; 1319#ifdef DEBUG_SHED 1320 printf("using slot %d for DSA 0x%lx\n", slot, 1321 (u_long)siop_cmd->dsa); 1322#endif 1323 /* note that we started a new command */ 1324 newcmd = 1; 1325 /* mark command as active */ 1326 if (siop_cmd->status == CMDST_READY) 1327 siop_cmd->status = CMDST_ACTIVE; 1328 else if (siop_cmd->status == CMDST_SENSE) 1329 siop_cmd->status = CMDST_SENSE_ACTIVE; 1330 else 1331 panic("siop_start: bad status"); 1332 /* patch script with DSA addr */ 1333 dsa = siop_cmd->dsa; 1334 /* 1335 * 0x78000000 is a 'move data8 to reg'. data8 1336 * is the second octet, reg offset is the third. 1337 */ 1338 scr[Ent_idsa0 / 4] = 1339 htole32(0x78100000 | 1340 ((dsa & 0x000000ff) << 8)); 1341 scr[Ent_idsa1 / 4] = 1342 htole32(0x78110000 | 1343 ( dsa & 0x0000ff00 )); 1344 scr[Ent_idsa2 / 4] = 1345 htole32(0x78120000 | 1346 ((dsa & 0x00ff0000) >> 8)); 1347 scr[Ent_idsa3 / 4] = 1348 htole32(0x78130000 | 1349 ((dsa & 0xff000000) >> 16)); 1350 /* handle timeout */ 1351 if (siop_cmd->status == CMDST_ACTIVE) { 1352 if ((siop_cmd->xs->xs_control & 1353 XS_CTL_POLL) == 0) { 1354 /* start exire timer */ 1355 timeout = 1356 siop_cmd->xs->timeout * 1357 hz / 1000; 1358 if (timeout == 0) 1359 timeout = 1; 1360 callout_reset( 1361 &siop_cmd->xs->xs_callout, 1362 timeout, siop_timeout, 1363 siop_cmd); 1364 } 1365 } 1366 /* 1367 * Change jump offset so that this slot will be 1368 * handled 1369 */ 1370 scr[Ent_slot / 4 + 1] = 0; 1371 break; 1372 } 1373 /* no more free slot, no need to continue */ 1374 if (slot == sc->sc_nshedslots) { 1375 goto end; 1376 } 1377 sc->sc_currshedslot = slot; 1378 } 1379 } 1380end: 1381 /* if nothing changed no need to flush cache and wakeup script */ 1382 if (newcmd == 0) 1383 return; 1384 /* make sure SCRIPT processor will read valid data */ 1385 siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1386 /* Signal script it has some work to do */ 1387 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP); 1388 /* and wait for IRQ */ 1389 return; 1390} 1391 1392void 1393siop_timeout(v) 1394 void *v; 1395{ 1396 struct siop_cmd *siop_cmd = v; 1397 struct siop_softc *sc = siop_cmd->siop_target->siop_sc; 1398 int s; 1399 u_int8_t scntl1; 1400 1401 scsi_print_addr(siop_cmd->xs->sc_link); 1402 printf("command timeout\n"); 1403 1404 s = splbio(); 1405 /* reset the scsi bus */ 1406 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1); 1407 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 1408 scntl1 | SCNTL1_RST); 1409 /* minimum 25 us, more time won't hurt */ 1410 delay(100); 1411 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1); 1412 1413 /* deactivate callout */ 1414 callout_stop(&siop_cmd->xs->xs_callout); 1415 /* mark command has being timed out; siop_intr will handle it */ 1416 /* 1417 * mark command has being timed out and just return; 1418 * the bus reset will generate an interrupt, 1419 * it will be handled in siop_intr() 1420 */ 1421 siop_cmd->flags |= CMDFL_TIMEOUT; 1422 splx(s); 1423 return; 1424 1425} 1426 1427void 1428siop_dump_script(sc) 1429 struct siop_softc *sc; 1430{ 1431 int i; 1432 siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1433 for (i = 0; i < NBPG / 4; i += 2) { 1434 printf("0x%04x: 0x%08x 0x%08x", i * 4, 1435 le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1])); 1436 if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) { 1437 i++; 1438 printf(" 0x%08x", le32toh(sc->sc_script[i+1])); 1439 } 1440 printf("\n"); 1441 } 1442} 1443 1444int 1445siop_morecbd(sc) 1446 struct siop_softc *sc; 1447{ 1448 int error, i; 1449 bus_dma_segment_t seg; 1450 int rseg; 1451 struct siop_cbd *newcbd; 1452 1453 /* allocate a new list head */ 1454 newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT); 1455 if (newcbd == NULL) { 1456 printf("%s: can't allocate memory for command descriptors " 1457 "head\n", sc->sc_dev.dv_xname); 1458 return ENOMEM; 1459 } 1460 1461 /* allocate cmd list */ 1462 newcbd->cmds = 1463 malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT); 1464 if (newcbd->cmds == NULL) { 1465 printf("%s: can't allocate memory for command descriptors\n", 1466 sc->sc_dev.dv_xname); 1467 error = ENOMEM; 1468 goto bad3; 1469 } 1470 error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg, 1471 BUS_DMA_NOWAIT); 1472 if (error) { 1473 printf("%s: unable to allocate cbd DMA memory, error = %d\n", 1474 sc->sc_dev.dv_xname, error); 1475 goto bad2; 1476 } 1477 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG, 1478 (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); 1479 if (error) { 1480 printf("%s: unable to map cbd DMA memory, error = %d\n", 1481 sc->sc_dev.dv_xname, error); 1482 goto bad2; 1483 } 1484 error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0, 1485 BUS_DMA_NOWAIT, &newcbd->xferdma); 1486 if (error) { 1487 printf("%s: unable to create cbd DMA map, error = %d\n", 1488 sc->sc_dev.dv_xname, error); 1489 goto bad1; 1490 } 1491 error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers, 1492 NBPG, NULL, BUS_DMA_NOWAIT); 1493 if (error) { 1494 printf("%s: unable to load cbd DMA map, error = %d\n", 1495 sc->sc_dev.dv_xname, error); 1496 goto bad0; 1497 } 1498 1499 for (i = 0; i < SIOP_NCMDPB; i++) { 1500 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG, 1501 MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1502 &newcbd->cmds[i].dmamap_data); 1503 if (error) { 1504 printf("%s: unable to create data DMA map for cbd: " 1505 "error %d\n", 1506 sc->sc_dev.dv_xname, error); 1507 goto bad0; 1508 } 1509 error = bus_dmamap_create(sc->sc_dmat, 1510 sizeof(struct scsipi_generic), 1, 1511 sizeof(struct scsipi_generic), 0, 1512 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1513 &newcbd->cmds[i].dmamap_cmd); 1514 if (error) { 1515 printf("%s: unable to create cmd DMA map for cbd %d\n", 1516 sc->sc_dev.dv_xname, error); 1517 goto bad0; 1518 } 1519 newcbd->cmds[i].siop_cbdp = newcbd; 1520 newcbd->cmds[i].siop_table = &newcbd->xfers[i]; 1521 memset(newcbd->cmds[i].siop_table, 0, sizeof(struct siop_xfer)); 1522 newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr + 1523 i * sizeof(struct siop_xfer); 1524 newcbd->cmds[i].status = CMDST_FREE; 1525 newcbd->cmds[i].siop_table->t_msgout.count= htole32(1); 1526 newcbd->cmds[i].siop_table->t_msgout.addr = 1527 htole32(newcbd->cmds[i].dsa); 1528 newcbd->cmds[i].siop_table->t_msgin.count= htole32(1); 1529 newcbd->cmds[i].siop_table->t_msgin.addr = 1530 htole32(newcbd->cmds[i].dsa + 8); 1531 newcbd->cmds[i].siop_table->t_extmsgin.count= htole32(2); 1532 newcbd->cmds[i].siop_table->t_extmsgin.addr = htole32( 1533 le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1); 1534 newcbd->cmds[i].siop_table->t_msgtag.count= htole32(2); 1535 newcbd->cmds[i].siop_table->t_msgtag.addr = htole32( 1536 le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1); 1537 newcbd->cmds[i].siop_table->t_status.count= htole32(1); 1538 newcbd->cmds[i].siop_table->t_status.addr = htole32( 1539 le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 8); 1540 TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next); 1541#ifdef DEBUG 1542 printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i, 1543 le32toh(newcbd->cmds[i].siop_table->t_msgin.addr), 1544 le32toh(newcbd->cmds[i].siop_table->t_msgout.addr), 1545 le32toh(newcbd->cmds[i].siop_table->t_status.addr)); 1546#endif 1547 } 1548 TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next); 1549 return 0; 1550bad0: 1551 bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma); 1552bad1: 1553 bus_dmamem_free(sc->sc_dmat, &seg, rseg); 1554bad2: 1555 free(newcbd->cmds, M_DEVBUF); 1556bad3: 1557 free(newcbd, M_DEVBUF); 1558 return error; 1559} 1560 1561#ifdef SIOP_STATS 1562void 1563siop_printstats() 1564{ 1565 printf("siop_stat_intr %d\n", siop_stat_intr); 1566 printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer); 1567 printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc); 1568 printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp); 1569 printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect); 1570 printf("siop_stat_intr_done %d\n", siop_stat_intr_done); 1571} 1572#endif 1573