📄 siop.c
字号:
siop_cmd->siop_tables.msg_in[0]); siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; siop_cmd->siop_tables.t_msgout.count= htole32(1); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_send_msgout); return 1; } case A_int_extmsgin:#ifdef SIOP_DEBUG_INTR printf("extended message: msg 0x%x len %d\n", siop_cmd->siop_tables.msg_in[2], siop_cmd->siop_tables.msg_in[1]);#endif if (siop_cmd->siop_tables.msg_in[1] > 6) printf("%s: extended message too big (%d)\n", sc->sc_dev.dv_xname, siop_cmd->siop_tables.msg_in[1]); siop_cmd->siop_tables.t_extmsgdata.count = htole32(siop_cmd->siop_tables.msg_in[1] - 1); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_get_extmsgdata); return 1; case A_int_extmsgdata: { int neg_action = SIOP_NEG_NOP; const char *neg_name = "";#ifdef SIOP_DEBUG_INTR { int i; printf("extended message: 0x%x, data:", siop_cmd->siop_tables.msg_in[2]); for (i = 3; i < 2 + siop_cmd->siop_tables.msg_in[1]; i++) printf(" 0x%x", siop_cmd->siop_tables.msg_in[i]); printf("\n"); }#endif switch (siop_cmd->siop_tables.msg_in[2]) { case MSG_EXT_WDTR: neg_action = siop_wdtr_neg(siop_cmd); neg_name = "wdtr"; break; case MSG_EXT_SDTR: neg_action = siop_sdtr_neg(siop_cmd); neg_name = "sdtr"; break; case MSG_EXT_PPR: neg_action = siop_ppr_neg(siop_cmd); neg_name = "ppr"; break; default: neg_action = SIOP_NEG_MSGREJ; break; } switch (neg_action) { case SIOP_NEG_NOP: break; case SIOP_NEG_MSGOUT: siop_update_scntl3(sc, siop_cmd->siop_target); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_send_msgout); break; case SIOP_NEG_ACK: siop_update_scntl3(sc, siop_cmd->siop_target); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_msgin_ack); break; case SIOP_NEG_MSGREJ: siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT; siop_cmd->siop_tables.t_msgout.count = htole32(1); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); CALL_SCRIPT(Ent_send_msgout); break; default: panic("invalid return value from siop_%s_neg(): 0x%x", neg_name, neg_action); } return (1); } case A_int_disc: INCSTAT(siop_stat_intr_sdp); offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);#ifdef SIOP_DEBUG_DR printf("disconnect offset %d\n", offset);#endif if (offset > SIOP_NSG) { printf("%s: bad offset for disconnect (%d)\n", sc->sc_dev.dv_xname, offset); goto reset; } /* * offset == SIOP_NSG may be a valid condition if * we get a sdp when the xfer is done. * Don't call memmove in this case. */ if (offset < SIOP_NSG) { bcopy(&siop_cmd->siop_tables.data[offset], &siop_cmd->siop_tables.data[0], (SIOP_NSG - offset) * sizeof(struct scr_table)); siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } CALL_SCRIPT(Ent_script_sched); /* check if we can put some command in scheduler */ siop_start(sc); return 1; case A_int_resfail: printf("reselect failed\n"); CALL_SCRIPT(Ent_script_sched); return 1; case A_int_done: if (xs == NULL) { printf("%s: done without command, DSA=0x%lx\n", sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa); siop_cmd->status = CMDST_FREE; siop_start(sc); CALL_SCRIPT(Ent_script_sched); return 1; }#ifdef SIOP_DEBUG_INTR printf("done, DSA=0x%lx target id 0x%x last msg " "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa, letoh32(siop_cmd->siop_tables.id), siop_cmd->siop_tables.msg_in[0], letoh32(siop_cmd->siop_tables.status));#endif INCSTAT(siop_stat_intr_done); if (siop_cmd->status == CMDST_SENSE_ACTIVE) siop_cmd->status = CMDST_SENSE_DONE; else siop_cmd->status = CMDST_DONE; goto end; default: printf("unknown irqcode %x\n", irqcode); if (xs) { xs->error = XS_SELTIMEOUT; goto end; } goto reset; } return 1; } /* We can get here if ISTAT_DIP and DSTAT_DFE are the only bits set. */ /* But that *SHOULDN'T* happen. It does on powerpc (at least). */ printf("%s: siop_intr() - we should not be here!\n" " istat = 0x%x, dstat = 0x%x, sist = 0x%x, sstat1 = 0x%x\n" " need_reset = %x, irqcode = %x, siop_cmd %s\n", sc->sc_dev.dv_xname, istat, dstat, sist, sstat1, need_reset, irqcode, (siop_cmd == NULL) ? "== NULL" : "!= NULL"); goto reset; /* Where we should have gone in the first place! */end: /* * Restart the script now if command completed properly. * Otherwise wait for siop_scsicmd_end(), it may need to put * a cmd at the front of the queue. */ if (letoh32(siop_cmd->siop_tables.status) == SCSI_OK && TAILQ_FIRST(&sc->urgent_list) != NULL) CALL_SCRIPT(Ent_script_sched); else restart = 1; siop_scsicmd_end(siop_cmd); siop_lun->siop_tag[tag].active = NULL; if (siop_cmd->status == CMDST_FREE) { TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); siop_lun->lun_flags &= ~SIOP_LUNF_FULL; if (freetarget && siop_target->status == TARST_PROBING) siop_del_dev(sc, target, lun); } siop_start(sc); if (restart) CALL_SCRIPT(Ent_script_sched); return 1;}voidsiop_scsicmd_end(siop_cmd) struct siop_cmd *siop_cmd;{ struct scsi_xfer *xs = siop_cmd->xs; struct siop_softc *sc = siop_cmd->siop_sc; switch(letoh32(siop_cmd->siop_tables.status)) { case SCSI_OK: xs->error = (siop_cmd->status == CMDST_DONE) ? XS_NOERROR : XS_SENSE; break; case SCSI_BUSY: xs->error = XS_BUSY; break; case SCSI_CHECK: if (siop_cmd->status == CMDST_SENSE_DONE) { /* request sense on a request sense ? */ printf("request sense failed\n"); xs->error = XS_DRIVER_STUFFUP; } else { siop_cmd->status = CMDST_SENSE; } break; case SCSI_QUEUE_FULL: { struct siop_lun *siop_lun = siop_cmd->siop_target->siop_lun[ xs->sc_link->lun]; /* * Device didn't queue the command. We have to retry * it. We insert it into the urgent list, hoping to * preserve order. But unfortunately, commands already * in the scheduler may be accepted before this one. * Also remember the condition, to avoid starting new * commands for this device before one is done. */ INCSTAT(siop_stat_intr_qfull);#ifdef SIOP_DEBUG printf("%s:%d:%d: queue full (tag %d)\n", sc->sc_dev.dv_xname, xs->sc_link->target, xs->sc_link->lun, siop_cmd->tag);#endif#ifndef PMON timeout_del(&xs->stimeout);#endif siop_lun->lun_flags |= SIOP_LUNF_FULL; siop_cmd->status = CMDST_READY; siop_setuptables(siop_cmd); TAILQ_INSERT_TAIL(&sc->urgent_list, siop_cmd, next); return; } case SCSI_SIOP_NOCHECK: /* * don't check status, xs->error is already valid */ break; case SCSI_SIOP_NOSTATUS: /* * the status byte was not updated, cmd was * aborted */ xs->error = XS_SELTIMEOUT; break; default: xs->error = XS_DRIVER_STUFFUP; } if (siop_cmd->status != CMDST_SENSE_DONE && xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, siop_cmd->dmamap_data->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); } bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); if (siop_cmd->status == CMDST_SENSE) { /* issue a request sense for this target */ int error; siop_cmd->rs_cmd.opcode = REQUEST_SENSE; siop_cmd->rs_cmd.byte2 = xs->sc_link->lun << 5; siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0; siop_cmd->rs_cmd.length = sizeof(struct scsi_sense_data); siop_cmd->rs_cmd.control = 0; siop_cmd->flags &= ~CMDFL_TAG; error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, &siop_cmd->rs_cmd, sizeof(struct scsi_sense), NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cmd DMA map " "(for SENSE): %d\n", sc->sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; goto out; } error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, &xs->sense, sizeof(struct scsi_sense_data), NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load data DMA map " "(for SENSE): %d\n", sc->sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); goto out; } bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD); bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); siop_setuptables(siop_cmd); /* arrange for the cmd to be handled now */ TAILQ_INSERT_HEAD(&sc->urgent_list, siop_cmd, next); return; } else if (siop_cmd->status == CMDST_SENSE_DONE) { bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data); }out:#ifndef PMON timeout_del(&siop_cmd->xs->stimeout);#endif siop_cmd->status = CMDST_FREE; xs->flags |= ITSDONE; xs->resid = 0; scsi_done(xs);}/* * handle a rejected queue tag message: the command will run untagged, * has to adjust the reselect script. */intsiop_handle_qtag_reject(siop_cmd) struct siop_cmd *siop_cmd;{ struct siop_softc *sc = siop_cmd->siop_sc; int target = siop_cmd->xs->sc_link->target; int lun = siop_cmd->xs->sc_link->lun; int tag = siop_cmd->siop_tables.msg_out[2]; struct siop_lun *siop_lun = sc->targets[target]->siop_lun[lun];#ifdef SIOP_DEBUG printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n", sc->sc_dev.dv_xname, target, lun, tag, siop_cmd->tag, siop_cmd->status);#endif if (siop_lun->siop_tag[0].active != NULL) { printf("%s: untagged command already running for target %d " "lun %d (status %d)\n", sc->sc_dev.dv_xname, target, lun, siop_lun->siop_tag[0].active->status); return -1; } /* clear tag slot */ siop_lun->siop_tag[tag].active = NULL; /* add command to non-tagged slot */ siop_lun->siop_tag[0].active = siop_cmd; siop_cmd->tag = 0; /* adjust reselect script if there is one */ if (siop_lun->siop_tag[0].reseloff > 0) { siop_script_write(sc, siop_lun->siop_tag[0].reseloff + 1, siop_cmd->dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_reload_dsa); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); } return 0;}/* * Handle a bus reset: reset chip, unqueue all active commands, free all * target structs and report losage to upper layer. * As the upper layer may requeue immediately we have to first store * all active commands in a temporary queue. */voidsiop_handle_reset(sc) struct siop_softc *sc;{ struct cmd_list reset_list; struct siop_cmd *siop_cmd, *next_siop_cmd; struct siop_lun *siop_lun; int target, lun, tag; /* * SCSI bus reset. Reset the chip and restart * the queue. Need to clean up all active commands. */ printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname); /* stop, reset and restart the chip */ siop_reset(sc); TAILQ_INIT(&reset_list); /* * Process all commands: first commmands being executed */ for (target = 0; target < sc->sc_link.adapter_buswidth; target++) { if (sc->targets[target] == NULL) continue; for (lun = 0; lun < 8; lun++) { siop_lun = sc->targets[target]->siop_lun[lun]; if (siop_lun == NULL) continue; siop_lun->lun_flags &= ~SIOP_LUNF_FULL; for (tag = 0; tag < ((sc->targets[target]->flags & TARF_TAG) ? SIOP_NTAG : 1); tag++) { siop_cmd = siop_lun->siop_tag[tag].active; if (siop_cmd == NULL) continue; printf("cmd %p (target %d:%d) in reset list\n", siop_cmd, target, lun); TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); siop_lun->siop_tag[tag].active = NULL; } } sc->targets[target]->status = TARST_ASYNC; sc->targets[target]->flags = 0; } /* Next commands from the urgent list */ for (siop_cmd = TAILQ_FIRST(&sc->urgent_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); siop_cmd->flags &= ~CMDFL_TAG; printf("cmd %p (target %d:%d) in reset list (wait)\n", siop_cmd, siop_cmd->xs->sc_link->target, siop_cmd->xs->sc_link->lun); TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next); TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); } /* Then command waiting in the input list */ for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); siop_cmd->flags &= ~CMDFL_TAG; printf("cmd %p (target %d:%d) in reset list (wait)\n", siop_cmd, siop_cmd->xs->sc_link->target, siop_cmd->xs->sc_link->lun);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -