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