📄 siop.c
字号:
TAILQ_REMOVE(&sc->ready_list, siop_cmd, next); TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next); } for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next); siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ? XS_TIMEOUT : XS_RESET; siop_cmd->siop_tables.status = htole32(SCSI_SIOP_NOCHECK); printf("cmd %p (status %d) about to be processed\n", siop_cmd, siop_cmd->status); if (siop_cmd->status == CMDST_SENSE || siop_cmd->status == CMDST_SENSE_ACTIVE) siop_cmd->status = CMDST_SENSE_DONE; else siop_cmd->status = CMDST_DONE; TAILQ_REMOVE(&reset_list, siop_cmd, next); siop_scsicmd_end(siop_cmd); TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); }}intsiop_scsicmd(xs) struct scsi_xfer *xs;{ struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc; struct siop_cmd *siop_cmd; int s, error, i, j; const int target = xs->sc_link->target; const int lun = xs->sc_link->lun; s = splbio();#ifdef SIOP_DEBUG_SCHED printf("starting cmd 0x%02x for %d:%d\n", xs->cmd->opcode, target, lun);#endif siop_cmd = TAILQ_FIRST(&sc->free_list); if (siop_cmd != NULL) { TAILQ_REMOVE(&sc->free_list, siop_cmd, next); } else { xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); }#ifndef PMON /* Always reset xs->stimeout, lest we timeout_del() with trash */ timeout_set(&xs->stimeout, siop_timeout, siop_cmd);#endif#ifdef DIAGNOSTIC if (siop_cmd->status != CMDST_FREE) panic("siop_scsicmd: new cmd not free");#endif if (sc->targets[target] == NULL) {#ifdef SIOP_DEBUG printf("%s: alloc siop_target for target %d\n", sc->sc_dev.dv_xname, target);#endif sc->targets[target] = malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT); if (sc->targets[target] == NULL) { printf("%s: can't malloc memory for target %d\n", sc->sc_dev.dv_xname, target); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } sc->targets[target]->status = TARST_PROBING; sc->targets[target]->flags = 0; sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */ sc->targets[target]->id |= target << 16; /* id */ /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */ /* get a lun switch script */ sc->targets[target]->lunsw = siop_get_lunsw(sc); if (sc->targets[target]->lunsw == NULL) { printf("%s: can't alloc lunsw for target %d\n", sc->sc_dev.dv_xname, target); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } for (i=0; i < 8; i++) sc->targets[target]->siop_lun[i] = NULL; siop_add_reselsw(sc, target); } if (sc->targets[target]->siop_lun[lun] == NULL) { sc->targets[target]->siop_lun[lun] = malloc(sizeof(struct siop_lun), M_DEVBUF, M_NOWAIT); if (sc->targets[target]->siop_lun[lun] == NULL) { printf("%s: can't alloc siop_lun for target %d " "lun %d\n", sc->sc_dev.dv_xname, target, lun); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } memset(sc->targets[target]->siop_lun[lun], 0, sizeof(struct siop_lun)); } siop_cmd->siop_target = sc->targets[target]; siop_cmd->xs = xs; siop_cmd->flags = 0; siop_cmd->status = CMDST_READY; /* load the DMA maps */ error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd, xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cmd DMA map: %d\n", sc->sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; splx(s); return(TRY_AGAIN_LATER); } if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) { error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data, xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT); if (error) { printf("%s: unable to load cmd DMA map: %d\n", sc->sc_dev.dv_xname, error); xs->error = XS_DRIVER_STUFFUP; bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd); splx(s); return(TRY_AGAIN_LATER); } bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0, siop_cmd->dmamap_data->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); } bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0, siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE); siop_setuptables(siop_cmd); TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next); siop_start(sc); if (xs->flags & SCSI_POLL) { /* poll for command completion */ for(i = xs->timeout; i > 0; i--) { siop_intr(sc); if (xs->flags & ITSDONE) { if ((xs->cmd->opcode == INQUIRY) && (xs->error == XS_NOERROR)) { error = ((struct scsi_inquiry_data *)xs->data)->device & SID_QUAL; if (error != SID_QUAL_BAD_LU) { /* * Allocate enough commands to hold at least max openings * worth of commands. Do this statically now 'cuz * a) We can't rely on the upper layers to ask for more * b) Doing it dynamically in siop_startcmd may cause * calls to bus_dma* functions in interrupt context */ for (j = 0; j < SIOP_NTAG; j += SIOP_NCMDPB) siop_morecbd(sc); if (sc->targets[target]->status == TARST_PROBING) sc->targets[target]->status = TARST_ASYNC; /* Can't do lun 0 here, because flags not set yet */ if (lun > 0) siop_add_dev(sc, target, lun); } } break; } delay(1000); } splx(s); if (i == 0) { siop_timeout(siop_cmd); while ((xs->flags & ITSDONE) == 0) siop_intr(sc); } return (COMPLETE); } splx(s); return (SUCCESSFULLY_QUEUED);}voidsiop_start(sc) struct siop_softc *sc;{ struct siop_cmd *siop_cmd, *next_siop_cmd; struct siop_lun *siop_lun; u_int32_t dsa;#ifndef PMON int timeout;#endif int target, lun, tag, slot; int newcmd = 0; int doingready = 0; /* * first make sure to read valid data */ siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* * The queue management here is a bit tricky: the script always looks * at the slots from first to last, so if we always use the first * free slot commands can stay at the tail of the queue ~forever. * The algorithm used here is to restart from the head when we know * that the queue is empty, and only add commands after the last one. * When we're at the end of the queue wait for the script to clear it. * The best thing to do here would be to implement a circular queue, * but using only 53c720 features this can be "interesting". * A mid-way solution could be to implement 2 queues and swap orders. */ slot = sc->sc_currschedslot; /* * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is * free. As this is the last used slot, all previous slots are free, * we can restart from 1. * slot 0 is reserved for request sense commands. */ if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) == 0x80000000) { slot = sc->sc_currschedslot = 1; } else { slot++; } /* first handle commands from the urgent list */ siop_cmd = TAILQ_FIRST(&sc->urgent_list);again: for (; siop_cmd != NULL; siop_cmd = next_siop_cmd) { next_siop_cmd = TAILQ_NEXT(siop_cmd, next);#ifdef DIAGNOSTIC if (siop_cmd->status != CMDST_READY && siop_cmd->status != CMDST_SENSE) panic("siop: non-ready cmd in ready list");#endif target = siop_cmd->xs->sc_link->target; lun = siop_cmd->xs->sc_link->lun; siop_lun = sc->targets[target]->siop_lun[lun]; /* if non-tagged command active, wait */ if (siop_lun->siop_tag[0].active != NULL) continue; /* * if we're in a queue full condition don't start a new * command, unless it's a request sense */ if ((siop_lun->lun_flags & SIOP_LUNF_FULL) && siop_cmd->status == CMDST_READY) continue; /* find a free tag if needed */ if (siop_cmd->flags & CMDFL_TAG) { for (tag = 1; tag < SIOP_NTAG; tag++) { if (siop_lun->siop_tag[tag].active == NULL) break; } if (tag == SIOP_NTAG) /* no free tag */ continue; } else { tag = 0; } siop_cmd->tag = tag; /* * find a free scheduler slot and load it. If it's a request * sense we need to use slot 0. */ if (siop_cmd->status != CMDST_SENSE) { for (; slot < SIOP_NSLOTS; slot++) { /* * If cmd if 0x80000000 the slot is free */ if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) == 0x80000000) break; } /* no more free slots, no need to continue */ if (slot == SIOP_NSLOTS) { goto end; } } else { slot = 0; if (siop_script_read(sc, Ent_script_sched_slot0 / 4) != 0x80000000) goto end; }#ifdef SIOP_DEBUG_SCHED printf("using slot %d for DSA 0x%lx\n", slot, (u_long)siop_cmd->dsa);#endif /* Ok, we can add the tag message */ if (tag > 0) {#ifdef DIAGNOSTIC int msgcount = letoh32(siop_cmd->siop_tables.t_msgout.count); if (msgcount != 1) printf("%s:%d:%d: tag %d with msgcount %d\n", sc->sc_dev.dv_xname, target, lun, tag, msgcount);#endif if (siop_cmd->xs->bp != NULL && (siop_cmd->xs->bp->b_flags & B_ASYNC)) siop_cmd->siop_tables.msg_out[1] = MSG_SIMPLE_Q_TAG; else siop_cmd->siop_tables.msg_out[1] = MSG_ORDERED_Q_TAG; siop_cmd->siop_tables.msg_out[2] = tag; siop_cmd->siop_tables.t_msgout.count = htole32(3); } /* note that we started a new command */ newcmd = 1; /* mark command as active */ if (siop_cmd->status == CMDST_READY) { siop_cmd->status = CMDST_ACTIVE; } else if (siop_cmd->status == CMDST_SENSE) { siop_cmd->status = CMDST_SENSE_ACTIVE; } else panic("siop_start: bad status"); if (doingready) TAILQ_REMOVE(&sc->ready_list, siop_cmd, next); else TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next); siop_lun->siop_tag[tag].active = siop_cmd; /* patch scripts with DSA addr */ dsa = siop_cmd->dsa; /* first reselect switch, if we have an entry */ if (siop_lun->siop_tag[tag].reseloff > 0) siop_script_write(sc, siop_lun->siop_tag[tag].reseloff + 1, dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_reload_dsa); /* CMD script: MOVE MEMORY addr */ siop_cmd->siop_xfer->resel[E_ldsa_abs_slot_Used[0]] = htole32(sc->sc_scriptaddr + Ent_script_sched_slot0 + slot * 8); siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE); /* scheduler slot: JUMP ldsa_select */ siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2 + 1, dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_select);#ifndef PMON /* handle timeout */ if (siop_cmd->status == CMDST_ACTIVE) { if ((siop_cmd->xs->flags & SCSI_POLL) == 0) { /* start expire timer */ timeout = (u_int64_t) siop_cmd->xs->timeout * (u_int64_t)hz / 1000; if (timeout == 0) timeout = 1; timeout_add(&siop_cmd->xs->stimeout, timeout); } }#endif /* * Change JUMP cmd so that this slot will be handled */ siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2, 0x80080000); /* if we're using the request sense slot, stop here */ if (slot == 0) goto end; sc->sc_currschedslot = slot; slot++; } if (doingready == 0) { /* now process ready list */ doingready = 1; siop_cmd = TAILQ_FIRST(&sc->ready_list); goto again; }end: /* if nothing changed no need to flush cache and wakeup script */ if (newcmd == 0) return; /* make sure SCRIPT processor will read valid data */ siop_script_sync(sc,BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Signal script it has some work to do */ bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP); /* and wait for IRQ */ return;}voidsiop_timeout(v) void *v;{ struct siop_cmd *siop_cmd = v; struct siop_softc *sc = siop_cmd->siop_sc; int s; sc_print_addr(siop_cmd->xs->sc_link); printf("timeout on SCSI command 0x%x\n", siop_cmd->xs->cmd->opcode); s = splbio(); /* reset the scsi bus */ siop_resetbus(sc);#ifndef PMON /* deactivate callout */ timeout_del(&siop_cmd->xs->stimeout);#endif /* * Mark command as being timed out and just return. The bus * reset will generate an interrupt, which will be handled * in siop_intr(). */ siop_cmd->flags |= CMDFL_TIMEOUT; splx(s); return;}voidsiop_dump_script(sc) struct siop_softc *sc;{ int i; printf("Dumping script @ 0x%08x:\n", sc->sc_script); for (i = 0; i < PAGE_SIZE / 4; i += 2) { printf("0x%04x: 0x%08x 0x%08x", i * 4, siop_script_read(sc, i), siop_script_read(sc, i+1)); if ((siop_script_read(sc, i) & 0xe0000000) == 0xc0000000) { i++; printf(" 0x%08x", siop_script_read(sc, i+1)); } printf("\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -