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:
parent
2a5f758aad
commit
6a1b5685fd
1 changed files with 56 additions and 54 deletions
110
PDP11/pdp11_rr.c
110
PDP11/pdp11_rr.c
|
@ -927,8 +927,8 @@ static t_stat rr_svc (UNIT *uptr)
|
||||||
cyl = uptr->CYL;
|
cyl = uptr->CYL;
|
||||||
|
|
||||||
if (wr) {
|
if (wr) {
|
||||||
if ((wloa & RPWLOA_ON) && !rper/*valid DA*/ &&
|
if ((wloa & RPWLOA_ON) && !rper/*valid DA*/
|
||||||
(n <= GET_WLOADRV(wloa) || cyl <= GET_WLOACYL(wloa))) {
|
&& (n <= GET_WLOADRV(wloa) || cyl <= GET_WLOACYL(wloa))) {
|
||||||
uptr->STATUS |= RPDS_WLK; /* DA write-locked */
|
uptr->STATUS |= RPDS_WLK; /* DA write-locked */
|
||||||
rper |= RPER_WPV;
|
rper |= RPER_WPV;
|
||||||
} else if (uptr->flags & UNIT_WPRT) /* write and locked? */
|
} else if (uptr->flags & UNIT_WPRT) /* write and locked? */
|
||||||
|
@ -1030,10 +1030,10 @@ static t_stat rr_svc (UNIT *uptr)
|
||||||
if (done >= todo)
|
if (done >= todo)
|
||||||
ioerr = 0; /* good stuff */
|
ioerr = 0; /* good stuff */
|
||||||
else if (ioerr)
|
else if (ioerr)
|
||||||
wc = n; /* short, adj wc */
|
wc = n; /* short, adj wd cnt */
|
||||||
else {
|
else {
|
||||||
todo -= done; /* to clear ... */
|
todo -= done; /* to clear... */
|
||||||
todo *= RP_SIZE(sizeof(*rpxb)); /* ... bytes */
|
todo *= RP_SIZE(sizeof(*rpxb)); /* ...bytes */
|
||||||
memset(rpxb + n, 0, todo);
|
memset(rpxb + n, 0, todo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1043,6 +1043,7 @@ static t_stat rr_svc (UNIT *uptr)
|
||||||
RPCONTR data;
|
RPCONTR data;
|
||||||
if (MAP_RDW(a, 1, &data)) { /* mem wd */
|
if (MAP_RDW(a, 1, &data)) { /* mem wd */
|
||||||
rper |= RPER_NXM; /* NXM? set flg */
|
rper |= RPER_NXM; /* NXM? set flg */
|
||||||
|
wc = n; /* adj wd cnt */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
a += 2;
|
a += 2;
|
||||||
|
@ -1051,27 +1052,29 @@ static t_stat rr_svc (UNIT *uptr)
|
||||||
if (data != rpxb[n]) /* match to disk? */
|
if (data != rpxb[n]) /* match to disk? */
|
||||||
rper |= RPER_WCE; /* no, err */
|
rper |= RPER_WCE; /* no, err */
|
||||||
}
|
}
|
||||||
n %= wc;
|
|
||||||
} else if ((n = MAP_WRW(ma, wc, rpxb))) { /* store buf */
|
} else if ((n = MAP_WRW(ma, wc, rpxb))) { /* store buf */
|
||||||
rper |= RPER_NXM; /* NXM? set flag */
|
rper |= RPER_NXM; /* NXM? set flag */
|
||||||
wc -= n; /* adj wd cnt */
|
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 */
|
rper |= RPER_FMTE; /* report as FMTE */
|
||||||
uptr->STATUS |= RPDS_HNF; /* sector not found */
|
uptr->STATUS |= RPDS_HNF; /* sector not found */
|
||||||
if (func == RPCS_WCHK)
|
if (func == RPCS_WCHK)
|
||||||
rper |= RPER_WCE; /* write-check err, too */
|
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: */
|
} else { /* write: */
|
||||||
if ((n = MAP_RDW(ma, wc, rpxb))) /* get buf */
|
if ((n = MAP_RDW(ma, wc, rpxb))) /* get buf */
|
||||||
wc -= n; /* adj wd cnt */
|
wc -= n; /* adj wd cnt */
|
||||||
if (wc && !(rpcs & RPCS_HDR)) { /* regular write? */
|
if (wc && !(rpcs & RPCS_HDR)) { /* regular write? */
|
||||||
DEVICE* dptr = find_dev_from_unit(uptr);
|
DEVICE* dptr = find_dev_from_unit(uptr);
|
||||||
int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to */
|
int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to... */
|
||||||
memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* end of blk */
|
memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* ...end of sect */
|
||||||
sim_disk_data_trace(uptr, (uint8*) rpxb, da, m * sizeof(*rpxb), "rr_write",
|
sim_disk_data_trace(uptr, (uint8*) rpxb, da, m * sizeof(*rpxb), "rr_write",
|
||||||
RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS);
|
RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS);
|
||||||
todo = m / RP_NUMWD; /* sectors to write */
|
todo = m / RP_NUMWD; /* sectors to write */
|
||||||
|
assert(!(m % RP_NUMWD));
|
||||||
ioerr = sim_disk_wrsect(uptr, da, (uint8*) rpxb, &done, todo);
|
ioerr = sim_disk_wrsect(uptr, da, (uint8*) rpxb, &done, todo);
|
||||||
assert(done <= todo);
|
assert(done <= todo);
|
||||||
if (done < todo) { /* short write? */
|
if (done < todo) { /* short write? */
|
||||||
|
@ -1093,51 +1096,49 @@ static t_stat rr_svc (UNIT *uptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(!ioerr || rper);
|
assert(!ioerr || rper);
|
||||||
|
assert(!wc || done);
|
||||||
|
assert(wc || rper);
|
||||||
|
|
||||||
if (wc) { /* any xfer? */
|
rpwc += wc;
|
||||||
assert(done);
|
rpwc &= RPWC_IMP;
|
||||||
rpwc += wc;
|
ma += wc << 1;
|
||||||
rpwc &= RPWC_IMP;
|
rpba = ma & RPBA_IMP;
|
||||||
ma += wc << 1;
|
rpcs &= ~RPCS_MEX;
|
||||||
rpba = ma & RPBA_IMP;
|
rpcs |= (ma >> (16 - RPCS_V_MEX)) & RPCS_MEX;
|
||||||
rpcs &= ~RPCS_MEX;
|
if (rpwc && !rper)
|
||||||
rpcs |= (ma >> (16 - RPCS_V_MEX)) & RPCS_MEX;
|
rper |= RPER_EOP; /* disk pack overrun */
|
||||||
if (rpwc && !(rper | ioerr))
|
|
||||||
rper |= RPER_EOP; /* disk pack overrun */
|
|
||||||
|
|
||||||
da += done; /* update DA */
|
da += done ? done : 1; /* update DA */
|
||||||
n = GET_DTYPE(uptr->flags); /* drive type */
|
n = GET_DTYPE(uptr->flags); /* drive type */
|
||||||
assert(da <= drv_tab[n].size);
|
assert(da <= drv_tab[n].size);
|
||||||
sect = da % RP_NUMSC; /* new sector */
|
sect = da % RP_NUMSC; /* new sector */
|
||||||
head = da / RP_NUMSC; /* new head (w/cyl) */
|
head = da / RP_NUMSC; /* new head (w/cyl) */
|
||||||
todo = head / RP_NUMSF; /* new cyl (tentative) */
|
todo = head / RP_NUMSF; /* new cyl (tentative) */
|
||||||
if (todo == drv_tab[n].cyl) { /* at the end? */
|
if (todo == drv_tab[n].cyl) { /* at the end? */
|
||||||
cyl = drv_tab[n].cyl - 1; /* keep on last cyl */
|
cyl = drv_tab[n].cyl - 1; /* keep on last cyl */
|
||||||
todo = 0; /* wrap cyl for rpda */
|
todo = 0; /* wrap cyl for rpda */
|
||||||
head = 0; /* ...and head, too */
|
head = 0; /* ...and head, too */
|
||||||
assert(!sect);
|
assert(!sect);
|
||||||
} else {
|
} else {
|
||||||
cyl = todo; /* new cyl */
|
cyl = todo; /* new cyl */
|
||||||
head %= RP_NUMSF; /* isolate head */
|
head %= RP_NUMSF; /* isolate head */
|
||||||
|
}
|
||||||
|
uptr->HEAD = head; /* update head */
|
||||||
|
if ((func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK) /* no SEEK I/O... */
|
||||||
|
&& (uptr->CYL != cyl /* ...and: arm moved or... */
|
||||||
|
|| (rper & RPER_EOP))) { /* ...boundary exceeded? */
|
||||||
|
n = (int32)(uptr - rr_dev.units); /* get unit number */
|
||||||
|
assert((1 << n) & RPDS_ATTN);
|
||||||
|
rpds |= 1 << n; /* set attention */
|
||||||
|
if (rpcs & RPCS_AIE) { /* att ints enabled? */
|
||||||
|
sim_debug(RRDEB_INT, &rr_dev, "rr_svc(SET_INT)\n");
|
||||||
|
SET_INT(RR); /* request interrupt */
|
||||||
}
|
}
|
||||||
uptr->HEAD = head; /* update head */
|
}
|
||||||
if ((func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK) /* no SEEK I/O... */
|
uptr->CYL = cyl; /* update cyl */
|
||||||
&& (uptr->CYL != cyl /* ...and: arm moved or... */
|
rpda = (head << RPDA_V_TRACK) | sect; /* updated head / sect */
|
||||||
|| (rper & RPER_EOP))) { /* ...boundary exceeded? */
|
rpca = todo; /* wrapped up cyl */
|
||||||
n = (int32)(uptr - rr_dev.units); /* get unit number */
|
suca = cyl; /* updated real cyl */
|
||||||
assert((1 << n) & RPDS_ATTN);
|
|
||||||
rpds |= 1 << n; /* set attention */
|
|
||||||
if (rpcs & RPCS_AIE) { /* att ints enabled? */
|
|
||||||
sim_debug(RRDEB_INT, &rr_dev, "rr_svc(SET_INT)\n");
|
|
||||||
SET_INT(RR); /* request interrupt */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uptr->CYL = cyl; /* update cyl */
|
|
||||||
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 */
|
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* name = uptr->uname;
|
||||||
const char* file = uptr->filename;
|
const char* file = uptr->filename;
|
||||||
const char* errstr = errno ? strerror(errno) : "";
|
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),
|
sim_printf("RR%u %s [%s:%s] FUNC=%o(%c) RPER=%06o I/O error (%s)%s%s",
|
||||||
GET_DTYPE(uptr->flags) ? RP_RP03 : RP_RP02, name ? name : "???",
|
(int) GET_DRIVE(rpcs), GET_DTYPE(uptr->flags) ? RP_RP03 : RP_RP02,
|
||||||
file ? file : "<NULL>", (int) rper, sim_error_text(ioerr),
|
name ? name : "???", file ? file : "<NULL>",
|
||||||
|
(int) func, "WR"[!wr], (int) rper, sim_error_text(ioerr),
|
||||||
errstr && *errstr ? ": " : "", errstr ? errstr : "");
|
errstr && *errstr ? ": " : "", errstr ? errstr : "");
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue