📄 cy.c
字号:
yc->yc_blkno++; goto opcont; } } else /* * Hard or non-i/o errors on non-raw tape * cause it to close. */ if ((bp->b_flags&B_RAW) == 0 && yc->yc_openf > 0) yc->yc_openf = -1; /* * Couldn't recover from error. */ tprintf(yc->yc_tpr, "yc%d: hard error bn%d status=%b, %s\n", YCUNIT(bp->b_dev), bp->b_blkno, yc->yc_status, CYS_BITS, (err < NCYERROR) ? cyerror[err] : ""); bp->b_flags |= B_ERROR; goto opdone; } else if (cy->cy_tpb.tpcmd == CY_BRCOM) { int reclen = htoms(cy->cy_tpb.tprec); /* * If we did a buffered read, check whether the read * was long enough. If we asked the controller for less * than the user asked for because the previous record * was shorter, update our notion of record size * and retry. If the record is longer than the buffer, * bump the errcnt so the retry will use direct read. */ if (reclen > yc->yc_blksize && bp->b_bcount > yc->yc_blksize) { yc->yc_blksize = reclen; if (reclen > cy->cy_bs) vm->um_tab.b_errcnt++; yc->yc_blkno++; goto opcont; } } /* * Advance tape control FSM. */ignoreerr: /* * If we hit a tape mark update our position. */ if (yc->yc_status&CYS_FM && bp->b_flags&B_READ) { cyseteof(bp); goto opdone; } switch (state) { case SIO: /* * Read/write increments tape block number. */ yc->yc_blkno++; yc->yc_blks++; if (vm->um_tab.b_errcnt || yc->yc_status & CYS_CR) yc->yc_softerrs++; yc->yc_blksize = htoms(cy->cy_tpb.tpcount); dlog((LOG_ERR, "blocksize %d", yc->yc_blksize)); goto opdone; case SCOM: /* * For forward/backward space record update current position. */ if (bp == &ccybuf[CYUNIT(bp->b_dev)]) switch ((int)bp->b_command) { case CY_SFORW: yc->yc_blkno -= bp->b_repcnt; break; case CY_SREV: yc->yc_blkno += bp->b_repcnt; break; } goto opdone; case SSEEK: yc->yc_blkno = bp->b_blkno; goto opcont; case SERASE: /* * Completed erase of the inter-record gap due to a * write error; now retry the write operation. */ vm->um_tab.b_active = SERASED; goto opcont; }opdone: /* * Reset error count and remove from device queue. */ vm->um_tab.b_errcnt = 0; dp->b_actf = bp->av_forw; /* * Save resid and release resources. */ bp->b_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount); if (bp != &ccybuf[cyunit]) vbadone(bp, &cy->cy_rbuf); biodone(bp); /* * Circulate slave to end of controller * queue to give other slaves a chance. */ vm->um_tab.b_actf = dp->b_forw; if (dp->b_actf) { dp->b_forw = NULL; if (vm->um_tab.b_actf == NULL) vm->um_tab.b_actf = dp; else vm->um_tab.b_actl->b_forw = dp; } if (vm->um_tab.b_actf == 0) return;opcont: cystart(vm);}cytimer(dev) int dev;{ register struct yc_softc *yc = &yc_softc[YCUNIT(dev)]; int s; if (yc->yc_openf == 0 && yc->yc_timo == INF) { yc->yc_tact = 0; return; } if (yc->yc_timo != INF && (yc->yc_timo -= 5) < 0) { printf("yc%d: lost interrupt\n", YCUNIT(dev)); yc->yc_timo = INF; s = spl3(); cyintr(CYUNIT(dev)); splx(s); } timeout(cytimer, (caddr_t)dev, 5*hz);}cyseteof(bp) register struct buf *bp;{ register int cyunit = CYUNIT(bp->b_dev); register struct cy_softc *cy = &cy_softc[cyunit]; register struct yc_softc *yc = &yc_softc[YCUNIT(bp->b_dev)]; if (bp == &ccybuf[cyunit]) { if (yc->yc_blkno > bp->b_blkno) { /* reversing */ yc->yc_nxrec = bp->b_blkno - htoms(cy->cy_tpb.tpcount); yc->yc_blkno = yc->yc_nxrec; } else { yc->yc_blkno = bp->b_blkno + htoms(cy->cy_tpb.tpcount); yc->yc_nxrec = yc->yc_blkno - 1; } return; } /* eof on read */ yc->yc_nxrec = bp->b_blkno;}/*ARGSUSED*/cyioctl(dev, cmd, data, flag) caddr_t data; dev_t dev;{ int ycunit = YCUNIT(dev); register struct yc_softc *yc = &yc_softc[ycunit]; register struct buf *bp = &ccybuf[CYUNIT(dev)]; register callcount; int fcount, op; struct mtop *mtop; struct mtget *mtget; /* we depend of the values and order of the MT codes here */ static cyops[] = {CY_WEOF,CY_FSF,CY_BSF,CY_SFORW,CY_SREV,CY_REW,CY_OFFL,CY_SENSE}; switch (cmd) { case MTIOCTOP: /* tape operation */ mtop = (struct mtop *)data; switch (op = mtop->mt_op) { case MTWEOF: callcount = mtop->mt_count; fcount = 1; break; case MTFSR: case MTBSR: callcount = 1; fcount = mtop->mt_count; break; case MTFSF: case MTBSF: callcount = mtop->mt_count; fcount = 1; break; case MTREW: case MTOFFL: case MTNOP: callcount = 1; fcount = 1; break; default: return (ENXIO); } if (callcount <= 0 || fcount <= 0) return (EINVAL); while (--callcount >= 0) {#ifdef notdef /* * Gagh, this controller is the pits... */ if (op == MTFSF || op == MTBSF) { do cycommand(dev, cyops[op], 1); while ((bp->b_flags&B_ERROR) == 0 && (yc->yc_status&(CYS_EOT|CYS_BOT|CYS_FM)) == 0); } else#endif cycommand(dev, cyops[op], fcount); dlog((LOG_INFO, "cyioctl: status %x, b_flags %x, resid %d\n", yc->yc_status, bp->b_flags, bp->b_resid)); if ((bp->b_flags&B_ERROR) || (yc->yc_status&(CYS_BOT|CYS_EOT))) break; } bp->b_resid = callcount + 1; /* * Pick up the device's error number and pass it * to the user; if there is an error but the number * is 0 set a generalized code. */ if ((bp->b_flags & B_ERROR) == 0) return (0); if (bp->b_error) return (bp->b_error); return (EIO); case MTIOCGET: cycommand(dev, CY_SENSE, 1); mtget = (struct mtget *)data; mtget->mt_dsreg = yc->yc_status; mtget->mt_erreg = yc->yc_control; mtget->mt_resid = yc->yc_resid; mtget->mt_type = MT_ISCY; break; default: return (ENXIO); } return (0);}/* * Poll until the controller is ready. */cywait(cp) register struct cyccb *cp;{ register int i = 5000; uncache(&cp->cbgate); while (i-- > 0 && cp->cbgate == GATE_CLOSED) { DELAY(1000); uncache(&cp->cbgate); } return (i <= 0);}/* * Load a 20 bit pointer into a Tapemaster pointer. */cyldmba(reg, value) register u_char *reg; caddr_t value;{ register int v = (int)value; *reg++ = v; *reg++ = v >> 8; *reg++ = 0; *reg = (v&0xf0000) >> 12;}/* * Unconditionally reset all controllers to their initial state. */cyreset(vba) int vba;{ register caddr_t addr; register int ctlr; for (ctlr = 0; ctlr < NCY; ctlr++) if (cyminfo[ctlr] && cyminfo[ctlr]->um_vbanum == vba) { addr = cyminfo[ctlr]->um_addr; CY_RESET(addr); if (!cyinit(ctlr, addr)) { printf("cy%d: reset failed\n", ctlr); cyminfo[ctlr] = NULL; } }}cyuncachetpb(cy) struct cy_softc *cy;{ register long *lp = (long *)&cy->cy_tpb; register int i; for (i = 0; i < howmany(sizeof (struct cytpb), sizeof (long)); i++) uncache(lp++);}/* * Dump routine. */#define DUMPREC (32*1024)cydump(dev) dev_t dev;{ register struct cy_softc *cy; register int bs, num, start; register caddr_t addr; int unit = CYUNIT(dev), error; if (unit >= NCY || cyminfo[unit] == 0 || (cy = &cy_softc[unit])->cy_bs == 0 || YCUNIT(dev) >= NYC) return (ENXIO); if (cywait(&cy->cy_ccb)) return (EFAULT);#define phys(a) ((caddr_t)((int)(a)&~0xc0000000)) addr = phys(cyminfo[unit]->um_addr); num = maxfree, start = NBPG*2; while (num > 0) { bs = num > btoc(DUMPREC) ? btoc(DUMPREC) : num; error = cydwrite(cy, start, bs, addr); if (error) return (error); start += bs, num -= bs; } cyweof(cy, addr); cyweof(cy, addr); uncache(&cy->cy_tpb); if (cy->cy_tpb.tpstatus&CYS_ERR) return (EIO); cyrewind(cy, addr); return (0);}cydwrite(cy, pf, npf, addr) register struct cy_softc *cy; int pf, npf; caddr_t addr;{ cy->cy_tpb.tpcmd = CY_WCOM; cy->cy_tpb.tpcontrol = CYCW_LOCK|CYCW_25IPS|CYCW_16BITS; cy->cy_tpb.tpstatus = 0; cy->cy_tpb.tpsize = htoms(npf*NBPG); cyldmba(cy->cy_tpb.tplink, (caddr_t)0); cyldmba(cy->cy_tpb.tpdata, (caddr_t)(pf*NBPG)); cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb); cy->cy_ccb.cbgate = GATE_CLOSED; CY_GO(addr); if (cywait(&cy->cy_ccb)) return (EFAULT); uncache(&cy->cy_tpb); if (cy->cy_tpb.tpstatus&CYS_ERR) return (EIO); return (0);}cyweof(cy, addr) register struct cy_softc *cy; caddr_t addr;{ cy->cy_tpb.tpcmd = CY_WEOF; cy->cy_tpb.tpcount = htoms(1); cy->cy_ccb.cbgate = GATE_CLOSED; CY_GO(addr); (void) cywait(&cy->cy_ccb);}cyrewind(cy, addr) register struct cy_softc *cy; caddr_t addr;{ cy->cy_tpb.tpcmd = CY_REW; cy->cy_tpb.tpcount = htoms(1); cy->cy_ccb.cbgate = GATE_CLOSED; CY_GO(addr); (void) cywait(&cy->cy_ccb);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -