📄 siop.c
字号:
for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL; cbdp = TAILQ_NEXT(cbdp, next)) { if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr && dsa < cbdp->xferdma->dm_segs[0].ds_addr + PAGE_SIZE) { dsa -= cbdp->xferdma->dm_segs[0].ds_addr; siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)]; siop_table_sync(siop_cmd, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); break; } } if (cbdp == NULL) { siop_cmd = NULL; } if (siop_cmd) { xs = siop_cmd->xs; siop_target = siop_cmd->siop_target; target = siop_cmd->xs->sc_link->target; lun = siop_cmd->xs->sc_link->lun; tag = siop_cmd->tag; siop_lun = siop_target->siop_lun[lun];#ifdef DIAGNOSTIC if (siop_cmd->status != CMDST_ACTIVE && siop_cmd->status != CMDST_SENSE_ACTIVE) { printf("siop_cmd (lun %d) not active (%d)\n", lun, siop_cmd->status); xs = NULL; siop_target = NULL; target = -1; lun = -1; tag = -1; siop_lun = NULL; siop_cmd = NULL; } else if (siop_lun->siop_tag[tag].active != siop_cmd) { printf("siop_cmd (lun %d tag %d) not in siop_lun " "active (%p != %p)\n", lun, tag, siop_cmd, siop_lun->siop_tag[tag].active); }#endif } else { xs = NULL; siop_target = NULL; target = -1; lun = -1; tag = -1; siop_lun = NULL; } if (istat & ISTAT_DIP) { dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);#ifdef DIAGNOSTIC printf("DSTAT: 0x%02x\n", dstat);#endif if (dstat & DSTAT_SSI) { printf("single step dsp 0x%08x dsa 0x%08x\n", bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); if ( bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) < 0xc0000000) { printf("* uncached inst 0x%08x 0x%08x\n", *(uint32_t*)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) + 0xa0000000), *(uint32_t*)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) + 0xa0000004)); printf("* cached inst 0x%08x 0x%08x\n", *(uint32_t*)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) + 0x80000000), *(uint32_t*)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) + 0x80000004)); } else { printf("* inst 0x%08x 0x%08x\n", siop_script_read(sc, (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - sc->sc_scriptaddr) / 4), siop_script_read(sc, (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - sc->sc_scriptaddr) / 4 + 1)); } if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 && (istat & ISTAT_SIP) == 0) { bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL) | DCNTL_STD); } return 1; } if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) { printf("DMA IRQ:"); if (dstat & DSTAT_IID) printf("Illegal instruction"); if (dstat & DSTAT_ABRT) printf(" abort"); if (dstat & DSTAT_BF) printf(" bus fault"); if (dstat & DSTAT_MDPE) printf(" parity"); if (dstat & DSTAT_DFE) printf(" dma fifo empty"); printf(", DSP=0x%x DSA=0x%x: ", bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA)); if (siop_cmd) printf("last msg_in=0x%x status=0x%x\n", siop_cmd->siop_tables.msg_in[0], letoh32(siop_cmd->siop_tables.status)); else printf("%s: current DSA invalid\n", sc->sc_dev.dv_xname); need_reset = 1; } } if (istat & ISTAT_SIP) { if (istat & ISTAT_DIP) delay(10); /* * Can't read sist0 & sist1 independantly, or we have to * insert delay */ sist = bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_SIST0); sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);#ifdef SIOP_DEBUG_INTR printf("scsi interrupt, sist=0x%x sstat1=0x%x " "DSA=0x%x DSP=0x%lx\n", sist, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));#endif if (sist & SIST0_RST) { siop_handle_reset(sc); siop_start(sc); /* no table to flush here */ return 1; } if (sist & SIST0_SGE) { if (siop_cmd) sc_print_addr(xs->sc_link); else printf("%s:", sc->sc_dev.dv_xname); printf("scsi gross error\n"); goto reset; } if ((sist & SIST0_MA) && need_reset == 0) { if (siop_cmd) { int scratcha0; dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT); /* * first restore DSA, in case we were in a S/G * operation. */ bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, siop_cmd->dsa); scratcha0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA); switch (sstat1 & SSTAT1_PHASE_MASK) { case SSTAT1_PHASE_STATUS: /* * Previous phase may have aborted for any reason * (for example, the target has less data to * transfer than requested). Just go to status * and the command should terminate. */ INCSTAT(siop_stat_intr_shortxfer); if ((dstat & DSTAT_DFE) == 0) siop_clearfifo(sc); /* no table to flush here */ CALL_SCRIPT(Ent_status); return 1; case SSTAT1_PHASE_MSGIN: /* * Target may be ready to disconnect. * Save data pointers just in case. */ INCSTAT(siop_stat_intr_xferdisc); if (scratcha0 & A_flag_data) siop_sdp(siop_cmd); else if ((dstat & DSTAT_DFE) == 0) siop_clearfifo(sc); bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA, scratcha0 & ~A_flag_data); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_msgin); return 1; } printf("%s: unexpected phase mismatch %d\n", sc->sc_dev.dv_xname, sstat1 & SSTAT1_PHASE_MASK); } else { printf("%s: phase mismatch without command\n", sc->sc_dev.dv_xname); } need_reset = 1; } if (sist & SIST0_PAR) { /* parity error, reset */ if (siop_cmd) sc_print_addr(xs->sc_link); else printf("%s:", sc->sc_dev.dv_xname); printf("parity error\n"); goto reset; } if ((sist & (SIST1_STO << 8)) && need_reset == 0) { /* selection time out, assume there's no device here */ if (siop_cmd) { siop_cmd->status = CMDST_DONE; xs->error = XS_SELTIMEOUT; freetarget = 1; goto end; } else { printf("%s: selection timeout without " "command\n", sc->sc_dev.dv_xname); need_reset = 1; } } if (sist & SIST0_UDC) { /* * unexpected disconnect. Usually the target signals * a fatal condition this way. Attempt to get sense. */ if (siop_cmd) { siop_cmd->siop_tables.status = htole32(SCSI_CHECK); goto end; } printf("%s: unexpected disconnect without " "command\n", sc->sc_dev.dv_xname); goto reset; } if (sist & (SIST1_SBMC << 8)) { /* SCSI bus mode change */ if (siop_modechange(sc) == 0 || need_reset == 1) goto reset; if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* * We have a script interrupt. It will * restart the script. */ goto scintr; } /* * Else we have to restart the script ourself, at the * interrupted instruction. */ bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - 8); return 1; } /* Else it's an unhandled exception (for now). */ printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x " "DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, sist, bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA), bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP)); if (siop_cmd) { siop_cmd->status = CMDST_DONE; xs->error = XS_SELTIMEOUT; goto end; } need_reset = 1; } if (need_reset) {reset: /* fatal error, reset the bus */ siop_resetbus(sc); /* no table to flush here */ return 1; }scintr: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSPS);#ifdef SIOP_DEBUG_INTR printf("script interrupt 0x%x\n", irqcode);#endif /* * no command, or an inactive command is only valid for a * reselect interrupt */ if ((irqcode & 0x80) == 0) { if (siop_cmd == NULL) { printf("%s: script interrupt (0x%x) with " "invalid DSA !!!\n", sc->sc_dev.dv_xname, irqcode); goto reset; } if (siop_cmd->status != CMDST_ACTIVE && siop_cmd->status != CMDST_SENSE_ACTIVE) { printf("%s: command with invalid status " "(IRQ code 0x%x current status %d) !\n", sc->sc_dev.dv_xname, irqcode, siop_cmd->status); xs = NULL; } } switch(irqcode) { case A_int_err: printf("error, DSP=0x%x\n", (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) - sc->sc_scriptaddr)); if (xs) { xs->error = XS_SELTIMEOUT; goto end; } else { goto reset; } case A_int_reseltarg: printf("%s: reselect with invalid target\n", sc->sc_dev.dv_xname); goto reset; case A_int_resellun: INCSTAT(siop_stat_intr_lunresel); target = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA) & 0xf; lun = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1); tag = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 2); siop_target = sc->targets[target]; if (siop_target == NULL) { printf("%s: reselect with invalid " "target %d\n", sc->sc_dev.dv_xname, target); goto reset; } siop_lun = siop_target->siop_lun[lun]; if (siop_lun == NULL) { printf("%s: target %d reselect with invalid " "lun %d\n", sc->sc_dev.dv_xname, target, lun); goto reset; } if (siop_lun->siop_tag[tag].active == NULL) { printf("%s: target %d lun %d tag %d reselect " "without command\n", sc->sc_dev.dv_xname, target, lun, tag); goto reset; } siop_cmd = siop_lun->siop_tag[tag].active; bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, siop_cmd->dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_reload_dsa); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); return 1; case A_int_reseltag: printf("%s: reselect with invalid tag\n", sc->sc_dev.dv_xname); goto reset; case A_int_msgin: { int msgin = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SFBR); if (msgin == MSG_MESSAGE_REJECT) { int msg, extmsg; if (siop_cmd->siop_tables.msg_out[0] & 0x80) { /* * Message was part of an identify + * something else. Identify shouldn't * have been rejected. */ msg = siop_cmd->siop_tables.msg_out[1]; extmsg = siop_cmd->siop_tables.msg_out[3]; } else { msg = siop_cmd->siop_tables.msg_out[0]; extmsg = siop_cmd->siop_tables.msg_out[2]; } if (msg == MSG_MESSAGE_REJECT) { /* MSG_REJECT for a MSG_REJECT! */ if (xs) sc_print_addr(xs->sc_link); else printf("%s: ", sc->sc_dev.dv_xname); printf("our reject message was " "rejected\n"); goto reset; } if (msg == MSG_EXTENDED && extmsg == MSG_EXT_WDTR) { if ((siop_target->flags & TARF_SYNC) == 0) { siop_target->status = TARST_OK; siop_print_info(sc, target); /* no table to flush here */ CALL_SCRIPT(Ent_msgin_ack); return 1; } siop_target->status = TARST_SYNC_NEG; siop_sdtr_msg(siop_cmd, 0, sc->min_st_sync, sc->maxoff); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_send_msgout); return 1; } else if (msg == MSG_EXTENDED && extmsg == MSG_EXT_SDTR) { siop_target->status = TARST_OK; siop_print_info(sc, target); /* no table to flush here */ CALL_SCRIPT(Ent_msgin_ack); return 1; } else if (msg == MSG_SIMPLE_Q_TAG || msg == MSG_HEAD_OF_Q_TAG || msg == MSG_ORDERED_Q_TAG) { if (siop_handle_qtag_reject( siop_cmd) == -1) goto reset; CALL_SCRIPT(Ent_msgin_ack); return 1; } if (xs) sc_print_addr(xs->sc_link); else printf("%s: ", sc->sc_dev.dv_xname); if (msg == MSG_EXTENDED) { printf("scsi message reject, extended " "message sent was 0x%x\n", extmsg); } else { printf("scsi message reject, message " "sent was 0x%x\n", msg); } /* no table to flush here */ CALL_SCRIPT(Ent_msgin_ack); return 1; } if (xs) sc_print_addr(xs->sc_link); else printf("%s: ", sc->sc_dev.dv_xname); printf("unhandled message 0x%x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -