From 9258e25c0dc689fabbfa93994bf1b30749a803b5 Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Sun, 3 Jul 2022 13:56:46 -0700 Subject: [PATCH] sigma: Fixed bugs in multi-unit operation The problems all stem from a single root cause: when an interrupt is requested - via any one of dozens of mechanisms (uend, normal end, special request, error, etc), the interrupt routine must be presented with the full device address, including the unit, which is stored in the channel data structures. This is so that AIO (acknowledge interrupt) can retrieve the unit number from the channel data structures and give it back to the invoking program. Unfortunately, service routines, error routines, etc were simply using the base device address, which is good enough for all channel operations EXCEPT AIO. So the four multi-unit device (RAD, DK, DP, MT) have had changes to reconstruct the full device address, with unit number, before any calls into the channel are made. DP, funnily enough, required the fewest changes. Ken was exactly right about the need to OR the unit number into dva at the start of the unit service routine. That had to be done in a few more places where my code was being lazy. RAD, DK, MT required many more changes, but they were mostly mechanical. All references to xx_dib.dva had to be examined and replaced with a full device address. The full device address had to be reconstructed from the UNIT pointer and the base device address, through the magic of pointer arithmetic. Another sore spot was HIO. HIO stops all the active unit in its tracks and does a channel UEND on it. The calculation of the unit number in the UEND was not correct in a few places, notably if DP did a controller reset. Fixes for the four modules; an updated bug history; and an expanded design document; are attached. --- sigma/Design Notes on the Sigma 7.doc | Bin 29184 -> 30208 bytes sigma/sigma_bugs.txt | 4 ++ sigma/sigma_dk.c | 89 +++++++++++++++----------- sigma/sigma_dp.c | 21 ++++-- sigma/sigma_mt.c | 68 +++++++++++--------- sigma/sigma_rad.c | 85 ++++++++++++++---------- 6 files changed, 161 insertions(+), 106 deletions(-) diff --git a/sigma/Design Notes on the Sigma 7.doc b/sigma/Design Notes on the Sigma 7.doc index 21a6769439bddaa4efa4c1befd9472371105e5e1..1a99ffaf20b25b265a43169be4707f75e203b0d9 100644 GIT binary patch delta 5504 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 Cy<`di delta 4037 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 DK_NUMDR) || /* inv unit num? */ @@ -178,23 +185,28 @@ switch (op) { /* case on op */ break; case OP_HIO: /* halt I/O */ - chan_clr_chi (dk_dib.dva); /* clr int */ + chan_clr_chi (dva); /* clr int */ *dvst = dk_tio_status (un); /* get status */ if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ for (i = 0; i < DK_NUMDR; i++) { /* find busy unit */ uptr = &dk_unit[i]; if (sim_is_active (uptr)) { /* active? */ sim_cancel (uptr); /* stop */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dk_dib.dva | i); /* uend on unit */ } /* end if active */ } /* end for */ } break; case OP_AIO: /* acknowledge int */ - chan_clr_chi (dk_dib.dva); /* clr int */ - *dvst = dk_tdv_status (un); /* status like TDV */ - break; + iu = chan_clr_chi (dk_dib.dva); /* clr int */ + if (iu < 0) { /* no int? */ + *dvst = 0; + return SCPE_IERR; + } + *dvst = dk_tdv_status (iu) | /* get status */ + (iu << DVT_V_UN); /* or in unit */ + break; default: *dvst = 0; @@ -210,18 +222,20 @@ t_stat dk_svc (UNIT *uptr) { uint32 i, sc, da, wd, wd1, cmd, c[3]; uint32 *fbuf = (uint32 *) uptr->filebuf; +uint32 un = uptr - dk_unit; +uint32 dva = dk_dib.dva | un; int32 t, dc; uint32 st; switch (dk_cmd) { case DKS_INIT: /* init state */ - st = chan_get_cmd (dk_dib.dva, &cmd); /* get command */ + st = chan_get_cmd (dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ - return dk_chan_err (st); + return dk_chan_err (dva,st); if ((cmd == 0) || /* invalid cmd? */ ((cmd > DKS_CHECK) && (cmd != DKS_RDEES) && (cmd != DKS_TEST))) { - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } dk_flags = 0; /* clear status */ @@ -240,9 +254,9 @@ switch (dk_cmd) { return SCPE_OK; case DKS_END: /* end state */ - st = chan_end (dk_dib.dva); /* set channel end */ + st = chan_end (dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ - return dk_chan_err (st); + return dk_chan_err (dva,st); if (st == CHS_CCH) { /* command chain? */ dk_cmd = DKS_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); @@ -252,13 +266,13 @@ switch (dk_cmd) { case DKS_SEEK: /* seek */ c[0] = c[1] = 0; for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { - st = chan_RdMemB (dk_dib.dva, &c[i]); /* get byte */ + st = chan_RdMemB (dva, &c[i]); /* get byte */ if (CHS_IFERR (st)) /* channel error? */ - return dk_chan_err (st); + return dk_chan_err (dva,st); } dk_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ - chan_set_chf (dk_dib.dva, CHF_LNTE)) /* care? */ + chan_set_chf (dva, CHF_LNTE)) /* care? */ return SCPE_OK; dc = DKA_GETTK (dk_ad); /* desired track */ t = abs (uptr->UTRK - dc); /* get track diff */ @@ -272,7 +286,7 @@ switch (dk_cmd) { case DKS_SEEK2: /* seek complete */ if (uptr->UTRK >= DK_TKUN) { dk_flags |= DKV_BADS; - chan_uen (dk_dib.dva); + chan_uen (dva); return SCPE_OK; } break; /* seek done */ @@ -282,31 +296,31 @@ switch (dk_cmd) { c[1] = dk_ad & 0xFF; /* address */ c[2] = GET_PSC (dk_time); /* curr sector */ for (i = 0, st = 0; (i < DKS_NBY) && (st != CHS_ZBC); i++) { - st = chan_WrMemB (dk_dib.dva, c[i]); /* store char */ + st = chan_WrMemB (dva, c[i]); /* store char */ if (CHS_IFERR (st)) /* channel error? */ - return dk_chan_err (st); + return dk_chan_err (dva,st); } if (((i != DKS_NBY) || (st != CHS_ZBC)) && - chan_set_chf (dk_dib.dva, CHF_LNTE)) /* length error? */ + chan_set_chf (dva, CHF_LNTE)) /* length error? */ return SCPE_OK; break; case DKS_WRITE: /* write */ if (uptr->flags & UNIT_RO) { /* write locked? */ dk_flags |= DKV_WPE; /* set status */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } if (dk_inv_ad (&da)) { /* invalid addr? */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; i < DK_WDSC; da++, i++) { /* sector loop */ if (st != CHS_ZBC) { /* chan not done? */ - st = chan_RdMemW (dk_dib.dva, &wd); /* read word */ + st = chan_RdMemW (dva, &wd); /* read word */ if (CHS_IFERR (st)) { /* channel error? */ dk_inc_ad (); /* da increments */ - return dk_chan_err (st); + return dk_chan_err (dva,st); } } else wd = 0; @@ -322,20 +336,20 @@ switch (dk_cmd) { case DKS_CHECK: /* write check */ if (dk_inv_ad (&da)) { /* invalid addr? */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; (i < (DK_WDSC * 4)) && (st != CHS_ZBC); ) { - st = chan_RdMemB (dk_dib.dva, &wd); /* read byte */ + st = chan_RdMemB (dva, &wd); /* read byte */ if (CHS_IFERR (st)) { /* channel error? */ dk_inc_ad (); /* da increments */ - return dk_chan_err (st); + return dk_chan_err (dva,st); } wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ if (wd != wd1) { /* check error? */ dk_inc_ad (); /* da increments */ - chan_set_chf (dk_dib.dva, CHF_XMDE); /* set xmt err flag */ - chan_uen (dk_dib.dva); /* force uend */ + chan_set_chf (dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (dva); /* force uend */ return SCPE_OK; } da = da + ((++i % 4) == 0); /* every 4th byte */ @@ -346,14 +360,14 @@ switch (dk_cmd) { case DKS_READ: /* read */ if (dk_inv_ad (&da)) { /* invalid addr? */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; (i < DK_WDSC) && (st != CHS_ZBC); da++, i++) { - st = chan_WrMemW (dk_dib.dva, fbuf[da]); /* store in mem */ + st = chan_WrMemW (dva, fbuf[da]); /* store in mem */ if (CHS_IFERR (st)) { /* channel error? */ dk_inc_ad (); /* da increments */ - return dk_chan_err (st); + return dk_chan_err (dva,st); } } if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ @@ -376,15 +390,18 @@ return SCPE_OK; t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) { +uint32 un = uptr - dk_unit; +uint32 dva = dk_dib.dva | un; + if (st != CHS_ZBC) { /* end record? */ if (dk_inc_ad ()) /* inc addr, ovf? */ - chan_uen (dk_dib.dva); /* uend */ + chan_uen (dva); /* uend */ else sim_activate (uptr, dk_time * 16); /* no, next sector */ return TRUE; } dk_inc_ad (); /* just incr addr */ if ((lnt != exp) && /* length error? */ - chan_set_chf (dk_dib.dva, CHF_LNTE)) /* do we care? */ + chan_set_chf (dva, CHF_LNTE)) /* do we care? */ return TRUE; return FALSE; /* cmd done */ } @@ -443,9 +460,9 @@ return FALSE; /* Channel error */ -t_stat dk_chan_err (uint32 st) +t_stat dk_chan_err (uint32 dva, uint32 st) { -chan_uen (dk_dib.dva); /* uend */ +chan_uen (dva); /* uend */ if (st < CHS_ERR) return st; return SCPE_OK; diff --git a/sigma/sigma_dp.c b/sigma/sigma_dp.c index 48286c0d..47931aa1 100644 --- a/sigma/sigma_dp.c +++ b/sigma/sigma_dp.c @@ -25,6 +25,7 @@ dp moving head disk pack controller + 02-Jul-2022 RMS Fixed bugs in multi-unit operation 28-Jun-22 RMS Fixed off-by-1 error in DP_SEEK definition (Ken Rector) 07-Jun-22 RMS Removed unused variables (V4) 06-Jun-22 RMS Fixed incorrect return in TIO status (Ken Rector) @@ -548,7 +549,11 @@ DEVICE dp_dev[] = { } }; -/* DP: IO dispatch routine */ +/* DP: IO dispatch routine + + For all calls except AIO, dva is the full channel/device/unit address + For AIO, the handler must return the unit number +*/ uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst) { @@ -612,7 +617,7 @@ switch (op) { /* case on op */ for (i = 0; i < DP_NUMDR; i++) { /* do every unit */ if (sim_is_active (&dp_unit[i])) { /* chan active? */ sim_cancel (&dp_unit[i]); /* cancel */ - chan_uen (dva); /* uend */ + chan_uen ((dva & ~DVA_M_UNIT) | i); /* uend */ } dp_clr_ski (cidx, i); /* clear seek int */ sim_cancel (&dp_unit[i + DP_SEEK]); /* cancel seek compl */ @@ -635,16 +640,16 @@ switch (op) { /* case on op */ return 0; } -/* Unit service */ +/* Unit service - reconstruct full device address on entry */ t_stat dp_svc (UNIT *uptr) { uint32 i, da, wd, wd1, c[DPS_NBY_16B]; uint32 cidx = uptr->UCTX; -uint32 dva = dp_dib[cidx].dva; -uint32 dtype = GET_DTYPE (uptr->flags); UNIT *dp_unit = dp_dev[cidx].units; uint32 un = uptr - dp_unit; +uint32 dva = dp_dib[cidx].dva | un; +uint32 dtype = GET_DTYPE (uptr->flags); DP_CTX *ctx = &dp_ctx[cidx]; int32 t, dc; uint32 st, cmd, sc; @@ -932,7 +937,8 @@ return SCPE_OK; t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) { uint32 cidx = uptr->UCTX; -uint32 dva = dp_dib[cidx].dva; +uint32 un = uptr - dp_dev[cidx].units; +uint32 dva = dp_dib[cidx].dva | un; DP_CTX *ctx = &dp_ctx[cidx]; if (st != CHS_ZBC) { /* end record? */ @@ -1112,7 +1118,8 @@ return SCPE_OK; t_stat dp_ioerr (UNIT *uptr) { uint32 cidx = uptr->UCTX; -uint32 dva = dp_dib[cidx].dva; +uint32 un = uptr - dp_dev[cidx].units; +uint32 dva = dp_dib[cidx].dva | un; perror ("DP I/O error"); clearerr (uptr->fileref); diff --git a/sigma/sigma_mt.c b/sigma/sigma_mt.c index 7a869288..b999dbe7 100644 --- a/sigma/sigma_mt.c +++ b/sigma/sigma_mt.c @@ -25,6 +25,8 @@ mt 7320 and 7322/7323 magnetic tape + 02-Jul-2022 RMS Fixed bugs in multi-unit operation + 07-Jun-22 RMS Removed unused variables (V4) 26-Mar-22 RMS Added extra case points for new MTSE definitions 13-Mar-17 RMS Annotated fall through in switch @@ -129,7 +131,7 @@ extern uint8 ebcdic_to_ascii[256]; uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst); uint32 mt_tio_status (uint32 un); uint32 mt_tdv_status (uint32 un); -t_stat mt_chan_err (uint32 st); +t_stat mt_chan_err (uint32 dva, uint32 st); t_stat mtu_svc (UNIT *uptr); t_stat mtr_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); @@ -215,7 +217,11 @@ DEVICE mt_dev = { &mt_dib, DEV_DISABLE | DEV_TAPE }; -/* Magtape: IO dispatch routine */ +/* Magtape: IO dispatch routine + + For all calls except AIO, dva is the full channel/device/unit address + For AIO, the handler must return the unit number +*/ uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst) { @@ -256,7 +262,7 @@ switch (op) { /* case on op */ break; case OP_AIO: /* acknowledge int */ - un = mt_clr_int (mt_dib.dva); /* clr int, get unit */ + un = mt_clr_int (mt_dib.dva); /* clr int, get unit and flag */ *dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */ (un & MTAI_INT) | /* device int flag */ ((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */ @@ -270,12 +276,13 @@ switch (op) { /* case on op */ return 0; } -/* Unit service */ +/* Unit service - reconstruct full unit address at entry */ t_stat mtu_svc (UNIT *uptr) { uint32 cmd = uptr->UCMD; uint32 un = uptr - mt_unit; +uint32 dva = mt_dib.dva | un; uint32 c; uint32 st; int32 t; @@ -287,9 +294,9 @@ if (cmd == MCM_INIT) { /* init state */ sim_activate (uptr, t); /* retry later */ return SCPE_OK; } - st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ + st = chan_get_cmd (dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ - return mt_chan_err (st); + return mt_chan_err (dva, st); if ((cmd & 0x80) || /* invalid cmd? */ (mt_op[cmd] == 0)) { uptr->UCMD = MCM_END; /* end state */ @@ -299,7 +306,7 @@ if (cmd == MCM_INIT) { /* init state */ 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 */ + chan_uen (dva); /* uend */ return SCPE_OK; } uptr->UCMD = cmd; /* unit state */ @@ -312,9 +319,9 @@ if (cmd == MCM_INIT) { /* init state */ } if (cmd == MCM_END) { /* end state */ - st = chan_end (mt_dib.dva); /* set channel end */ + st = chan_end (dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ - return mt_chan_err (st); + return mt_chan_err (dva, st); if (st == CHS_CCH) { /* command chain? */ uptr->UCMD = MCM_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); @@ -331,7 +338,7 @@ if ((mt_op[cmd] & O_ATT) && /* op req att and */ 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 */ + chan_uen (dva); /* uend */ return SCPE_OK; } @@ -390,15 +397,15 @@ switch (cmd) { /* case on command */ mt_bptr = 0; /* init rec ptr */ } c = mt_xb[mt_bptr++]; /* get char */ - st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ + st = chan_WrMemB (dva, c); /* write to memory */ if (CHS_IFERR (st)) /* channel error? */ - return mt_chan_err (st); + return mt_chan_err (dva, 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? */ + chan_set_chf (dva, CHF_LNTE)) /* uend taken? */ return SCPE_OK; /* finished */ break; /* normal end */ @@ -412,23 +419,23 @@ switch (cmd) { /* case on command */ mt_bptr = mt_blim; /* init rec ptr */ } c = mt_xb[--mt_bptr]; /* get char */ - st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ + st = chan_WrMemBR (dva, c); /* write mem rev */ if (CHS_IFERR (st)) /* channel error? */ - return mt_chan_err (st); + return mt_chan_err (dva, 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? */ + chan_set_chf (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 */ + st = chan_RdMemB (dva, &c); /* read char */ if (CHS_IFERR (st)) { /* channel error? */ mt_flush_buf (uptr); /* flush buffer */ - return mt_chan_err (st); + return mt_chan_err (dva, st); } mt_xb[mt_blim++] = c; /* store in buffer */ if (st != CHS_ZBC) { /* end record? */ @@ -473,42 +480,45 @@ return SCPE_OK; t_stat mt_map_err (UNIT *uptr, t_stat st) { +uint32 un = uptr - mt_unit; +uint32 dva = mt_dib.dva | un; + switch (st) { case MTSE_FMT: /* illegal fmt */ case MTSE_UNATT: /* not attached */ case MTSE_WRP: /* write protect */ default: /* unknown error*/ - chan_set_chf (mt_dib.dva, CHF_XMME); /* set err, fall through */ + chan_set_chf (dva, CHF_XMME); /* set err, fall through */ case MTSE_OK: /* no error */ - chan_uen (mt_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_IERR; case MTSE_TMK: /* end of file */ uptr->UST |= MTDV_EOF; /* set eof flag */ - chan_uen (mt_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return CHS_INACTV; case MTSE_IOERR: /* IO error */ uptr->UST |= MTDV_DTE; /* set DTE flag */ - chan_set_chf (mt_dib.dva, CHF_XMDE); - chan_uen (mt_dib.dva); /* force uend */ + chan_set_chf (dva, CHF_XMDE); + chan_uen (dva); /* uend */ return SCPE_IOERR; case MTSE_INVRL: /* invalid rec lnt */ uptr->UST |= MTDV_DTE; /* set DTE flag */ - chan_set_chf (mt_dib.dva, CHF_XMDE); - chan_uen (mt_dib.dva); /* force uend */ + chan_set_chf (dva, CHF_XMDE); + chan_uen (dva); /* uend */ return SCPE_MTRLNT; case MTSE_RECE: /* record in error */ case MTSE_EOM: /* end of medium */ uptr->UST |= MTDV_DTE; /* set DTE flag */ - return chan_set_chf (mt_dib.dva, CHF_XMDE); /* possible error */ + return chan_set_chf (dva, CHF_XMDE); /* possible error */ case MTSE_BOT: /* reverse into BOT */ uptr->UST |= MTDV_BOT; /* set BOT */ - chan_uen (mt_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return CHS_INACTV; } /* end switch */ @@ -555,9 +565,9 @@ return st; /* Channel error */ -t_stat mt_chan_err (uint32 st) +t_stat mt_chan_err (uint32 dva, uint32 st) { -chan_uen (mt_dib.dva); /* uend */ +chan_uen (dva); /* uend */ if (st < CHS_ERR) return st; return SCPE_OK; diff --git a/sigma/sigma_rad.c b/sigma/sigma_rad.c index 8542dd8d..8de5b490 100644 --- a/sigma/sigma_rad.c +++ b/sigma/sigma_rad.c @@ -1,6 +1,6 @@ /* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator - Copyright (c) 2007-2008, Robert M Supnik + Copyright (c) 2007-2022, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ rad 7211/7212 or 7231/7232 fixed head disk + 02-Jul-2022 RMS Fixed bugs in multi-unit operation + The RAD is a head-per-track disk. To minimize overhead, the entire RAD is buffered in memory. @@ -121,7 +123,7 @@ extern uint32 chan_ctl_time; uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst); uint32 rad_tio_status (uint32 un); uint32 rad_tdv_status (uint32 un); -t_stat rad_chan_err (uint32 st); +t_stat rad_chan_err (uint32 dva, uint32 st); t_stat rad_svc (UNIT *uptr); t_stat rad_reset (DEVICE *dptr); t_stat rad_settype (UNIT *uptr, int32 val, CONST char *cptr, void *desc); @@ -189,12 +191,17 @@ DEVICE rad_dev = { &rad_dib, DEV_DISABLE }; -/* RAD: IO dispatch routine */ +/* RAD: IO dispatch routine + + For all calls except AIO, dva is the full channel/device/unit address + For AIO, the handler must return the unit number +*/ uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst) { uint32 i; uint32 un = DVA_GETUNIT (dva); +int32 iu; UNIT *uptr; if ((un >= RAD_NUMDR) || /* inv unit num? */ @@ -219,22 +226,27 @@ switch (op) { /* case on op */ break; case OP_HIO: /* halt I/O */ - chan_clr_chi (rad_dib.dva); /* clr int*/ + chan_clr_chi (dva); /* clr int */ *dvst = rad_tio_status (un); /* get status */ if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ for (i = 0; i < RAD_NUMDR; i++) { /* find busy unit */ uptr = &rad_unit[i]; if (sim_is_active (uptr)) { /* active? */ sim_cancel (uptr); /* stop */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (rad_dib.dva | i); /* uend on drive */ } /* end if active */ } /* end for */ } break; case OP_AIO: /* acknowledge int */ - chan_clr_chi (rad_dib.dva); /* clr int */ - *dvst = rad_tdv_status (0); /* status like TDV */ + iu = chan_clr_chi (rad_dib.dva); /* clr int */ + if (iu < 0) { /* no int? */ + *dvst = 0; + return SCPE_IERR; + } + *dvst = rad_tdv_status (iu) | /* status like TDV */ + (iu << DVT_V_UN); /* or in unit */ break; default: @@ -251,18 +263,20 @@ t_stat rad_svc (UNIT *uptr) { uint32 i, sc, da, cmd, wd, wd1, c[4], gp; uint32 *fbuf = (uint32 *) uptr->filebuf; +uint32 un = uptr - rad_unit; +uint32 dva = rad_dib.dva | un; uint32 st; int32 t; switch (rad_cmd) { case RADS_INIT: /* init state */ - st = chan_get_cmd (rad_dib.dva, &cmd); /* get command */ + st = chan_get_cmd (dva, &cmd); /* get command */ if (CHS_IFERR (st)) /* channel error? */ - return rad_chan_err (st); + return rad_chan_err (dva, st); if ((cmd == 0) || /* invalid cmd? */ ((cmd > RADS_CHECK) && (cmd != RADS_RDEES))) { - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } rad_flags = 0; /* clear status */ @@ -279,9 +293,9 @@ switch (rad_cmd) { return SCPE_OK; case RADS_END: /* end state */ - st = chan_end (rad_dib.dva); /* set channel end */ + st = chan_end (dva); /* set channel end */ if (CHS_IFERR (st)) /* channel error? */ - return rad_chan_err (st); + return rad_chan_err (dva, st); if (st == CHS_CCH) { /* command chain? */ rad_cmd = RADS_INIT; /* restart thread */ sim_activate (uptr, chan_ctl_time); @@ -291,13 +305,13 @@ switch (rad_cmd) { case RADS_SEEK: /* seek */ c[0] = c[1] = 0; for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { - st = chan_RdMemB (rad_dib.dva, &c[i]); /* get byte */ + st = chan_RdMemB (dva, &c[i]); /* get byte */ if (CHS_IFERR (st)) /* channel error? */ - return rad_chan_err (st); + return rad_chan_err (dva, st); } rad_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ - chan_set_chf (rad_dib.dva, CHF_LNTE)) /* care? */ + chan_set_chf (dva, CHF_LNTE)) /* care? */ return SCPE_OK; break; @@ -307,12 +321,12 @@ switch (rad_cmd) { c[2] = GET_PSC (rad_time); /* curr sector */ c[3] = 0; for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) { - st = chan_WrMemB (rad_dib.dva, c[i]); /* store char */ + st = chan_WrMemB (dva, c[i]); /* store char */ if (CHS_IFERR (st)) /* channel error? */ - return rad_chan_err (st); + return rad_chan_err (dva, st); } if (((i != rad_tab[rad_model].nbys) || (st != CHS_ZBC)) && - chan_set_chf (rad_dib.dva, CHF_LNTE)) /* length error? */ + chan_set_chf (dva, CHF_LNTE)) /* length error? */ return SCPE_OK; break; @@ -321,19 +335,19 @@ switch (rad_cmd) { rad_tab[rad_model].tkun; if ((rad_wlk >> gp) & 1) { /* write lock set? */ rad_flags |= RADV_WPE; /* set status */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } /* fall through */ if (rad_inv_ad (&da)) { /* invalid addr? */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; i < RAD_WDSC; da++, i++) { /* write */ if (st != CHS_ZBC) { /* chan active? */ - st = chan_RdMemW (rad_dib.dva, &wd); /* get data */ + st = chan_RdMemW (dva, &wd); /* get data */ if (CHS_IFERR (st)) { /* channel error? */ rad_inc_ad (); /* da increments */ - return rad_chan_err (st); + return rad_chan_err (dva, st); } } else wd = 0; @@ -349,20 +363,20 @@ switch (rad_cmd) { case RADS_CHECK: /* write check */ if (rad_inv_ad (&da)) { /* invalid addr? */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; (i < (RAD_WDSC * 4)) && (st != CHS_ZBC); ) { - st = chan_RdMemB (rad_dib.dva, &wd); /* read sector */ + st = chan_RdMemB (dva, &wd); /* read sector */ if (CHS_IFERR (st)) { /* channel error? */ rad_inc_ad (); /* da increments */ - return rad_chan_err (st); + return rad_chan_err (dva, st); } wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ if (wd != wd1) { /* check error? */ rad_inc_ad (); /* da increments */ - chan_set_chf (rad_dib.dva, CHF_XMDE); /* set xmt err flag */ - chan_uen (rad_dib.dva); /* force uend */ + chan_set_chf (dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (dva); /* force uend */ return SCPE_OK; } da = da + ((++i % 4) == 0); /* every 4th byte */ @@ -373,14 +387,14 @@ switch (rad_cmd) { case RADS_READ: /* read */ if (rad_inv_ad (&da)) { /* invalid addr? */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ return SCPE_OK; } for (i = 0, st = 0; (i < RAD_WDSC) && (st != CHS_ZBC); da++, i++) { - st = chan_WrMemW (rad_dib.dva, fbuf[da]); /* store in mem */ + st = chan_WrMemW (dva, fbuf[da]); /* store in mem */ if (CHS_IFERR (st)) { /* channel error? */ rad_inc_ad (); /* da increments */ - return rad_chan_err (st); + return rad_chan_err (dva, st); } } if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ @@ -403,15 +417,18 @@ return SCPE_OK; t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) { +uint32 un = uptr - rad_unit; +uint32 dva = rad_dib.dva | un; + if (st != CHS_ZBC) { /* end record? */ if (rad_inc_ad ()) /* inc addr, ovf? */ - chan_uen (rad_dib.dva); /* uend */ + chan_uen (dva); /* uend */ else sim_activate (uptr, rad_time * 16); /* no, next sector */ return TRUE; } rad_inc_ad (); /* just incr addr */ if ((lnt != exp) && /* length error? */ - chan_set_chf (rad_dib.dva, CHF_LNTE)) /* do we care? */ + chan_set_chf (dva, CHF_LNTE)) /* do we care? */ return TRUE; return FALSE; /* cmd done */ } @@ -483,9 +500,9 @@ return FALSE; /* Channel error */ -t_stat rad_chan_err (uint32 st) +t_stat rad_chan_err (uint32 dva, uint32 st) { -chan_uen (rad_dib.dva); /* uend */ +chan_uen (dva); /* uend */ if (st < CHS_ERR) return st; return SCPE_OK;