PDP11: RP11: Make sure to advance DA after every I/O

It looks like disk controllers, which automatically update
disk address (DA) after completion of I/O, are expected to do
so even if there was no data transfer because of I/O errors.
I was studying RSX-11's Error Logger documentation and
examples are clearly offsetting disk addresses backwards
by one when I/O errors are reported by the controller.

Since once the controller has found the DA-specified sector,
the I/O begins regardless of the condition of the sector (bad
or good data) or ability to transfer the contents between the
disk and the memory.  If an error occurs (NXM, for instance)
the operation would stop (with the error reported) at the end
of the sector.  So if, for example, the bus address register
had a bad address from the get-go, no data would be able to
transfer at all, yet DA should still be updated with DA + 1
once the controller asserts the DONE bit.

This patch makes sure that DA is always advanced when I/O has
actually been commenced.
This commit is contained in:
Tony Lawrence 2024-01-30 20:50:55 -05:00 committed by Paul Koning
parent 2a5f758aad
commit 6a1b5685fd

View file

@ -927,8 +927,8 @@ static t_stat rr_svc (UNIT *uptr)
cyl = uptr->CYL;
if (wr) {
if ((wloa & RPWLOA_ON) && !rper/*valid DA*/ &&
(n <= GET_WLOADRV(wloa) || cyl <= GET_WLOACYL(wloa))) {
if ((wloa & RPWLOA_ON) && !rper/*valid DA*/
&& (n <= GET_WLOADRV(wloa) || cyl <= GET_WLOACYL(wloa))) {
uptr->STATUS |= RPDS_WLK; /* DA write-locked */
rper |= RPER_WPV;
} else if (uptr->flags & UNIT_WPRT) /* write and locked? */
@ -1030,7 +1030,7 @@ static t_stat rr_svc (UNIT *uptr)
if (done >= todo)
ioerr = 0; /* good stuff */
else if (ioerr)
wc = n; /* short, adj wc */
wc = n; /* short, adj wd cnt */
else {
todo -= done; /* to clear... */
todo *= RP_SIZE(sizeof(*rpxb)); /* ...bytes */
@ -1043,6 +1043,7 @@ static t_stat rr_svc (UNIT *uptr)
RPCONTR data;
if (MAP_RDW(a, 1, &data)) { /* mem wd */
rper |= RPER_NXM; /* NXM? set flg */
wc = n; /* adj wd cnt */
break;
}
a += 2;
@ -1051,27 +1052,29 @@ static t_stat rr_svc (UNIT *uptr)
if (data != rpxb[n]) /* match to disk? */
rper |= RPER_WCE; /* no, err */
}
n %= wc;
} else if ((n = MAP_WRW(ma, wc, rpxb))) { /* store buf */
rper |= RPER_NXM; /* NXM? set flag */
wc -= n; /* adj wd cnt */
}
if (!n && ioerr) { /* all wrds ok but I/O? */
if (!rper && ioerr) { /* all wrds ok but I/O? */
rper |= RPER_FMTE; /* report as FMTE */
uptr->STATUS |= RPDS_HNF; /* sector not found */
if (func == RPCS_WCHK)
rper |= RPER_WCE; /* write-check err, too */
}
if (rper) /* adj sector count */
done = (wc + (RP_NUMWD - 1)) / RP_NUMWD; /* NB: works for HDR, too */
} else { /* write: */
if ((n = MAP_RDW(ma, wc, rpxb))) /* get buf */
wc -= n; /* adj wd cnt */
if (wc && !(rpcs & RPCS_HDR)) { /* regular write? */
DEVICE* dptr = find_dev_from_unit(uptr);
int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to */
memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* end of blk */
int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to... */
memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* ...end of sect */
sim_disk_data_trace(uptr, (uint8*) rpxb, da, m * sizeof(*rpxb), "rr_write",
RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS);
todo = m / RP_NUMWD; /* sectors to write */
assert(!(m % RP_NUMWD));
ioerr = sim_disk_wrsect(uptr, da, (uint8*) rpxb, &done, todo);
assert(done <= todo);
if (done < todo) { /* short write? */
@ -1093,19 +1096,19 @@ static t_stat rr_svc (UNIT *uptr)
}
}
assert(!ioerr || rper);
assert(!wc || done);
assert(wc || rper);
if (wc) { /* any xfer? */
assert(done);
rpwc += wc;
rpwc &= RPWC_IMP;
ma += wc << 1;
rpba = ma & RPBA_IMP;
rpcs &= ~RPCS_MEX;
rpcs |= (ma >> (16 - RPCS_V_MEX)) & RPCS_MEX;
if (rpwc && !(rper | ioerr))
if (rpwc && !rper)
rper |= RPER_EOP; /* disk pack overrun */
da += done; /* update DA */
da += done ? done : 1; /* update DA */
n = GET_DTYPE(uptr->flags); /* drive type */
assert(da <= drv_tab[n].size);
sect = da % RP_NUMSC; /* new sector */
@ -1136,8 +1139,6 @@ static t_stat rr_svc (UNIT *uptr)
rpda = (head << RPDA_V_TRACK) | sect; /* updated head / sect */
rpca = todo; /* wrapped up cyl */
suca = cyl; /* updated real cyl */
} else
assert(rper);
rr_set_done(0); /* all done here */
@ -1145,9 +1146,10 @@ static t_stat rr_svc (UNIT *uptr)
const char* name = uptr->uname;
const char* file = uptr->filename;
const char* errstr = errno ? strerror(errno) : "";
sim_printf("RR%u %s [%s:%s] RPER=%06o I/O error (%s)%s%s", (int) GET_DRIVE(rpcs),
GET_DTYPE(uptr->flags) ? RP_RP03 : RP_RP02, name ? name : "???",
file ? file : "<NULL>", (int) rper, sim_error_text(ioerr),
sim_printf("RR%u %s [%s:%s] FUNC=%o(%c) RPER=%06o I/O error (%s)%s%s",
(int) GET_DRIVE(rpcs), GET_DTYPE(uptr->flags) ? RP_RP03 : RP_RP02,
name ? name : "???", file ? file : "<NULL>",
(int) func, "WR"[!wr], (int) rper, sim_error_text(ioerr),
errstr && *errstr ? ": " : "", errstr ? errstr : "");
return SCPE_IOERR;
}