📄 tmscp.c
字号:
* No more requests for this drive, remove * from controller queue and look at next drive. * We know we're at the head of the controller queue. */ dp->b_active = 0; um->um_tab.b_actf = dp->b_forw; continue; /* Need to check for loop */ } um->um_tab.b_active++; tmscpaddr = (struct tmscpdevice *)um->um_addr; ui = tmsdinfo[(TMSUNIT(bp->b_dev))]; tms = &tms_info[ui->ui_unit]; if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN) { tprintf(tms->tms_tpr, "tms%d: hard error bn%d\n", minor(bp->b_dev)&03, bp->b_blkno); log(TMS_PRI, "tmscp%d: sa 0%o, state %d\n",um->um_ctlr, tmscpaddr->tmscpsa&0xffff, sc->sc_state); (void)tmscpinit(um->um_ctlr); /* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */ break; } /* * Default is that last command was NOT a write command; * if a write command is done it will be detected in tmscprsp. */ tms->tms_lastiow = 0; if (ui->ui_flags == 0) { /* not online */ if ((mp = tmscpgetcp(um)) == NULL) break; mp->mscp_opcode = M_OP_ONLIN; mp->mscp_unit = ui->ui_slave; dp->b_active = 2; um->um_tab.b_actf = dp->b_forw; /* remove from controller q */ *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; if (tmscpaddr->tmscpsa&TMSCP_ERR) printf("tmscp%d fatal error (0%o)\n",um->um_ctlr, tmscpaddr->tmscpsa&0xffff); i = tmscpaddr->tmscpip; continue; } switch (cpu) { case VAX_8600: case VAX_780: i = UBA_NEEDBDP|UBA_CANTWAIT; break; case VAX_750: i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT; break; case VAX_730: case VAX_630: i = UBA_CANTWAIT; break; } /* end switch (cpu) */ /* * If command is an ioctl command then set the ioctl flag for later use. * If not (i.e. it is a read or write) then attempt * to set up a buffer pointer. */ ioctl = 0; if (bp == &ctmscpbuf[um->um_ctlr]) ioctl = 1; else if ((i = ubasetup(um->um_ubanum, bp, i)) == 0) { if(dp->b_qsize != 0) break; /* When a command completes and */ /* frees a bdp tmscpstart will be called */ if ((mp = tmscpgetcp(um)) == NULL) break;# ifdef DEBUG printd("tmscpstart: GTUNT %d ubasetup = %d\n",ui->ui_unit, i); if(tmscpdebug)DELAY(10000);# endif mp->mscp_opcode = M_OP_GTUNT; mp->mscp_unit = ui->ui_slave; *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT; if (tmscpaddr->tmscpsa&TMSCP_ERR) printf("tmscp%d: fatal error (0%o)\n",um->um_ctlr, tmscpaddr->tmscpsa&0xffff); i = tmscpaddr->tmscpip; /* initiate polling */ break; }# if defined(VAX750) if (cpu == VAX_750) tempi = i & 0xfffffff; /* mask off bdp */ else# endif tempi = i; if ((mp = tmscpgetcp(um)) == NULL) { if (!ioctl) /* only need to release if NOT ioctl */ ubarelse(um->um_ubanum,&tempi); break; } mp->mscp_cmdref = (long)bp; /* pointer to get back */ mp->mscp_unit = ui->ui_slave; /* * If its an ioctl-type command then set up the appropriate * tmscp command; by doing a switch on the "b_resid" field where * the command mneumonic is stored. */ if (ioctl) {# ifdef DEBUG printd("tmscpstart: doing ioctl cmd %d\n", bp->b_resid);# endif /* * The reccnt and tmkcnt fields are set to zero by the getcp * routine (as bytecnt and buffer fields). Thus reccnt and * tmkcnt are only modified here if they need to be set to * a non-zero value. */ switch ((int)bp->b_resid) { case TMS_WRITM: mp->mscp_opcode = M_OP_WRITM; break; case TMS_FSF: mp->mscp_opcode = M_OP_REPOS; mp->mscp_tmkcnt = bp->b_bcount; break; case TMS_BSF: mp->mscp_opcode = M_OP_REPOS; mp->mscp_modifier = M_MD_REVRS; mp->mscp_tmkcnt = bp->b_bcount; break; case TMS_FSR: mp->mscp_opcode = M_OP_REPOS; mp->mscp_modifier = M_MD_OBJCT; mp->mscp_reccnt = bp->b_bcount; break; case TMS_BSR: mp->mscp_opcode = M_OP_REPOS; mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT; mp->mscp_reccnt = bp->b_bcount; break; /* * Clear serious exception is done for Rewind & Available cmds */ case TMS_REW: mp->mscp_opcode = M_OP_REPOS; mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX; if (bp->b_bcount == 0) mp->mscp_modifier |= M_MD_IMMED; tms->tms_serex = 0; break; case TMS_OFFL: mp->mscp_opcode = M_OP_AVAIL; mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX; tms->tms_serex = 0; break; case TMS_SENSE: mp->mscp_opcode = M_OP_GTUNT; break; case TMS_CACHE: mp->mscp_opcode = M_OP_STUNT; tms->tms_unitflgs |= M_UF_WBKNV; mp->mscp_unitflgs = tms->tms_unitflgs; mp->mscp_format = tms->tms_format; /* default device dependant parameters */ mp->mscp_mediaid = 0; break; case TMS_NOCACHE: mp->mscp_opcode = M_OP_STUNT; tms->tms_unitflgs &= ~(M_UF_WBKNV); mp->mscp_unitflgs = tms->tms_unitflgs; mp->mscp_format = tms->tms_format; /* default device dependant parameters */ mp->mscp_mediaid = 0; break; case TMS_CSE: /* * This is a no-op command. It performs a * clear serious exception only. (Done on a * non-rewinding close after a serious exception.) */ mp->mscp_opcode = M_OP_REPOS; mp->mscp_modifier = M_MD_CLSEX; tms->tms_serex = 0; tms->tms_clserex = 1; break; case TMS_LOWDENSITY: /* * Set the unit to low density */ mp->mscp_opcode = M_OP_STUNT; mp->mscp_unitflgs = tms->tms_unitflgs; mp->mscp_mediaid = 0; /* default device dependant parameters */ if ((tms->tms_fmtmenu & M_TF_800) != 0) mp->mscp_format = M_TF_800; else mp->mscp_format = M_TF_PE & tms->tms_fmtmenu; tms->tms_format = mp->mscp_format; break; case TMS_HIDENSITY: /* * Set the unit to high density (format == 0) */ mp->mscp_opcode = M_OP_STUNT; mp->mscp_unitflgs = tms->tms_unitflgs; mp->mscp_mediaid = 0; /* default device dependant parameters */ mp->mscp_format = 0; tms->tms_format = 0; break; default: printf("Bad ioctl on tms unit %d\n", ui->ui_unit); /* Need a no-op. Reposition no amount */ mp->mscp_opcode = M_OP_REPOS; break; } /* end switch (bp->b_resid) */ } else /* Its a read/write command (not an ioctl) */ { mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE; mp->mscp_bytecnt = bp->b_bcount; mp->mscp_buffer = UBAI_ADDR(i) | (UBAI_BDP(i) << 24); bp->b_ubinfo = tempi; /* save mapping info */ } if (tms->tms_serex == 2) /* if tape mark read */ { mp->mscp_modifier |= M_MD_CLSEX; /* clear serious exc */ tms->tms_serex = 0; } *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;# ifdef DEBUG printd("tmscpstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt); if(tmscpdebug)DELAY(100000);# endif i = tmscpaddr->tmscpip; /* initiate polling */ dp->b_qsize++; /* * Move drive to the end of the controller queue */ if (dp->b_forw != NULL) { um->um_tab.b_actf = dp->b_forw; um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; dp->b_forw = NULL; } /* * Move buffer to I/O wait queue */ dp->b_actf = bp->av_forw; dp = &tmscpwtab[um->um_ctlr]; bp->av_forw = dp; bp->av_back = dp->av_back; dp->av_back->av_forw = bp; dp->av_back = bp; if (tmscpaddr->tmscpsa&TMSCP_ERR) { printf("tmscp%d: fatal error (0%o)\n", um->um_ctlr, tmscpaddr->tmscpsa&0xffff); (void)tmscpinit(um->um_ctlr); break; } } /* end for */ /* * Check for response ring transitions lost in the * Race condition */ for (i = sc->sc_lastrsp;; i++) { i %= NRSP; if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN) break; tmscprsp(um, tm, sc, i); tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN; } sc->sc_lastrsp = i;}/* * Process a response packet */tmscprsp(um, tm, sc, i) register struct uba_ctlr *um; register struct tmscp *tm; register struct tmscp_softc *sc; int i;{ register struct mscp *mp; register struct tms_info *tms; struct uba_device *ui; struct buf *dp, *bp; int st; mp = &tm->tmscp_rsp[i]; mp->mscp_header.tmscp_msglen = mscp_msglen; sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf; /* low 4 bits */ if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10) /* Check */ return;# ifdef DEBUG printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK);# endif /* * If it's an error log message (datagram), * pass it on for more extensive processing. */ if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10) { /* check */ tmserror(um, (struct mslg *)mp); return; } st = mp->mscp_status&M_ST_MASK; /* * The controller interrupts as drive 0. * This means that you must check for controller interrupts * before you check to see if there is a drive 0. */ if((M_OP_STCON|M_OP_END) == mp->mscp_opcode) { if (st == M_ST_SUCC) {# ifdef DEBUG printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf); printd("ctlr timeout = %d\n", mp->mscp_cnttmo);# endif sc->sc_state = S_RUN; } else sc->sc_state = S_IDLE; um->um_tab.b_active = 0; wakeup((caddr_t)um); return; } if (mp->mscp_unit >= NTMS) return; if ((ui = tmscpip[um->um_ctlr][mp->mscp_unit]) == 0) return; tms = &tms_info[ui->ui_unit]; /* * Save endcode, endflags, and status for mtioctl get unit status. * NOTE: Don't do this on Clear serious exception (reposition no-op); * which is done on close since this would * overwrite the real status we want. */ if (tms->tms_clserex != 1) { tms->tms_endcode = mp->mscp_opcode; tms->tms_flags = mp->mscp_flags; tms->tms_status = st; } else tms->tms_clserex = 0; switch (mp->mscp_opcode) { case M_OP_ONLIN|M_OP_END: tms->tms_type = mp->mscp_mediaid; dp = &tmsutab[ui->ui_unit]; if (st == M_ST_SUCC) { /* * Link the drive onto the controller queue */ dp->b_forw = NULL; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; ui->ui_flags = 1; /* mark it online */ tms->tms_dsize=(daddr_t)mp->mscp_maxwrt;# ifdef DEBUG printd("tmscprsp: unit %d online\n", mp->mscp_unit);# endif /* * This define decodes the Media type identifier */# define F_to_C(x,i) ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')# ifdef DEBUG printd("tmscprsp: unit %d online %x %c%c %c%c%c%d\n" ,mp->mscp_unit, mp->mscp_mediaid ,F_to_C(mp,4) ,F_to_C(mp,3), F_to_C(mp,2) ,F_to_C(mp,1), F_to_C(mp,0), mp->mscp_mediaid & 0x7f);# endif dp->b_active = 1; } /* end if st == M_ST_SUCC */ else { if (bp = dp->b_actf) tprintf(tms->tms_tpr, "tms%d: hard error bn%d: OFFLINE\n", minor(bp->b_dev)&03, bp->b_blkno); else tprintf(tms->tms_tpr, "tms%d: hard error: OFFLINE\n", ui->ui_unit); while (bp = dp->b_actf) { dp->b_actf = bp->av_forw; bp->b_flags |= B_ERROR; iodone(bp); } } if(mp->mscp_cmdref!=NULL) /* Seems to get lost sometimes in uda */ wakeup((caddr_t)mp->mscp_cmdref); break; /* * The AVAILABLE ATTENTION message occurs when the * unit becomes available after loading, * marking the unit offline (ui_flags = 0) will force an * online command prior to using the unit. */ case M_OP_AVATN: ui->ui_flags = 0; tms->tms_type = mp->mscp_mediaid; break; case M_OP_END: /* * An endcode without an opcode (0200) is an invalid command. * The mscp specification states that this would be a protocol * type error, such as illegal opcodes. The mscp spec. also * states that parameter error type of invalid commands should * return the normal end message for the command. This does not appear * to be the case. An invalid logical block number returned an endcode * of 0200 instead of the 0241 (read) that was expected. */ printf("tmscp%d: invalid cmd, endcode = %o, status=%o\n", um->um_ctlr, mp->mscp_opcode, st); bp = (struct buf *)mp->mscp_cmdref; /* * Unlink buffer from I/O wait queue. * And signal iodone, so the higher level command can exit! * */ bp->av_back->av_forw = bp->av_forw; bp->av_forw->av_back = bp->av_back; dp = &tmsutab[ui->ui_unit]; dp->b_qsize--; iodone(bp); break; case M_OP_WRITE|M_OP_END: /* mark the last io op as a write */ tms->tms_lastiow = 1; case M_OP_READ|M_OP_END: case M_OP_WRITM|M_OP_END: case M_OP_REPOS|M_OP_END: case M_OP_STUNT|M_OP_END: /* * The AVAILABLE message occurs when the mt ioctl "rewoffl" is * issued. For the ioctl, "rewoffl", a tmscp AVAILABLE command is * done with the UNLOAD modifier. This performs a rewind, followed * by marking the unit offline. So mark the unit offline * software wise as well (ui_flags = 0 and * tms->tms_openf = 0). */ case M_OP_AVAIL|M_OP_END:# ifdef DEBUG printd("tmscprsp: position = %d\n", mp->mscp_lbn);# endif bp = (struct buf *)mp->mscp_cmdref; /* * Only need to release buffer if the command was read or write. * No ubasetup was done in "tmscpstart" if it was an ioctl cmd. */ if (mp->mscp_opcode == (M_OP_READ|M_OP_END) || mp->mscp_opcode == (M_OP_WRITE|M_OP_END)) ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo); /* * Unlink buffer from I/O wait queue. */ bp->av_back->av_forw = bp->av_forw; bp->av_forw->av_back = bp->av_back;# if defined(VAX750) if (cpu == VAX_750) { if ((tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr]) && (um->um_ubinfo != 0)) { ubarelse(um->um_ubanum, &um->um_ubinfo); } else { if (mp->mscp_opcode == (M_OP_READ|M_OP_END) || mp->mscp_opcode == (M_OP_WRITE|M_OP_END)) UBAPURGE(uba_hd[um->um_ubanum].uh_uba,(um->um_ubinfo >>28) & 0x0f); } }# endif dp = &tmsutab[ui->ui_unit]; dp->b_qsize--; if (st == M_ST_OFFLN || st == M_ST_AVLBL) { ui->ui_flags = 0; /* mark unit offline */ tms->tms_openf = 0; tms->tms_type = mp->mscp_mediaid; /* * Link the buffer onto the front of the drive queue */ if ((bp->av_forw = dp->b_actf) == 0) dp->b_actl = bp; dp->b_actf = bp; /* * Link the drive onto the controller queue */ if (dp->b_active == 0) { dp->b_forw = NULL; if (um->um_tab.b_actf == NULL) um->um_tab.b_actf = dp; else um->um_tab.b_actl->b_forw = dp; um->um_tab.b_actl = dp; dp->b_active = 1; }# if defined(VAX750) if (cpu == VAX_750 && um->um_ubinfo == 0) um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);# endif return; } if (st != M_ST_SUCC) { if (mp->mscp_flags & M_EF_SEREX) tms->tms_serex = 1; if (st != M_ST_TAPEM) { tprintf(tms->tms_tpr, "tms%d: hard error bn%d\n", minor(bp->b_dev)&03, bp->b_blkno); errinfo(st); /* produces more info */# ifdef DEBUG printd("tmscprsp: error; status sub-code = 0%o, flags = 0%o\n", (mp->mscp_status & 177740)>>5, mp->mscp_flags);# endif bp->b_flags |= B_ERROR; } else /* Hit a tape mark - Set serex flag to * a special value so we can clear the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -