int32 ts_readr (UNIT *uptr, uint32 fc) { t_stat st; t_mtrlnt i, tbc, wbc; int32 wa; msgrfc = fc; st = sim_tape_rdrecr (uptr, tsxb, &tbc, MT_MAXFR); /* read rec rev */ if (st != MTSE_OK) /* error? */ return ts_map_status (st); if (fc == 0) /* byte count */ fc = 0200000; tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ for (i = wbc; i > 0; i--) { /* copy buffer */ tsba = tsba - 1; wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ if (Map_WriteB (wa, 1, &tsxb[i - 1])) { /* store byte, nxm? */ tssr = ts_updtssr (tssr | TSSR_NXM); return (XTC (XS0_RLS, TC4)); } msgrfc = (msgrfc - 1) & DMASK; } if (msgrfc) /* buf too big? */ return (XTC (XS0_RLS, TC2)); if (tbc > wbc) /* rec too big? */ return (XTC (XS0_RLL, TC2)); return 0; }
t_stat mt_readrec (UNIT *uptr) { t_mtrlnt tbc; t_stat st; if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ mt_set_err (uptr); /* no, err, disc */ return SCPE_UNATT; } if (mt_inst & CHC_REV) /* reverse? */ st = sim_tape_rdrecr (uptr, mtxb, &tbc, MT_MAXFR); /* read rec rev */ else { /* no, fwd */ t_bool passed_eot = sim_tape_eot (uptr); /* passed EOT? */ st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); if (!passed_eot && sim_tape_eot (uptr)) /* just passed eot? */ uptr->eotf = 1; } if (st == MTSE_TMK) { /* tape mark? */ mt_eof = 1; /* set eof flag */ mtxb[0] = mtxb[1] = 017; /* EOR char */ mt_blnt = 2; /* store 2 */ return SCPE_OK; } if (st != MTSE_OK) { /* other error? */ mt_set_err (uptr); /* err, disc */ if (st == MTSE_IOERR) /* IO error? */ return SCPE_IOERR; if (st == MTSE_INVRL) /* inv rec lnt? */ return SCPE_MTRLNT; if (st == MTSE_EOM) /* eom? set eot */ uptr->eotf = 1; return SCPE_OK; } mt_blnt = tbc; /* set buf lnt */ return SCPE_OK; }
t_stat mtu_svc (UNIT *uptr) { uint32 cmd = uptr->UCMD; uint32 un = uptr - mt_unit; uint32 c; uint32 st; int32 t; t_mtrlnt tbc; t_stat r; if (cmd == MCM_INIT) { /* init state */ if ((t = sim_activate_time (uptr + MT_REW)) != 0) { /* rewinding? */ sim_activate (uptr, t); /* retry later */ return SCPE_OK; } st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((cmd & 0x80) || /* invalid cmd? */ (mt_op[cmd] == 0)) { uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, chan_ctl_time); /* resched ctlr */ return SCPE_OK; } else { /* valid cmd */ if ((mt_op[cmd] & O_REV) && /* reverse op */ (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ chan_uen (mt_dib.dva); /* channel end */ return SCPE_OK; } uptr->UCMD = cmd; /* unit state */ if (!(mt_op[cmd] & O_NMT)) /* motion? */ uptr->UST = 0; /* clear status */ } mt_blim = 0; /* no buffer yet */ sim_activate (uptr, chan_ctl_time); /* continue thread */ return SCPE_OK; /* done */ } if (cmd == MCM_END) { /* end state */ st = chan_end (mt_dib.dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if (st == CHS_CCH) { /* command chain? */ uptr->UCMD = MCM_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); } else uptr->UCMD = 0; /* ctlr idle */ return SCPE_OK; /* done */ } if ((mt_op[cmd] & O_ATT) && /* op req att and */ ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ sim_activate (uptr, mt_ctime); /* retry */ return mt_stopioe? SCPE_UNATT: SCPE_OK; } if ((mt_op[cmd] & O_WRE) && /* write op and */ sim_tape_wrp (uptr)) { /* write protected? */ uptr->UST |= MTDV_WLE; /* set status */ chan_uen (mt_dib.dva); /* unusual end */ return SCPE_OK; } r = SCPE_OK; switch (cmd) { /* case on command */ case MCM_SFWR: /* space forward */ if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SBKR: /* space reverse */ if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ r = mt_map_err (uptr, r); /* map error */ break; case MCM_SFWF: /* space fwd file */ while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_SBKF: /* space rev file */ while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; if (r != MTSE_TMK) /* stopped by tmk? */ r = mt_map_err (uptr, r); /* no, map error */ else r = SCPE_OK; break; case MCM_WTM: /* write eof */ if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ r = mt_map_err (uptr, r); /* map error */ uptr->UST |= MTDV_EOF; /* set eof */ break; case MCM_RWU: /* rewind unload */ r = detach_unit (uptr); break; case MCM_REW: /* rewind */ case MCM_RWI: /* rewind and int */ if (r = sim_tape_rewind (uptr)) /* rewind */ r = mt_map_err (uptr, r); /* map error */ mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ break; case MCM_READ: /* read */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = 0; /* init rec ptr */ } c = mt_xb[mt_bptr++]; /* get char */ st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_RDBK: /* read reverse */ if (mt_blim == 0) { /* first read? */ r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); if (r != MTSE_OK) { /* tape error? */ r = mt_map_err (uptr, r); /* map error */ break; } mt_bptr = mt_blim; /* init rec ptr */ } c = mt_xb[--mt_bptr]; /* get char */ st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ if (CHS_IFERR (st)) /* channel error? */ return mt_chan_err (st); if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ case MCM_WRITE: /* write */ st = chan_RdMemB (mt_dib.dva, &c); /* read char */ if (CHS_IFERR (st)) { /* channel error? */ mt_flush_buf (uptr); /* flush buffer */ return mt_chan_err (st); } mt_xb[mt_blim++] = c; /* store in buffer */ if (st != CHS_ZBC) { /* end record? */ sim_activate (uptr, mt_time); /* continue thread */ return SCPE_OK; } r = mt_flush_buf (uptr); /* flush buffer */ break; } if (r != SCPE_OK) /* error? abort */ return CHS_IFERR(r)? SCPE_OK: r; uptr->UCMD = MCM_END; /* end state */ sim_activate (uptr, mt_ctime); /* sched ctlr */ return SCPE_OK; }
/* Handle processing of tape requests. */ t_stat mt_srv(UNIT * uptr) { int chan = uptr->u5 & MT_CHAN; int unit = uptr - mt_unit; int cmd = uptr->u5 & MT_CMD; DEVICE *dptr = find_dev_from_unit(uptr); t_mtrlnt reclen; t_stat r = SCPE_ARG; /* Force error if not set */ uint8 ch; int mode; t_mtrlnt loc; /* Simulate tape load delay */ if (uptr->u5 & MT_LOADED) { uptr->u5 &= ~MT_LOADED; uptr->u5 |= MT_BSY|MT_RDY; sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Loaded\n", unit); sim_activate(uptr, 50000); return SCPE_OK; } if (uptr->u5 & MT_BSY) { uptr->u5 &= ~MT_BSY; sim_debug(DEBUG_DETAIL, dptr, "Unit=%d Online\n", unit); iostatus |= 1 << (uptr - mt_unit); if (uptr->u5 & MT_IDLE) sim_activate(uptr, 50000); return SCPE_OK; } if (uptr->u5 & MT_IDLE) { uptr->u5 &= ~MT_IDLE; if (uptr->u5 & MT_RDY) { sim_debug(DEBUG_DETAIL, dptr, "Unit=%d idling\n", unit); return SCPE_OK; } sim_debug(DEBUG_DETAIL, dptr, "Unit=%d start %02o\n", unit, cmd); } switch (cmd) { /* Handle interrogate */ case MT_INT: if (sim_tape_wrp(uptr)) chan_set_wrp(chan); uptr->u5 &= ~(MT_CMD|MT_BIN); uptr->u5 |= MT_RDY; chan_set_end(chan); sim_debug(DEBUG_DETAIL, dptr, "Status\n"); return SCPE_OK; case MT_RD: /* Read */ /* If at end of record, fill buffer */ if (BUF_EMPTY(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "Read unit=%d %s ", unit, (uptr->u5 & MT_BIN)? "bin": "bcd"); if (sim_tape_eot(uptr)) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_EOM, dptr); } r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM\n"); ch = 017; (void)chan_write_char(chan, &ch, 1); sim_activate(uptr, 4000); } else { sim_debug(DEBUG_DETAIL, dptr, "r=%d\n", r); sim_activate(uptr, 5000); } return mt_error(uptr, chan, r, dptr); } else { uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; } sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); uptr->u6 = 0; if ((uptr->u5 & MT_BIN) == 0) mode = 0100; else mode = 0; for (loc = 0; loc < reclen; loc++) { ch = mt_buffer[chan][loc] & 0177; if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) { chan_set_error(chan); break; } } } ch = mt_buffer[chan][uptr->u6++] & 0177; /* 00 characters are not transfered in BCD mode */ if (ch == 0) { if (((uint32)uptr->u6) >= uptr->hwmark) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_activate(uptr, HT); return SCPE_OK; } } if (chan_write_char(chan, &ch, (((uint32)uptr->u6) >= uptr->hwmark) ? 1 : 0)) { sim_debug(DEBUG_DATA, dptr, "Read unit=%d %d EOR\n", unit, uptr->hwmark-uptr->u6); sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_debug(DEBUG_DATA, dptr, "Read data unit=%d %d %03o\n", unit, uptr->u6, ch); sim_activate(uptr, HT); } return SCPE_OK; case MT_RDBK: /* Read Backword */ /* If at end of record, fill buffer */ if (BUF_EMPTY(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "Read back unit=%d %s ", unit, (uptr->u5 & MT_BIN)? "bin": "bcd"); if (sim_tape_bot(uptr)) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_BOT, dptr); } r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM\n"); ch = 017; (void)chan_write_char(chan, &ch, 1); sim_activate(uptr, 4000); } else { uptr->u5 |= MT_BSY; sim_debug(DEBUG_DETAIL, dptr, "r=%d\n", r); sim_activate(uptr, 100); } return mt_error(uptr, chan, r, dptr); } else { uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; } sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); uptr->u6 = uptr->hwmark; if ((uptr->u5 & MT_BIN) == 0) mode = 0100; else mode = 0; for (loc = 0; loc < reclen; loc++) { ch = mt_buffer[chan][loc] & 0177; if (((parity_table[ch & 077]) ^ (ch & 0100) ^ mode) == 0) { chan_set_error(chan); break; } } } ch = mt_buffer[chan][--uptr->u6] & 0177; /* 00 characters are not transfered in BCD mode */ if (ch == 0) { if (uptr->u6 <= 0) { sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_activate(uptr, HT); return SCPE_OK; } } if (chan_write_char(chan, &ch, (uptr->u6 > 0) ? 0 : 1)) { sim_debug(DEBUG_DATA, dptr, "Read back unit=%d %d EOR\n", unit, uptr->hwmark-uptr->u6); sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_OK, dptr); } else { sim_debug(DEBUG_DATA, dptr, "Read back data unit=%d %d %03o\n", unit, uptr->u6, ch); sim_activate(uptr, HT); } return SCPE_OK; case MT_WR: /* Write */ /* Check if write protected */ if (uptr->u6 == 0 && sim_tape_wrp(uptr)) { sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_WRP, dptr); } if (chan_read_char(chan, &ch, (uptr->u6 > BUFFSIZE) ? 1 : 0)) { reclen = uptr->u6; /* If no transfer, then either erase */ if (reclen == 0) { sim_debug(DEBUG_DETAIL, dptr, "Erase\n"); r = MTSE_OK; } else if ((reclen == 1) && (cmd & MT_BIN) == 0 && (mt_buffer[chan][0] == 017)) { /* Check if write rtape mark */ sim_debug(DEBUG_DETAIL, dptr, "Write Mark unit=%d\n", unit); r = sim_tape_wrtmk(uptr); } else { sim_debug(DEBUG_DETAIL, dptr, "Write unit=%d Block %d %s chars\n", unit, reclen, (uptr->u5 & MT_BIN)? "bin": "bcd"); r = sim_tape_wrrecf(uptr, &mt_buffer[chan][0], reclen); } uptr->u5 &= ~(MT_BOT|MT_EOT); sim_activate(uptr, 4000); return mt_error(uptr, chan, r, dptr); /* Record errors */ } else { /* Copy data to buffer */ ch &= 077; ch |= parity_table[ch]; if ((uptr->u5 & MT_BIN)) ch ^= 0100; /* Don't write out even parity zeros */ if (ch != 0) mt_buffer[chan][uptr->u6++] = ch; sim_debug(DEBUG_DATA, dptr, "Write data unit=%d %d %03o\n", unit, uptr->u6, ch); uptr->hwmark = uptr->u6; } sim_activate(uptr, HT); return SCPE_OK; case MT_FSR: /* Space forward one record */ if (BUF_EMPTY(uptr)) { /* If at end of record, fill buffer */ sim_debug(DEBUG_DETAIL, dptr, "Space unit=%d ", unit); if (sim_tape_eot(uptr)) { uptr->u5 &= ~MT_BOT; sim_debug(DEBUG_DETAIL, dptr, "EOT\n"); sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_EOM, dptr); } r = sim_tape_rdrecf(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM "); reclen = 1; chan_set_eof(chan); } else { sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r); reclen = 10; } } uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); sim_activate(uptr, uptr->hwmark * HT); return SCPE_OK; } sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); case MT_BSR: /* Backspace record */ if (BUF_EMPTY(uptr)) { /* If at end of record, fill buffer */ sim_debug(DEBUG_DETAIL, dptr, "backspace unit=%d ", unit); if (sim_tape_bot(uptr)) { sim_debug(DEBUG_DETAIL, dptr, "BOT\n"); sim_activate(uptr, 100); return mt_error(uptr, chan, MTSE_BOT, dptr); } r = sim_tape_rdrecr(uptr, &mt_buffer[chan][0], &reclen, BUFFSIZE); if (r != MTSE_OK) { if (r == MTSE_TMK) { sim_debug(DEBUG_DETAIL, dptr, "TM "); reclen = 1; chan_set_eof(chan); } else { reclen = 10; sim_debug(DEBUG_DETAIL, dptr, "r=%d ", r); } } uptr->u5 &= ~(MT_BOT|MT_EOT); uptr->hwmark = reclen; sim_debug(DEBUG_DETAIL, dptr, "%d chars\n", uptr->hwmark); sim_activate(uptr, uptr->hwmark * HT); return SCPE_OK; } sim_activate(uptr, 4000); return mt_error(uptr, chan, MTSE_OK, dptr); case MT_REW: /* Rewind */ sim_debug(DEBUG_DETAIL, dptr, "Rewind unit=%d pos=%d\n", unit, uptr->pos); uptr->u5 &= ~(MT_CMD | MT_BIN | MT_IDLE | MT_RDY); uptr->u5 |= MT_BSY|MT_RDY; iostatus &= ~(1 << (uptr - mt_unit)); sim_activate(uptr, (uptr->pos/100) + 100); r = sim_tape_rewind(uptr); uptr->u5 &= ~MT_EOT; uptr->u5 |= MT_BOT; chan_set_end(chan); return r; } return mt_error(uptr, chan, r, dptr); }