Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_SRC_1_19910112
-
6-1-monitor/phykni.mac
There are 19 other files named phykni.mac in the archive. Click here to see a list.
;[SRI-NIC]SRC:<6-1-MONITOR>PHYKNI.MAC.4, 5-Jul-88 15:23:46, Edit by MKL
; add some stats (IS.IEN) to count packets for SYSDPY display
; *** Edit 7326 to PHYKNI.MAC by MCCOLLUM on 23-Jun-86
; Store the new physical address in UNCAR instead of UNDAD in NISCA
; *** Edit 7286 to PHYKNI.MAC by MCCOLLUM on 14-Apr-86
; Store the ethernet address in the UN block before issuing the callbacks in
; NISCA
;------------------------- Autopatch Tape # 13 -------------------------
;------------------------- Autopatch Tape # 12 -------------------------
; Edit 7174 to PHYKNI.MAC by PALMIERI on 28-Oct-85 (TCO 6.1.1544)
; Fix invalid KNIIEC BUGHLTs.
; Edit 7134 to PHYKNI.MAC by GRANT on 15-Aug-85 (TCO 6-1-1522)
; Turn off the NI at BUGHLT and PAR>SHUT time
; UPD ID= 2295, SNARK:<6.1.MONITOR>PHYKNI.MAC.117, 15-Jul-85 15:14:06 by PALMIERI
;TCO 6.1.1482 Add routine KNIRSC to reset all channels if requested by
; PHYSIO (usually after a power failure).
; UPD ID= 2292, SNARK:<6.1.MONITOR>PHYKNI.MAC.116, 9-Jul-85 14:00:33 by PALMIERI
;Change call to BUGHLT to a RET at KNIDSP reset channel function from PHYSIO.
;It was assumed this call would never be made. This is temporary until we
;decide if reloading the KLNI is the appropriate thing to do.
; UPD ID= 2285, SNARK:<6.1.MONITOR>PHYKNI.MAC.115, 28-Jun-85 11:15:19 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 2224, SNARK:<6.1.MONITOR>PHYKNI.MAC.114, 17-Jun-85 11:10:28 by GROSSMAN
;TCO 6.1.1452 - Fix symbols for SYSERR related stuff.
;TCO 6.1.1453 - Fix keep-alive stuff to be more sensitive to messed up command
;queues.
; UPD ID= 2162, SNARK:<6.1.MONITOR>PHYKNI.MAC.113, 5-Jun-85 10:42:54 by GROSSMAN
;TCO 6.1.1425 - Make KNIIPF a BUGHLT, start removing TOPS-10 conditionals.
;TCO 6.1.1424 - Use seperate BUGINFs for each planned CRAM parity error.
; UPD ID= 2027, SNARK:<6.1.MONITOR>PHYKNI.MAC.111, 28-May-85 16:59:22 by GROSSMAN
;TCO 6.1.1413 - Fix NIRPI to return multicasts correctly.
; UPD ID= 2004, SNARK:<6.1.MONITOR>PHYKNI.MAC.110, 24-May-85 12:02:23 by MCCOLLUM
;Fix KNIPPE Bug.
; UPD ID= 1999, SNARK:<6.1.MONITOR>PHYKNI.MAC.109, 23-May-85 14:29:27 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1955, SNARK:<6.1.MONITOR>PHYKNI.MAC.108, 10-May-85 16:47:32 by GROSSMAN
;TCO 6.1.1376 - Make NIINI non global.
; UPD ID= 1951, SNARK:<6.1.MONITOR>PHYKNI.MAC.107, 9-May-85 17:39:35 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1940, SNARK:<6.1.MONITOR>PHYKNI.MAC.106, 9-May-85 16:51:20 by GROSSMAN
;TCO 6.1.1372 - Fix ERRDSP dispatch table to not jump into section 0 when
;an unknown error code is received from the port.
; UPD ID= 1920, SNARK:<6.1.MONITOR>PHYKNI.MAC.105, 7-May-85 21:11:35 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1914, SNARK:<6.1.MONITOR>PHYKNI.MAC.104, 6-May-85 20:11:50 by GROSSMAN
;TCO 6.1.1364 - Check for existance of KLNI before playing with it.
; UPD ID= 1863, SNARK:<6.1.MONITOR>PHYKNI.MAC.103, 2-May-85 17:15:51 by GROSSMAN
;TCO 6.1.1355 - Prevent KNIIPT BUGHLTs by preventing NIDPT from giving
;error returns.
; UPD ID= 1843, SNARK:<6.1.MONITOR>PHYKNI.MAC.102, 30-Apr-85 11:55:45 by MCCOLLUM
;TCO 6.1.1238 - Fix more BUG. documentation
; UPD ID= 1743, SNARK:<6.1.MONITOR>PHYKNI.MAC.101, 9-Apr-85 14:03:52 by MCCOLLUM
;More of TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1742, SNARK:<6.1.MONITOR>PHYKNI.MAC.100, 9-Apr-85 14:01:08 by MCCOLLUM
;TCO 6.1.1238 - Fix BUG. documentation
; UPD ID= 1678, SNARK:<6.1.MONITOR>PHYKNI.MAC.99, 25-Mar-85 10:58:08 by GROSSMAN
;TCO 6.1.1285 - Fix KNIRTO. Remove code under FTCKM, and fix NF.RPI.
; UPD ID= 1667, SNARK:<6.1.MONITOR>PHYKNI.MAC.98, 22-Mar-85 11:27:54 by GROSSMAN
;More TCO 6.1.1283 - Change various BUGINF's to BUGCHK's and vice versa. Also,
;fix text for KNICFF.
; UPD ID= 1662, SNARK:<6.1.MONITOR>PHYKNI.MAC.97, 21-Mar-85 23:22:15 by GROSSMAN
;TCO 6.1.1283 - Fix KNISTP. Make KNIRFD a BUGINF, KNIUOP a BUGHLT. Fix
;some bugs in code under FTHIST.
; UPD ID= 1561, SNARK:<6.1.MONITOR>PHYKNI.MAC.96, 22-Feb-85 17:17:25 by GROSSMAN
;TCO 6.1.1217 - Don't set Ethernet address to 0 if it hasn't been initialized.
; UPD ID= 1541, SNARK:<6.1.MONITOR>PHYKNI.MAC.95, 20-Feb-85 10:00:55 by GROSSMAN
;More TCO 6.1.1204 - Correct TCO number in edit 1529.
; UPD ID= 1534, SNARK:<6.1.MONITOR>PHYKNI.MAC.94, 19-Feb-85 12:00:45 by GROSSMAN
;TCO 6.1.1209 - Clean up the response queue in KNIERR so that we get RQA
;interrupts when we restart the port.
; UPD ID= 1530, SNARK:<6.1.MONITOR>PHYKNI.MAC.93, 18-Feb-85 23:36:07 by GROSSMAN
;TCO 6.1.1205 - Fix wrong code at NIDPT + a few.
; UPD ID= 1529, SNARK:<6.1.MONITOR>PHYKNI.MAC.92, 18-Feb-85 23:13:17 by GROSSMAN
;TCO 6.1.1204 - Fix detection of Planned CRAM Parity Errors.
; UPD ID= 1508, SNARK:<6.1.MONITOR>PHYKNI.MAC.91, 12-Feb-85 14:45:53 by GROSSMAN
;TCO 6.1.1181 - Add new version number format support for the KLNI.
; UPD ID= 1465, SNARK:<6.1.MONITOR>PHYKNI.MAC.90, 2-Feb-85 11:38:59 by GROSSMAN
;TCO 6.1.1170 - Call NISTP before doing a KNISTP so that we get the micro PC.
; UPD ID= 1463, SNARK:<6.1.MONITOR>PHYKNI.MAC.89, 2-Feb-85 11:28:20 by GROSSMAN
;TCO 6.1.1169 - Create a CDB and dispatch table so that DIAG% can manipulate
;the KLNI's channel logout area. In addition, make ENBKLP call NISTP when
;initialization fails.
; UPD ID= 1424, SNARK:<6.1.MONITOR>PHYKNI.MAC.88, 29-Jan-85 14:36:19 by GROSSMAN
;TCO 6.1.1162 - Add state UNS.RR - Request Reload. Setting this state causes
;STRLD to be called (which eventually makes KNILDR run and reload the KLNI).
; UPD ID= 1408, SNARK:<6.1.MONITOR>PHYKNI.MAC.87, 28-Jan-85 09:53:51 by GROSSMAN
;Do previous edit in a better way.
; UPD ID= 1396, SNARK:<6.1.MONITOR>PHYKNI.MAC.86, 22-Jan-85 23:59:53 by PAETZOLD
;TCO 6.1.1152 - Make sure buffers coming out of NIDPT2 have a clear address.
; UPD ID= 1348, SNARK:<6.1.MONITOR>PHYKNI.MAC.85, 16-Jan-85 13:41:44 by GROSSMAN
;More TCO 6.1.1122 - Work around KNISV for RDTIME bug in non-zero sections.
; UPD ID= 1341, SNARK:<6.1.MONITOR>PHYKNI.MAC.84, 15-Jan-85 23:59:31 by GROSSMAN
;More TCO 6.1.1137 - Call RUNDII in the correct section. Make sure all
;addresses passed to RUNDII are global.
; UPD ID= 1339, SNARK:<6.1.MONITOR>PHYKNI.MAC.83, 15-Jan-85 14:24:27 by GROSSMAN
;TCO 6.1.1137 - Move KNIJB0 to section 6 so it can live harmoniously with the
;rest of NISRV.
;TCO 6.1.1136 - Remove all references to KNIN.
; UPD ID= 1310, SNARK:<6.1.MONITOR>PHYKNI.MAC.82, 11-Jan-85 14:06:29 by PAETZOLD
;Do not use KNIN for assembly control since it is a global symbol from STG.
; UPD ID= 1291, SNARK:<6.1.MONITOR>PHYKNI.MAC.81, 9-Jan-85 11:05:37 by GROSSMAN
;TCO 6.1.1122 - Move to section 6. Fix NIRSI to prevent KNISTPs. Don't call
;SETSTA with bogus PS from KNIJB0. Fix GETCOR so that 4 word alignment is no
;longer done.
; UPD ID= 1275, SNARK:<6.1.MONITOR>PHYKNI.MAC.80, 6-Jan-85 15:20:32 by GROSSMAN
;TCO 6.1.1113 - Put KNIFQE, KNIDMD/DM1 under control of NIBUGX.
; UPD ID= 1267, SNARK:<6.1.MONITOR>PHYKNI.MAC.79, 4-Jan-85 09:06:26 by GROSSMAN
;TCO 6.1.1109 - Rewrite NIDRA & implement a multicast address use count. Re-do
;NIWSI & friends so that they won't smash the promiscuous & promiscuous
;multicast bits. Accumulate total time at interrupt level in TOTINT. Add a
;memory request cache for xmits & receives. Get rid of all code under DEBUG.
;Remove extra RESCDs. Get rid of various NF. functions and routines. Zero
;shadow counters during KLNI restarts. Increase KNIRTO timeout value. Re-do
;NIEPT and FNDPT to make protocol types -2 & -3 work (and work nicely). Make
;NIDPT also disable all multicasts associated with the portal.
; UPD ID= 1187, SNARK:<6.1.MONITOR>PHYKNI.MAC.78, 11-Dec-84 14:56:28 by GROSSMAN
;More TCO 6.1.1072 - Detect length errors at the correct place, and fix error
;code UNRFD%.
; UPD ID= 1149, SNARK:<6.1.MONITOR>PHYKNI.MAC.77, 5-Dec-84 00:37:50 by GROSSMAN
;TCO 6.1.1072 - Remove NIRES and friends. Add error recovery for response
;errors.
; UPD ID= 1106, SNARK:<6.1.MONITOR>PHYKNI.MAC.76, 20-Nov-84 01:01:28 by GROSSMAN
;TCO 6.1.1061 - Rewrite SETSTA. Make sure external state properly reflects
;internal state.
; UPD ID= 1084, SNARK:<6.1.MONITOR>PHYKNI.MAC.75, 16-Nov-84 15:18:32 by GROSSMAN
;More of TCO 6.1.1051 - Don't start timing until job 0 runs.
; UPD ID= 1068, SNARK:<6.1.MONITOR>PHYKNI.MAC.74, 13-Nov-84 18:00:55 by GROSSMAN
;TCO 6.1.1051 - Implement timeout for KNILDR. If KNILDR doesn't complete in
; 15. seconds, give a KNIRTO BUGCHK and put port in UNS.CR state.
; UPD ID= 1048, SNARK:<6.1.MONITOR>PHYKNI.MAC.73, 13-Nov-84 00:10:12 by GROSSMAN
; TCO 6.1.1047 - Many fixes in preparation for NI% JSYS.
; - Implement command abort for dead ports.
; - Make receive abort code (NIDPT) use MSGAVA.
; - Add KNICRS as mousetrap for spurious KNISTP's.
; - Remove NISCH (and CALL in LV8CHK).
; - KNISTP now calls NISTP to really stop the port.
; - Change XCTUU to XCTU in FIXBSD for user mode address case.
; - Make sure that RCRCC zeroes Receive Failure Bit Mask if Receive Failure
; Counter is 0.
; - Fix race in NISTP by disabling PSCQA before stopping port.
; UPD ID= 784, SNARK:<6.1.MONITOR>PHYKNI.MAC.69, 4-Sep-84 14:04:26 by GROSSMAN
; Fix NSARD for the case when no address is ever set.
; UPD ID= 781, SNARK:<6.1.MONITOR>PHYKNI.MAC.68, 4-Sep-84 00:30:26 by GROSSMAN
; Clear the KLNI at the beginning of NIINIA. Don't do anything if user is
; setting KLNI state to it's current value.
; UPD ID= 767, SNARK:<6.1.MONITOR>PHYKNI.MAC.67, 30-Aug-84 22:28:29 by GROSSMAN
; Fix management of port variables. Make port restart code work right.
; UPD ID= 763, SNARK:<6.1.MONITOR>PHYKNI.MAC.66, 27-Aug-84 15:30:09 by GROSSMAN
; Various and sundry fixes for port restart.
; UPD ID= 749, SNARK:<6.1.MONITOR>PHYKNI.MAC.65, 23-Aug-84 09:30:59 by GROSSMAN
; Start putting in auto reload code for KLNI.
; Fix a possible buffer corruption bug in FIXBSD.
; Implement NISCS (Set Channel State).
; Remove some junk code.
; UPD ID= 737, SNARK:<6.1.MONITOR>PHYKNI.MAC.64, 10-Aug-84 17:33:04 by GROSSMAN
; Fix reading of the ROM address, and re-do some of the keep-alive code. Also,
; don't check state anymore in QUECMD - PSCQA will change to do the correct
; thing based upon the current state of the channel.
; UPD ID= 720, SNARK:<6.1.MONITOR>PHYKNI.MAC.63, 28-Jul-84 14:30:51 by GROSSMAN
; Fix initialization bug by not setting CQA and ENA simultaneously in ENBKLP.
; UPD ID= 715, SNARK:<6.1.MONITOR>PHYKNI.MAC.62, 27-Jul-84 00:19:14 by GROSSMAN
; Implement BSD receives and new un-scrambled address format. Start
; implementing state machine. Many minor bug fixes.
; UPD ID= 557, SNARK:<6.1.MONITOR>PHYKNI.MAC.61, 24-May-84 14:03:23 by GROSSMAN
; Add history buffer maintenance code.
; Fix bug in NIDPT. Don't use protocol type as a monitor address. Clear T3
; on return from read counters.
; UPD ID= 521, SNARK:<6.1.MONITOR>PHYKNI.MAC.60, 14-May-84 10:05:25 by GROSSMAN
; Fix non-contiguous transmit buffers. Fix race in .NION and .NIOFF.
; UPD ID= 466, SNARK:<6.1.MONITOR>PHYKNI.MAC.59, 27-Apr-84 13:41:32 by GROSSMAN
; Implement NISRV.MEM.
; UPD ID= 368, SNARK:<6.1.MONITOR>PHYKNI.MAC.58, 2-Mar-84 02:27:21 by GROSSMAN
; Fix counters. Expand counters block for extra reserved words required by
; KLNI error detection/recovery.
; Speed up posting of receive buffers by remembering free-q header address in
; PRFQA instead of searching the PTT.
; UPD ID= 336, SNARK:<6.1.MONITOR>PHYKNI.MAC.57, 17-Feb-84 00:50:59 by GROSSMAN
; Fix moby race caused by allowing scheduler to run while NIPIA channel is off!
; Copy counters from Read Counters block to the user's buffer.
; UPD ID= 330, SNARK:<6.1.MONITOR>PHYKNI.MAC.56, 10-Feb-84 16:29:42 by GROSSMAN
; NISRB - Check receive buffers for physical contiguity.
; UPD ID= 318, SNARK:<6.1.MONITOR>PHYKNI.MAC.55, 8-Feb-84 17:39:26 by GROSSMAN
; Many numerous and sundry fixes to avoid race due to NP blocks. NP blocks
; go away. New AC conventions. Considerable speedups in transmit and
; receive paths. Interrupts cleaned up. Some support for error recovery.
; Read ucode version before starting the port, and make it more accessible to
; humans by storing it into a full word field. Also, add code to distinguish
; between the ROM address and a software address. PSHAD & PSLAD now contain
; the soft address, PSHRA & PSLRA now contain the ROM address.
; UPD ID= 235, SNARK:<6.1.MONITOR>PHYKNI.MAC.54, 7-Nov-83 21:42:25 by GROSSMAN
; Add new dispatch to KNIDSP for PORT RELEASE function.
; UPD ID= 229, SNARK:<6.1.MONITOR>PHYKNI.MAC.53, 28-Oct-83 14:52:21 by GROSSMAN
; Make GETCOR a little smarter about BNC's. Have it first call GETCOR to
; get a new block, then call RELCOR to release the bad block.
; UPD ID= 227, SNARK:<6.1.MONITOR>PHYKNI.MAC.52, 27-Oct-83 14:08:08 by GROSSMAN
; Make GETCOR try again when it gets a BNC.
; UPD ID= 223, SNARK:<6.1.MONITOR>PHYKNI.MAC.51, 26-Oct-83 10:36:30 by GROSSMAN
; Start writing new chunk manager. This is under the FTCKM conditional.
; Fix hung port problem by making CHKBUF a little smarter. It didn't handle
; the case where physical memory ran backwards w/respect to virtual memory.
;
;WORK:<GROSSMAN.BUILD>PHYKNI.MAC.69 24-Oct-83 14:26:40, Edit by GROSSMAN
; Only report line state change once when in maintenance mode.
; Make CHKBUF smarter about page boundaries.
; Take remainder into account when converting buffer size into words.
; Add more info to KNISTP. Print out the LAR, and the CONI.
; UPD ID= 192, SNARK:<6.1.MONITOR>PHYKNI.MAC.50, 9-Aug-83 10:55:01 by GROSSMAN
; Convert buffer size to words when queueing up receive buffers (NISRB).
; Don't report errors twice, only report them at interrupt level.
; UPD ID= 172, SNARK:<6.1.MONITOR>PHYKNI.MAC.49, 22-Jul-83 10:23:33 by GROSSMAN
; Include CO.BTS when doing the CONO to clear FQE.
; UPD ID= 171, SNARK:<6.1.MONITOR>PHYKNI.MAC.48, 22-Jul-83 01:49:05 by GROSSMAN
; Use different symbol for ucode word in read counters response block.
; Handle Free Queue Errors differently.
; UPD ID= 169, SNARK:<6.1.MONITOR>PHYKNI.MAC.47, 21-Jul-83 19:51:57 by GROSSMAN
; Add comment to 168
; UPD ID= 168, SNARK:<6.1.MONITOR>PHYKNI.MAC.46, 21-Jul-83 19:45:13 by GROSSMAN
; Add one word to the Read Counters response block.
; UPD ID= 159, SNARK:<6.1.MONITOR>PHYKNI.MAC.45, 11-Jul-83 15:04:42 by RIZZOLO
; Move the NI.xxx symbols from PHYKNI into D36PAR so NIDLL can use them.
; UPD ID= 157, SNARK:<6.1.MONITOR>PHYKNI.MAC.44, 1-Jul-83 10:42:05 by LEAPLINE
; UPD ID= 156, SNARK:<6.1.MONITOR>PHYKNI.MAC.43, 1-Jul-83 10:30:44 by LEAPLINE
;Do some general clean up.
; UPD ID= 148, SNARK:<6.1.MONITOR>PHYKNI.MAC.41, 15-Jun-83 14:50:35 by LEAPLINE
;Change code at NIDRA to get the address from the correct place (NPDID)
;Make checks at all entry points for channel being a KLNI port.
; UPD ID= 128, SNARK:<6.1.MONITOR>PHYKNI.MAC.35, 10-May-83 12:13:54 by LEAPLINE
;Remove read counters test code.
; UPD ID= 125, SNARK:<6.1.MONITOR>PHYKNI.MAC.33, 9-May-83 11:43:00 by LEAPLINE
;Make use of CDB's.
;Remove channel independant code. IOEXE is REPEAT 0'ED OUT.
;SNARK:<6.1.MONITOR>PHYKNI.MAC.10, 7-APR-83 10:16:11 by RIZZOLO
;Fix Protocol type problems at SETFQH+some.
;Fixup REDIT changes.
;SNARK:<6.1.MONITOR>PHYKNI.MAC.10, 16-Mar-83 14:14:36 by RIZZOLO
;Add code to support the new DLL to port driver interfaces.
; UPD ID= 54, SNARK:<6.1.MONITOR>PHYKNI.MAC.9, 22-Feb-83 12:16:45 by LEAPLINE
;Make DSPTBL all illegal functions.
; UPD ID= 52, SNARK:<6.1.MONITOR>PHYKNI.MAC.8, 19-Feb-83 14:04:41 by LEAPLINE
;Remove NISFLG and return to SCHED if queue empty instead of BUG.
; UPD ID= 51, SNARK:<6.1.MONITOR>PHYKNI.MAC.6, 18-Feb-83 18:48:51 by LEAPLINE
;If no KLNI, set level 2 clock checks very high.
; UPD ID= 50, SNARK:<6.1.MONITOR>PHYKNI.MAC.5, 18-Feb-83 18:31:55 by LEAPLINE
;Fix bug in KNICHK.
; UPD ID= 49, SNARK:<6.1.MONITOR>PHYKNI.MAC.4, 18-Feb-83 11:31:28 by LEAPLINE
;Add routine KNICHK for periodic checks.
;Fix REMQUE to do standard +1 and +2 returns. Also, make IOEXE require the
; instruction to execute in T1 instead of P.
; UPD ID= 21, SNARK:<6.1.MONITOR>PHYKNI.MAC.3, 11-Feb-83 07:15:43 by LEAPLINE
;Take out save of AC's in PUTQUE, REMQUE. Routine adjusts P for returns.
; UPD ID= 30, SNARK:<6.DECNET>PHYKNI.MAC.9, 30-Jan-83 12:49:14 by LEAPLINE
;Do total clean up of all queues on RESET.
;Change interrupt processing to process selected entries from the RESPONSE Q
; UPD ID= 18, SNARK:<6.DECNET>PHYKNI.MAC.7, 17-Jan-83 17:39:10 by LEAPLINE
;Change interrupt processing to only check for errors and set a scheduler
;flag to finish the processing of the response queue.
;Changed definition of bit 33 in station register. WSENA --> WSPMC
; UPD ID= 10, SNARK:<6.DECNET>PHYKNI.MAC.6, 15-Dec-82 20:20:33 by LEAPLINE
;Use DNGWDZ and DNFWDS instead of ASGRES and RELRES.
; UPD ID= 9, SNARK:<6.DECNET>PHYKNI.MAC.5, 13-Dec-82 09:32:57 by LEAPLINE
;Correct interrupt handling code.
; UPD ID= 8, SNARK:<6.DECNET>PHYKNI.MAC.4, 10-Dec-82 13:03:22 by LEAPLINE
;Fix bug in IOEXE routine.
; UPD ID= 7, SNARK:<6.DECNET>PHYKNI.MAC.3, 10-Dec-82 10:30:09 by LEAPLINE
;Make CMDDSP 0 a temp dispatch for datagram received. Also, put in counter
;for LONG WORD COUNT ERRORS. Microcode can cause these.
; UPD ID= 6, SNARK:<6.DECNET>PHYKNI.MAC.2, 9-Dec-82 10:53:12 by LEAPLINE
;TCO 6.1.XXXX More KLNI support
; UPD ID= 4, SNARK:<6.DECNET>PHYKNI.MAC.1, 7-Dec-82 15:32:24 by LEAPLINE
SUBTTL S. LEAPLINE 27-SEP-82
SUBTTL PHYKNI - DEVICE DEPENDENT CODE FOR KLNI PORT
SEARCH PROLOG ;SYSTEM PARAMETERS
SEARCH PHYPAR,SERCOD
;Special AC's
DEFAC PS,Q3 ; Points to PS (port storage) block
DEFAC CM,P4 ; Points to current command block
SUBTTL KNOWN BUGS AND DEFICIENTIES
COMMENT/
Stu 9 may 84 - Fixed 5-Dec-84
Error recovery needs to be added. Currently, a BUGxxx is given
for the errors detected.
Stu 9 May 84 - Fixed 6-Jan-85
A mechanism for returning FREE QUEUE ERROR to the user must be
invented.
Stu 9 May 84 - Fixed
CM blocks don't get returned when a command gets an error.
Stu 9 May 84 - Fixed 4-Jan-85
Need new memory mangler to prevent KNIBNCs.
Stu 9 May 84 - Fixed
MSD style sends don't handle non-physically contiguous buffer
segments.
Stu 9 May 84 - Fixed
UNSTA not updated as per spec.
Stu 9 May 84 - Fixed 24 May 84
Open of information portals fails for no good reason.
Stu 24 May 84 - Fixed
Initialization failures not handled correctly. ENBKLP and
friends need to be made smarter.
Stu 23 July 84
MAPs need to check results.
Stu 27 August 84 - Fixed
NIWSI, LDPTT, LDMCT should be done first after a port restart.
Stu 15 October 84
NOINT's need to be placed around all instances of GETCOR.
Stu 11 November 84 - Fixed 4-Jan-85
DLLCLO should disable any multicast addresses associated with the
portal.
Stu 11 December 84
Things that acquire interlocks should leave some info laying around.
Stu 11 December 84
When restarting the port, reset all the interlock words.
/
SUBTTL Special macros
DEFINE $SAVE(syms)<
IRP syms,<.$SAV1(syms,\...STK)>
.$SAV1($RESTORE,\...STK)
DEFINE $RESTORE<.$RES1($RESTORE,\...STK)
.$RES2(syms)>
>
SUBTTL CONX BIT DEFINITIONS
RH0==540 ;DEVICE CODE FOR RH0
;Channel Command Word definitions (taken directly from PHYH2). These are
;needed here because KLNI initialization involves setting up a CCW to the
;PCB, and then starting the KLIPA which then transfers some information at
;the specified address that indicates the PCB address, PI level of the
;device, and some other stuff.
CHXFR==1B0 ;INDICATE XFER WORD
CHJMP==2B2 ;INDICATE CHANNEL JUMP
CHLST==1B1 ;INDICATE LAST XFER
CHREV==1B2 ;INDICATE REVERSE
CHCNT==MASKB(3,13) ;MASK FOR WORD COUNT IN CCW
CHADR==MASKB(14,35) ;MASK FOR PHYSICAL ADDRESS IN CCW
;CONI BITS - LEFT (defined in the IPA20-L spec)
CI.PPT==1B0 ;PORT PRESENT
CI.DCC==1B2 ;DIAG CSR CHANGE
CI.CPE==1B6 ;CRAM PARITY ERROR
CI.MBE==1B7 ;MBUS ERROR
CI.IDL==1B11 ;IDLE
CI.DCP==1B12 ;DISABLE COMPLETE
CI.ECP==1B13 ;ENABLE COMPLETE
;CONI/CONO BITS - RIGHT
CO.CPT==1B18 ;CLEAR PORT
CO.LAR==1B21 ;SELECT LAR
CI.EPE==1B24 ;EBUS PARITY ERROR
CI.FQE==1B25 ;FREE QUEUE ERROR
CI.DME==1B26 ;DATA MOVER ERROR
CO.CQA==1B27 ;COMMAND QUEUE AVAILABLE
CI.RQA==1B28 ;RESPONSE QUEUE AVAILABLE
CO.DIS==1B30 ;DISABLE
CO.ENA==1B31 ;ENABLE
CO.MRN==1B32 ;MICRO-PROCESSOR RUN
CO.BTS==CO.ENA!CO.MRN!NIPIA ;BITS WHICH NEED TO BE ON IN ALL CONOS
CI.ERR==CI.CPE!CI.MBE!CI.EPE!CI.DME ;HARDWARE ERROR BITS
CI.INT==CI.FQE!CI.RQA ;NORMAL INTERRUPT BITS
DO.LRA==1B0 ;BIT ON IN DATAO TO LOAD RAM ADDRESS REGISTER
DEFSTR MICPC,,12,12 ;UPROC PC FIELD WHEN READ VIA A DATAI
DEFSTR UCMAJ,,25,6 ; Major version #
DEFSTR UCMIN,,29,4 ; Minor version #
DEFSTR UCEDT,,29,10 ; Edit #
MICVER==136 ; Microcode major and minor version #s
MICEDT==137 ; Microcode edit #
MINCPE==7750 ;LOWEST PLANNED CRAM PARITY ERROR
MAXCPE==7777 ;HIGHEST PLANNED CRAM PARITRY ERROR
SUBTTL Error Definitions
; These codes are returned somewhere in the CMERR field of each completed
; command. These codes are only valid if the low order bit is 1.
NI.EXC==0 ; Excessive collisions
NI.CCF==1 ; Carrier check failed
NI.CDF==2 ; Collision detect check failed
NI.SCI==3 ; Short circuit
NI.OCI==4 ; Open circuit
NI.FTL==5 ; Frame too long
NI.RFD==6 ; Remote failure to defer
NI.BCE==7 ; Block check error (CRC error)
NI.FER==10 ; Framing error
NI.DOV==11 ; Data overrun
NI.UPT==12 ; Unrecognized protocol type?!?
NI.FTS==13 ; Frame too short
NI.SCE==27 ; Spurious channel error
NI.CER==30 ; Channel error (WC <> 0)
NI.QLV==31 ; Queue length violation
NI.IPL==32 ; Illegal PLI function
NI.URC==33 ; Unrecognized command
NI.BLV==34 ; Buffer length violation
NI.RSV==35 ; Reserved
NI.TBP==36 ; Xmit buffer parity error
NI.INT==37 ; Internal error
SUBTTL STRUCTURE DEFINITIONS FOR THE PCB
COMMENT / THE FOLLOWING IS THE PORT CONTROL BLOCK FORMAT
+-------------------------------------------------------+
PBCQI ! Command Queue Interlock !
+-------------------------------------------------------+
PBCQF ! Command Queue FLINK !
+-------------------------------------------------------+
PBCQB ! Command Queue BLINK !
+-------------------------------------------------------+
PBRS0 ! RESERVED !
+-------------------------------------------------------+
PBRQI ! Response Queue Interlock !
+-------------------------------------------------------+
PBRQF ! Response Queue FLINK !
+-------------------------------------------------------+
PBRQB ! Response Queue BLINK !
+-------------------------------------------------------+
PBRS1 ! RESERVED !
+-------------------------------------------------------+
PBUQI ! Unknown Protocol Type Queue Interlock !
+-------------------------------------------------------+
PBUQF ! Unknown Protocol Type FLINK !
+-------------------------------------------------------+
PBUQB ! Unknown Protocol Type BLINK !
+-------------------------------------------------------+
PBUQL ! Unknown Protocol Queue Entry Length !
+-------------------------------------------------------+
PBRS2 ! RESERVED !
+-------------------------------------------------------+
PBPTT ! Protocol Type Table starting address !
+-------------------------------------------------------+
PBMTT ! Multicast Address Table starting address !
+-------------------------------------------------------+
PBRS3 ! RESERVED !
+-------------------------------------------------------+
PBER0 ! Error Logout 0 !
+-------------------------------------------------------+
PBER1 ! Error Logout 1 !
+-------------------------------------------------------+
PBLAD ! Address of Channel Logout Word 1 !
+-------------------------------------------------------+
PBCLO ! Contents of Channel Logout Word 1 !
+-------------------------------------------------------+
PBPBA ! Port Control Block base address !
+-------------------------------------------------------+
PBPIA ! PI Level Assignment !
+-------------------------------------------------------+
PBIVA ! Interrupt Vector Assignment !
+-------------------------------------------------------+
PBCCW ! Channel Command Word !
+-------------------------------------------------------+
PBRS4 ! RESERVED FOR PORT !
+-------------------------------------------------------+
/
BEGSTR PB
WORD CQI ;COMMAND QUEUE INTERLOCK
WORD CQF ;COMMAND QUEUE FLINK
WORD CQB ;COMMAND QUEUE BLINK
WORD RS0 ;RESERVED FOR SOFTWARE
WORD RQI ;RESPONSE QUEUE INTERLOCK
WORD RQF ;RESPONSE QUEUE FLINK
WORD RQB ;RESPONSE QUEUE BLINK
WORD RS1 ;RESERVED
WORD UQI ;UNKNOWN PROTOCOL TYPE QUEUE INTERLOCK
WORD UQF ;UNKNOWN PROTOCOL TYPE QUEUE FLINK
WORD UQB ;UNKNOWN PROTOCOL TYPE QUEUE BLINK
WORD UQL ;UNKNOWN PROTOCOL TYPE QUEUE LENGTH
WORD RS2 ;RESERVED
WORD PTT ;PROTOCOL TYPE TABLE STARTING ADDRESS
WORD MTT ;MULTICAST ADDRESS TABLE STARTING ADDRESS
WORD RS3 ;RESERVED
WORD ER0 ;KLNI ERROR LOGOUT 0
WORD ER1 ;KLNI ERROR LOGOUT 1
WORD LAD ;ADDRESS OF CHANNEL LOGOUT WORD 1
WORD CLO ;CONTENTS OF CHANNEL LOGOUT WORD 1
WORD PBA ;PORT CONTROL BLOCK BASE ADDRESS
WORD PIA ;PI LEVEL ASSIGNMENT
WORD IVA ;INTERRUPT VECTOR ASSIGNMENT
WORD CCW ;CHANNEL COMMAND WORD
WORD RCB ;POINTER TO READ COUNTERS BUFFER
ENDSTR
SUBTTL PTT AND MTT DEFINITIONS
;PROTOCOL TYPE TABLE. NOTHING MAY BE ADDED WITHOUT AFFECTING THE UCODE.
BEGSTR PT
FIELD ENA,1 ; Protocol is enabled
FILLER 15 ; MBZ
FIELD TYP,16 ; Protocol type
FIELD FRE,1,35 ; 1 means entry is free
WORD FRQ ; Free queue header address
WORD VIR ; Virtual address of free queue header
ENDSTR
;MULTI-CAST ADDRESS TABLE. NOTHING MAY BE ADDED WITHOUT AFFECTING THE UCODE.
BEGSTR MT
WORD HAD ; High order address
FIELD LAD,36,35 ; Low order address
MSKSTR MTUSE,NMTT*MT.LST,-1 ; Usage count for this multicast
MSKSTR MTENA,MT.LAD,1 ; Enable bit
ENDSTR
SUBTTL COMMAND DEFINITIONS
;ALL COMMANDS HAVE THE FOLLOWING FORMAT. NOTHING CAN BE ADDED TO THE CM DEFINE.
BEGSTR CM
WORD FLI ;FORWARD LINK
MSKSTR CMERC,CM.FLI,CMFLI ;NISRV ERROR CODE DURING COMMAND PROCESSING
WORD BLI ;BACKWARD LINK
WORD VAD ;VIRTUAL ADDRESS OF ENTRY
;STATUS FIELD
FIELD SRI,1,1 ;SEND/RECEIVE INDICATOR
FIELD ERR,6 ;Error code including error bit at bottom
;FLAGS FIELD
FIELD FLG,8 ;FLAGS FIELD
BIT PAC ;PACKING MODE FOR NON-BSD
BIT CRC ;CRC INCLUDED
BIT PAD ;UNUSED
BIT B03 ;UNUSED
BIT BSD ;BUFFER SEGMENT DESCRIPTOR FORMAT
BIT B05 ;UNUSED
BIT CLR ;CLEAR COUNTERS
BIT RSP ;RESPONSE NEEDED
;OPCODE
FIELD OPC,8 ;OPCODE
;OPERATION CODE DEFINITIONS
OP.FLS==0 ;FLUSH COMMANDS -- MUST BE ILLEGAL OPCODE
OP.SND==1 ;SEND DATAGRAM
OP.LDM==2 ;LOAD MUTICAST ADDRESS TABLE
OP.LDP==3 ;LOAD PROTOCOL TYPE TABLE
OP.RCC==4 ;READ AND CLEAR COUNTERS
OP.RCV==5 ;DATAGRAM RECEIVED
OP.WPL==6 ;WRITE PLI
OP.RPL==7 ;READ PLI
OP.RSI==8 ;READ STATION INFORMATION
OP.WSI==9 ;WRITE STATION INFORMATION
;TDR
FIELD TDR,^D10,^D35 ;Time domain reflectometry value
ENDSTR
SUBTTL SEND DATAGRAM DEFINITIONS
;NON-BSD DEFINITIONS. NOTHING MAY BE ADDED WITHOUT AFFECTING THE UCODE.
BEGSTR SN,CM.LST
FIELD TXL,16,35 ;TEXT LENGTH (BYTES)
FIELD PTY,16,31 ;PROTOCOL TYPE
WORD FRQ ;FREE QUEUE HEADER ADDRESS
WORD HAD ;HIGH ORDER ADDRESS
WORD LAD ;LOW ORDER
ENDSTR
;BSD STYLE DATAGRAMS
BEGSTR SB,SN.LST
WORD BBA ; Physical BSD base address
; Anything may be added from here on ****
WORD PID ; Portal ID
WORD MSD ; MSD pointer
WORD RID ; Request ID
WORD BFA,2 ; Buffer address
WORD RES,2 ; Pad out to 4 word boundary
ENDSTR
;BSD DEFINITIONS
BEGSTR BD
FIELD PAC,2,7 ;PACKING MODE
FIELD SBA,24,35 ;PHYSICAL SEGMENT BASE ADDRESS
WORD NXA ;PHYSICAL NEXT BSD ADDRESS
WORD SLN ;SEGMENT LENGTH
WORD RES ;RESERVED FOR SOFTWARE
;**** ADDITION DEFINITIONS MAY BE ADDED HERE
ENDSTR
SUBTTL PORT STORAGE DEFINITIONS
;SOFTWARE DEFINED ONLY.
BEGSTR PS
WORD NXT ; Pointer to next channel block
WORD PCB ;PORT CONTROL BLOCK BASE ADDRESS (VIRTUAL)
WORD PBA ;PORT CONTROL BLOCK PHYSICAL BASE ADDRESS
WORD PTT ;VIRTUAL ADDRESS OF PROTOCOL TYPE TABLE
WORD MTT ;VIRTUAL ADDRESS OF MULTICAST ADDRESS TABLE
WORD INT ;INTERRUPT LEVEL CONTROL BUFFER
WORD NON ;NON-INTERRUPT LEVEL CONTROL BUFFER
WORD LPT ;LOAD PTT TABLE BUFFER ADDRESS
WORD LMT ;LOAD MULTICAST ADDRESS TABLE BUFFER ADDRESS
WORD WSI ;WRITE STATION INFO BUFFER ADDRESS
WORD RSI ;READ STATION INFO BUFFER ADDRESS
WORD UNK,PT.LEN ;PSEUDO PTT FOR UNKNOWN PROTOCOL TYPE QUEUE
FIELD FLG,18 ;FLAGS WORD
BIT SLS ;1=LINE STATE NEEDS REPORTED
BIT WUL ;1=WAITING FOR UCODE TO BE LOADED
BIT STP ;1=WAITING FOR PORT RESTART
BIT BIG ;1=KNISTP BUGINF REPORTED
BIT LSI ;1=NEED TO WRITE STATION INFORMATION
BIT LMC ;1=NEED TO DO LOAD MULTICAST TABLE COMMAND
BIT LPP ;1=NEED TO DO LOAD PROTOCOL TABLE COMMAND
BIT VAD ; 1=PSHAD/LAD is valid
WORD STA ;LINE STATE
DEFSTR (PSRUN,$PSSTA,0,1) ; Channel is running, should be 1b0
DEFSTR (PSSST,$PSSTA,26,9) ; Channel substate
DEFSTR (PSEXS,$PSSTA,35,9) ; Channel external state
WORD HAD ;STORED HIGH ORDER STATION ADDRESS
WORD LAD ;STORED LOW ORDER STATION ADDRESS
WORD SAD,2 ;Shadowed address
WORD HRA ;STORED HIGH ORDER ROM ADDRESS
WORD LRA ;STORED LOW ORDER ROM ADDRESS
FIELD VAR,4 ;STORED VARIBLES
;--IMPORTANT-- THE FOLLOWING 4 BITS MUST BE IN SAME ORDER AS WSVAR
BIT CRC ;ALLOW RECEIPT OF FRAMES WITH CRC ERRORS
BIT PMC ;STATION IS IN PROMISCIOUS MULTICAST MODE
BIT H40 ;H4000 MODE IF 1
BIT PRM ;PROMISCIOUS MODE IF 1
FIELD SVA,4 ; Shadowed variables (what the port contains)
FIELD VBT,4 ; Valid bits in PSVAR (same order as PSVAR)
BIT VCR ; PSCRC is valid
BIT VPM ; PSPMC is valid
BIT VH4 ; PSH40 is valid
BIT VPR ; PSPRM is valid
FIELD RSP,8 ;MAXIMUM NUMBER OF ENTRIES ON THE RESPONSE QUE
FIELD CHN,4 ; Logical channel number
FIELD CBA,3 ; CBUS address
WORD CHK ; Check word, contains magic value
WORD TLR ; Time of last response
WORD CNO ; CONO KNI,(T1)
WORD CNI ; CONI KNI,T1
WORD DTO ; DATAO KNI,T1
WORD DTI ; DATAI KNI,T1
WORD CQA ; CONO KNI,CO.BTS+CO.CQA or NOP
WORD MXT ; # of Multicasts transmitted
HWORD UMA ; Major version #
HWORD UMI ; Minor version #
WORD UED ; Edit #
WORD TPC ;UDT OF PORT CRASH
WORD LAR ;LAR AT TIME OF UCODE CRASH
WORD CRL ;LEFT HAND CRAM BITS AT TIME OF CRASH
WORD CRR ;RIGHT HAND CRAM BITS AT TIME OF CRASH
WORD TLZ ;TIME AT WHICH PORT COUNTERS WERE ZEROED
WORD SHC ;ADDRESS OF SHADOW COUNTERS BLOCK
ENDSTR
SUBTTL QUEUE STRUCTURE DEFINITIONS
;SOFTWARE AND UCODE DEFINED.
BEGSTR QH ;QUEUE HEADER DEFINITION
WORD IWD ;INTERLOCK WORD
WORD FLI ;FORWARD LINK
WORD BLI ;BACKWARD LINK
WORD LEN ;LENGTH OF QUEUE ENTRIES
ENDSTR
BEGSTR QE ;QUEUE ENTRY
WORD FLI ;FORWARD LINK
WORD BLI ;BACKWARD LINK
WORD VIR ;VIRTUAL ADDRESS OF ENTRY
WORD OPC ;QUEUE ENTRY OPERATION CODE
ENDSTR
SUBTTL NI STATION INFO FORMAT
;WRITE STATION INFO FORMAT
BEGSTR WS,CM.LST
WORD HAD ;HIGH ORDER ETHERNET ADDRESS
WORD LAD ;LOW ORDER ETHERNET ADDRESS
FILLER 32 ;NOT USED
FIELD VAR,4 ;VARIBLES
BIT CRC ;ALLOW RECEIPT OF FRAMES WITH CRC ERRORS
BIT PMC ;PROMISCIOUS MULTICAST MODE
BIT H40 ;H4000 MODE
BIT PRM ;PROMISCIOUS MODE
NXTWRD
FILLER 24 ;NOT USED
FIELD RTY,12 ;ERROR RETRY VALUE
;**** ADDITIONS MAY BE ADDED HERE
HWORD FNC ;FUNCTION WHICH INVOKED THIS COMMAND
ENDSTR
;READ STATION INFORMATION FORMAT. UCODE DEFINED ONLY.
BEGSTR RS,CM.LST
WORD HAD ;HIGH ORDER ETHERNET ADDRESS
WORD LAD ;LOW ORDER ETHERNET ADDRESS
FILLER 32 ;NOT USED
FIELD VAR,4 ;VARIBLES
BIT NOP ;RECEIVE MOP MODE (UNUSED)
BIT PMC ;PROMISCIOUS MULTICAST MODE
BIT H40 ;H4000 MODE
BIT PRM ;PROMISCIOUS MODE
NXTWRD
FILLER 16 ;UNUSED
FIELD UCV,8 ;UCODE VERSION
FIELD NMC,6 ;NUMBER OF MULTICAST ADDRESSES ALLOWED
FIELD NPT,6 ;NUMBER OF PROTOCOL TYPES ALLOWED
ENDSTR
SUBTTL RECEIVE DATAGRAM DEFINITIONS
BEGSTR RD,CM.LST
FIELD SIZ,16,35 ; Text length + CRC (bytes)
WORD DA1,2 ; Let program align the bytes
WORD SA1,2
; FIELD DA1,32 ; High order destination address
; FIELD DA2,16,31 ; Low order destination address
; FIELD SA1,32 ; High order source address
; FIELD SA2,16,31 ; Low order source address
FIELD PTY,16,31 ; Protocol type
FIELD PBA,22,35 ; Physical address of receive buffer
; **** Additions may be added here
WORD VBA,2 ; Virtual address of receive buffer
WORD PID ; Portal ID
WORD RID ; Request ID
ENDSTR
;READ/READ CLEAR COUNTERS
BEGSTR C1,CM.LST
WORD RID ; Request ID
WORD PID ; Process ID
WORD BFA ; Buffer address
WORD SPI ; Secondary portal ID
FIELD ZRO,1 ; Indicates counters should be zeroed
HWORD FNC ; Function code
ENDSTR
; Structure for read counters block
BEGSTR RC
WORD BR ;BYTES RECEIVED
WORD BX ;BYTES TRANSMITTED
WORD FR ;FRAMES RECEIVED
WORD FX ;FRAMES TRANSMITTED
WORD MCB ;MULTICAST BYTES RECEIVED
WORD MCF ;MULTICAST FRAMES RECEIVED
WORD FXD ;FRAMES XMITTED, INITIALLY DEFERRED
WORD FXS ;FRAMES XMITTED, SINGLE COLLISION
WORD FXM ;FRAMES XMITTED, MULTIPLE COLLISIONS
WORD XF ;TRANSMIT FAILURES
WORD XFM ;TRANSMIT FAILURE BIT MASK
RCLOC==1B24 ; LOSS OF CARRIER
RCXBP==1B25 ; XMIT BUFFER PARITY ERROR
RCRFD==1B26 ; REMOTE FAILURE TO DEFER
RCXFL==1B27 ; XMITTED FRAME TOO LONG
RCOC==1B28 ; OPEN CIRCUIT
RCSC==1B29 ; SHORT CIRCUIT
RCCCF==1B30 ; COLLISION DETECT CHECK FAILED
RCEXC==1B31 ; EXCESSIVE COLLISIONS
WORD CDF ;CARRIER DETECT CHECK FAILED
WORD RF ;RECEIVE FAILURES
WORD RFM ;RECEIVE FAILURE BIT MASK
RCFLE==1B27 ; FREE LIST PARITY ERROR
RCNFB==1B28 ; NO FREE BUFFERS
RCFTL==1B29 ; FRAME TOO LONG
RCFER==1B30 ; FRAMING ERROR
RCBCE==1B31 ; BLOCK CHECK ERROR
WORD DUN ;DISCARDED UNKNOWN
WORD D01 ;DISCARDED POSITION 1
WORD D02 ;DISCARDED POSITION 2
WORD D03 ;DISCARDED POSITION 3
WORD D04 ;DISCARDED POSITION 4
WORD D05 ;DISCARDED POSITION 5
WORD D06 ;DISCARDED POSITION 6
WORD D07 ;DISCARDED POSITION 7
WORD D08 ;DISCARDED POSITION 8
WORD D09 ;DISCARDED POSITION 9
WORD D10 ;DISCARDED POSITION 10
WORD D11 ;DISCARDED POSITION 11
WORD D12 ;DISCARDED POSITION 12
WORD D13 ;DISCARDED POSITION 13
WORD D14 ;DISCARDED POSITION 14
WORD D15 ;DISCARDED POSITION 15
WORD D16 ;DISCARDED POSITION 16
WORD UFD ;UNRECOGNIZED FRAME DEST
WORD DOV ;DATA OVERRUN
WORD SBU ;SYSTEM BUFFER UNAVAILABLE
WORD UBU ;USER BUFFER UNAVAILABLE
WORD RS0 ;PLI REG RD PAR ERROR,,PLI PARITY ERROR
WORD RS1 ;MOVER PARITY ERROR,,CBUS PARITY ERROR
WORD RS2 ;EBUS PARITY ERROR,,EBUS QUE PARITY ERROR
WORD RS3 ;CHANNEL ERROR,,SPUR CHANNEL ERROR
WORD RS4 ;SPUR XMIT ATTN ERROR,,CBUS REQ TIMOUT ERROR
WORD RS5 ;EBUS REQ TIMEOUT ERROR,,CSR GRNT TIMEOUT ERROR
WORD RS6 ;USED BUFF PARITY ERROR,,XMIT BUFF PARITY ERROR
WORD RS7 ;RESERVED FOR UCODE
WORD RS8 ;RESERVED FOR UCODE
ENDSTR
;FLUSH COMMAND QUEUE DEFINITIONS
BEGSTR FL,CM.LST
WORD CHK ;CHECK WORD
WORD PID ;PORTAL ID
ENDSTR
SUBTTL MISC. DEFINITIONS
KNI==564 ;DEVICE CODE FOR KLNI
TIMOUT==^D5000 ;LOOP FOR INTERLOCK WAIT
ADRMSK==MASKB (0,13) ;ADDRESS MASK
NRETRY==20 ;NUMBER OF RETRYS
KNIRH2==5 ;NORMAL RH SLOT FOR KLNI
NPTT==^D16 ;NUMBER OF SUPPORTED PROTOCOL TYPES
; THIS WILL BE SUPPLIED BY THE MICROCODE LATER
NMTT==^D16 ;NUMBER OF SUPPORTED MULTICAST ADDRESSES
; THIS ALSO WILL BE SUPPLIED BY THE MICROCODE
NIPIA==DLSCHN ;PRIORITY INTERRUPT ASSIGNMENT FOR KLNI
KNICLK==^D5000 ;SECONDS FOR LOCAL TIMER
STSCLK==^D59 ;TIME FOR STATS
CHNLGO==KIEPT+KNIRH2*4 ;ADDRESS OF FIRST WORD OF KLNI CHANNEL LOGOUT
TIM==20 ;Timer device
OPDEF RDTIME [DATAI TIM,] ; Instruction for reading the time base
SUBTTL LOCAL STORAGE
RSI (CHNBAS,0) ;BASE OF CHANNEL BLOCK LIST
;**;[7134] Add NIHERE CEG 15-AUG-85
RS NIHERE,1 ;[7134] NI IN USE
RS (TIMCNT) ;COUNT FOR BROKEN KLIPA
RS (PRTSTG,PS.LST) ;PORT STORAGE
RS (PCBSTG,PB.LST) ;PCB
RS (CNTRL,UN.LEN*2+QE.LEN*2+WS.LST+RS.LST) ;CONTROL BUFFERS
RS (PTTADR,NPTT*PT.LST) ;PROTOCOL TYPE TABLE ADDRESS
RS (MCTADR,NMTT*MT.LST) ;MULTICAST TABLE ADDRESS
RS (MCTUSE,NMTT*MT.LST) ;MCAT USE TABLE (MUST FOLLOW
; MCTADR & BE SAME LENGTH)
RS (FRQADR,QH.LST*NPTT) ;FREE QUEUE HEADERS
RS (RCBADR,RC.LEN) ;READ COUNTERS BLOCK
RS (ENTINT,2) ;TIME AT WHICH WE ENTERED INTERRUPT LEVEL
RSI (TOTINT,<0,0>) ;TOTAL TIME SPENT AT INTERRUPT LEVEL
RSI (XRCQUE,0) ; Transmit/receive command core pool head
RSI (CORTIM,0) ; Time at which next CORCHK should occur
RS (JB0STF) ;Non-zero means run KNILDR under job 0
SUBTTL COMMAND QUEUE DISPATCH TABLE
CMDDSP: IFIW CLOSED ;FLUSH COMMANDS
IFIW DGSNT ;DATAGRAM SENT
IFIW LMCRES ;LOAD MULTICAST RESPONSE
IFIW LPTRES ;LOAD PROTOCOL TYPE RESPONSE
IFIW RCRES ;READ AND CLEAR COUNTERS RESPONSE
IFIW MSGAVA ;DGRCV RESPONSE
IFIW UNKRES ;WRITE PLI RESPONSE
IFIW UNKRES ;READ PLI RESPONSE
IFIW NSARD ;READ STATION REGISTER
IFIW WRTNSA ;WRITE STATION REGISTER
DSPEND==.-CMDDSP ;END OF DISPATCH TABLE
SUBTTL NIDSP - Primary interface between NISRV and PHYKNI
; Call: MOVX T1,NF.xyz ; Get function code
; MOVX UN,UN_block ; User's argument block
; MOVX PR,PR_block ; Portal data base
; CALL NIDSP
; <+1 with error code in T1>
; <+2 Success>
NIDSP: SAVEAC <PS,CM>
SKIPLE T1 ; Less than zero?
CAXLE T1,NF.MAX ; Or larger than the max?
BUG. (HLT,KNIBFC,PHYKNI,SOFT,<PHYKNI - Illegal NI function code>,<<T1,FUNC>>,<
Cause: NISRV called PHYKNI with a bad function code. The code is in T1.
Data: FUNC - Illegal function code
>)
MOVE T1,DSPTBL(T1) ; Get dispatch table entry
TXNE T1,NOCHAN ; Channel block required?
JRST (T1) ; Nope, skip the check
LOAD PS,PRCHN,(PR) ; Get channel block address
JUMPLE PS,NIDSP1 ; Jump if it's .LE. 0
OPSTR <CAME PS,>,PSCHK,(PS) ; Does the check word look Kosher?
NIDSP1: BUG. (HLT,KNIICA,PHYKNI,SOFT,<PHYKNI - Illegal channel block address>,<<PS,PS>,<PR,PR>>,<
Cause: The channel block address for this portal is invalid.
Data: PS - Bad channel block address
PR - Bad portal block address
>)
JRST (T1) ; Call the routine
NOCHAN==1B2 ; No channel block required
DSPTBL: TABBEG NF.ILL,NF.MAX,<FOO>
TABENT NF.ILL,<IFIW ILLFNC> ;ILLEGAL FUNCTION
TABENT NF.XMT,<IFIW NISND> ;TRANSMIT DATAGRAM
TABENT NF.RCV,<IFIW NISRB> ;SPECIFY RECEIVE BUFFER
TABENT NF.LSC,<IFIW ILLFNC> ;LINE STATE CHANGE
TABENT NF.RDC,<IFIW!NOCHAN!NIRDC> ;READ CHANNEL COUNTERS
TABENT NF.DPT,<IFIW NIDPT> ;DISABLE PROTOCOL TYPE
TABENT NF.EMA,<IFIW NISRA> ;ENABLE MULTICAST ADDRESS
TABENT NF.DMA,<IFIW NIDRA> ;DISABLE MULTICAST ADDRESS
TABENT NF.ASP,<IFIW!NOCHAN!ASGPRO> ;ASSIGN PROTOCOL
TABENT NF.RCI,<IFIW!NOCHAN!NIRCI> ;READ CHANNEL INFO
TABENT NF.CLO,<IFIW!NOCHAN!NICLO> ;CLOSE PORTAL (FLUSH COMMANDS)
TABENT NF.SCA,<IFIW!NOCHAN!NISCA> ;SET CHANNEL ADDRESS
TABENT NF.RPC,<IFIW!NOCHAN!NIRPC> ;READ PORTAL COUNTERS
TABENT NF.SCS,<IFIW!NOCHAN!NISCS> ;SET CHANNEL STATE
TABENT NF.RPI,<IFIW!NIRPI> ;READ PORTAL INFO
TABEND
SUBTTL INITIALIZE THE KLNI PORT
;+
; THIS ROUTINE IS CALLED AT SYSTEM STARTUP AND ONLY AT SYSTEM STARTUP
; TO GET THE KLNI GOING.
;
; CALL NIINI ;PORT IS ON RH#5
; P1 = CDB ADDRESS
;
; RETURN +1: ALWAYS
;
;-
IFN FTHINI,RESCD
NIINI:
IFN FTHINI,<
JRST @[NIINI1] ; Make the big leap
XRESCD ; Change PSECTs
NIINI1:
>
; Check for a KLIPA in slot 5
CONI KNI,T1 ; Read the CSR
JE CI.PPT,T1,RTN ; Just return if not a KLIPA
; Create a CDB so that diagnostics will work
;**;[7134] Add 1 line CEG 15-AUG-85
SETOM NIHERE ;[7134] WE HAVE AN NI
SAVEAC <P1,P2,P3>
MOVX T1,CDBLEN ; Get length of CDB
CALL PHYALC ; Allocate some storage
RET ; Failure, quit initialization
MOVEI P1,-CDBINT(T1) ; CDB base address to P1
MOVX T1,5 ; Get actual channel address
MOVEM P1,CHNTAB(T1) ; Save CDB in channel table
HRRZM T1,CDBADR(P1) ; Store CHNTAB index
EXCH P1,P3 ; Get CDB in P3
MOVEI T1,.BTCDB ; Mark as CDB
DPB T1,USYBKT ; ...
EXCH P1,P3 ; Restore
MOVEI T1,.CTNI ; Set type
DPB T1,CSYTYP ; as NI
MOVX T1,CS.NIP ; This is an
IORM T1,CDBSTS(P1) ; NI channel
MOVX T1,KIEPT+0+5*4 ; Address of channel ICP area
; = ept+ICP offset+(rh slot #*logout len)
MOVEM T1,CDBICP(P1) ; Stash in CDB
MOVEI T1,KNIDSP ; Get bogus dispatch table address
MOVEM T1,CDBDSP(P1) ; Setup dispatch table address
MOVEI T1,CDBUDB(P1) ; Get start of UDB table
MOVEM T1,CDBIUN(P1) ; Setup bogus AOBJN word for unit table
MOVX T1,5 ; Get CBUS channel number 5
CALL KLIINI ; Initialize it
NOP ; Just ignore failure return for now
RET
RESCD ; Dispatch table must live in section 0/1
; Bogus dispatch vector for NI channel
KNIDSP::JRST NIINI ;0 - INITIALIZATION
JRST DSPBUG ;1 - STACK SECOND CHANNEL COMMAND
JRST DSPBUG ;2 - START I/O
JRST DSPBUG ;3 - POSITION REQUEST
JRST DSPBUG ;4 - RETURN BEST XFER
JRST DSPBUG ;5 - INTERRUPT PROCESSING
JRST DSPBUG ;6 - MAKE CHANNEL XFER WORD
JRST DSPBUG ;7 - TRANSFER HUNG
JRST KNIRSC ;10 - RESET CHANNEL
RET ;11 - PERIODIC CHECK
JRST DSPBUG ;12 - CHECK UNIT EXISTANCE
JRST DSPBUG ;13 - EXTRACT ADDRESS FROM CCW WORD
DSPBUG: BUG. (HLT,KNIIPF,PHYKNI,SOFT,<PHYKNI - Illegal channel dispatch>,,<
Cause: The KLNI driver was called to perform a PHYSIO function it is not
capable of doing.
>)
RET
XRESCD ; Put us back in section 6
SUBTTL KLIINI - Initialize a KLNI the first time
; Initialize a specified KLNI channel. Create the all the databases and
; start the channel.
;
; Call: MOVX T1,CBUS channel #
; CALL KLIINI
; <+1 Return for failure>
; <+2 Success>
;
KLIINI: SAVEAC <PS,CM,UN,P1,P2,P3>
SKIPA PS,CHNBAS ; Get base of channel list
KLIIN1: LOAD PS,PSNXT,(PS) ; Get next channel block
JUMPE PS,KLIIN2 ; No such channel
OPSTR <CAMN T1,>,PSCBA,(PS) ; Does the CBUS address match?
JRST NIINIA ; Yes, just init the channel
JRST KLIIN1 ; Loop over all channels
; Here to create a PS block for this channel and fill it in with constants
KLIIN2: MOVE P1,T1 ; Save the CBUS channel #
XMOVEI PS,PRTSTG ; For now just use pre-allocated blocks
; Now setup all the constants
STOR PS,PSCHK,(PS) ; Set up the check word
STOR P1,PSCBA,(PS) ; Save the CBUS address
MOVE T1,P1 ; Get CBUS address
LSH T1,^D26 ; Move it into device code field
MOVX T2,<CONO RH0,(T1)> ; Get standard CONO for CBUS addr # 0
ADD T2,T1 ; Compute the CONO for this KLNI
STOR T2,PSCNO,(PS) ; Save it away
MOVX T2,<CONI RH0,T1> ; Get standard CONI for CBUS addr # 0
ADD T2,T1 ; Compute the CONI for this KLNI
STOR T2,PSCNI,(PS) ; Save it away
MOVX T2,<DATAO RH0,T1> ; Get standard DATAO for CBUS addr # 0
ADD T2,T1 ; Compute DATAO for this KLNI
STOR T2,PSDTO,(PS) ; Save it away
MOVX T2,<DATAI RH0,T1> ; Get standard DATAI for CBUS addr # 0
ADD T2,T1 ; Compute DATAI for this KLNI
STOR T2,PSDTI,(PS) ; Save it away
MOVX T2,<NOP> ; Get a no-op
STOR T2,PSCQA,(PS) ; Save that as the command initiator
SETZRO PSFLG,(PS) ; Clear all the flags
MOVEI T1,UNS.VG ; The channel is now in a virginal state
CALL SETSTA ; Tell the others about it
XMOVEI P2,PCBSTG ; PCB address
STOR P2,PSPCB,(PS) ; Save the PCB address in KLNI storage
MAP T1,(P2) ; Convert to physical address
TXZ T1,ADRMSK ; Clear junk
STOR T1,PBPBA,(P2) ; Save the PCB base physical address
STOR T1,PSPBA,(PS) ; Save it in the channel block also
MOVEI T2,NIPIA ; Get PI assignment
STOR T2,PBPIA,(P2) ; Save the PIA
MOVE T1,P1 ; Get CBUS address
LSH T1,2 ; Multiply it by 4
ADDI T1,KIEPT+1 ; Compute address of channel logout area
MAP T1,(T1) ; Make it physical
TXZ T1,ADRMSK ; Clear junk bits
STOR T1,PBLAD,(P2) ; Tell the port about it
;...
;...
XMOVEI T1,CNTRL ; Control buffers address
STOR T1,PSINT,(PS) ; Save interrupt level buffer
ADDI T1,UN.LEN ; Advance to the next buffer
STOR T1,PSNON,(PS) ; Save it
ADDI T1,UN.LEN ; And the last, 3 buffers in all
STOR T1,PSLPT,(PS) ; Save protocol type command buffer address
ADDI T1,QE.LEN ; Advance to next
STOR T1,PSLMT,(PS) ; And the multicast address command buffer
ADDI T1,QE.LEN ; Advance to next
STOR T1,PSWSI,(PS) ; Save the write station info command buffer
ADDI T1,WS.LST ; Advance to next
STOR T1,PSRSI,(PS) ; Save the read station info command buffer
CALL PCBINI ; Initialize the PCB and queue headers
MOVX T1,<.RESP1,,RC.LEN> ; Allocate resident memory for
MOVX T2,.RESGP ; counters shadow block
CALL ASGRES ; Get the memory
JRST NIINI9 ; Couldn't get it...
STOR T1,PSSHC,(PS) ; Setup pointer to shadow counters
MOVE T1,CHNBAS ; Get base of channel list
STOR T1,PSNXT,(PS) ; Make current block point to 1st on chain
MOVEM PS,CHNBAS ; Make current block be the first
CALL STRLD ; Initiate a reload
RETSKP
NIINIA: MOVE T1,CHNTAB+5 ; Get our CDB address
MOVX T2,CS.MAI ; Get the maint mode bit
ANDCAM T2,CDBSTS(T1) ; Clear the maintenance mode bit
MOVX T1,UNS.IN ; New state is "initializing"
CALL SETSTA ; Set the state
CALL ZERSHD ; Zero the shadow counters
CALL INICOM ; Setup the initial KLNI commands
JRST NIINI9 ;
CALL ENBKLP ; Enable the KLNI
JRST NIINI9 ; Reset line state and exit
RETSKP ; And return success
NIINI9: CALL NISTP ; Stop the port
MOVEI T1,UNS.BK ; Set state to broken
CALLRET SETSTA ; Tell users about it
SUBTTL KNIRSC - Reset all channels
; Expects nothing
; CALL KNIRSC
; <+1 Return only>
IFN FTHINI, RESCD
KNIRSC:
IFN FTHINI,<
JRST @[KNIRS1]
XRESCD
KNIRS1:
>
SKIPN CHNBAS ; Any channels initialized
RET ; No
SAVEAC <PS>
CALL ALLCHN ; Co-routine to loop through all channels
CALL NISTP ; Stop this channel
CALLRET STRLD ; and request that KNILDR reload it
SUBTTL SETSTA - Set channel state
; Expects PS to be setup.
;
; Call: MOVX T1,new-state
; CALL SETSTA
; <+1 Return only>
SETSTA: MOVE T1,STAMAP-UNS.VG(T1) ; Get new state word
OPSTR <CAMN T1,>,PSSTA,(PS) ; Is the state changing???
RET ; Nope, don't bother anybody
STOR T1,PSSTA,(PS) ; Yes, save it
OPSTR <SKIPN UN,>,PSNON,(PS) ; Get control buffer
RET ; Can't report state
LOAD T1,PSCHN,(PS) ; Get the channel number
STOR T1,UNCHN,(UN) ; Stuff it in the UN block
MOVEI T1,NF.LSC ; Function to dll (LINE STATE CHANGE)
CALLRET DLLCBK ; Send it
;Table for mapping between substate and state word
DEFINE XX (state)<
IFE state-UNS.RN,<UNRUN+FLD(state,UNEXS)+FLD(.-STAMAP+UNS.VG,UNSST)>
IFN state-UNS.RN,<FLD(state,UNEXS)+FLD(.-STAMAP+UNS.VG,UNSST)>>
STAMAP: TABBEG UNS.VG,UNS.MX,FOO
TABENT UNS.VG,XX UNS.OF ; Virgin
TABENT UNS.RE,XX UNS.RN ; Reload
TABENT UNS.CR,XX UNS.OF ; Can't Reload
TABENT UNS.IN,XX UNS.RN ; Init
TABENT UNS.RN,XX UNS.RN ; Run
TABENT UNS.DP,XX UNS.RN ; Dump
TABENT UNS.DR,XX UNS.RN ; Dump & Reload
TABENT UNS.BK,XX UNS.OF ; Broken
TABENT UNS.OF,XX UNS.OF ; Off
TABENT UNS.RR,0 ; Request Reload - impossible
TABEND
SUBTTL KNISV - Unvectored interrupt service for KLNI's
;
; This routine is called from STG when an unvectored interrupt on the KLNI
; channel occurs. If there are no interrupt bits set, we just return so that
; other devices on this level can be serviced. Otherwise, go into the real
; interrupt handler for the KLNI.
;
IFN FTHINI,RESCD
KNISV:: RDTIME ENTINT ; Remember when we entered this interrupt level
EA.ENT ; Must run extended
IFN FTHINI,<
JRST @[KNISV2] ; Jump to the skyseg
XRESCD ; Change PSECTs
KNISV2:
>
MOVX T2,CHNBAS-$PSNXT ; Get base of channel tables
KNISV1: OPSTR <SKIPN T2,>,PSNXT,(T2) ; Get address of next channel block
RET ; Return if no more channels to check
OPSTR <XCT>,PSCNI,(T2) ; Read KLNI status
TXNN T1,CI.INT!CI.ERR ; Any reason for interrupt?
JRST KNISV1 ; Nope, check next KLNI
CALL INTPRO ; Go process interrupt
NOP ; In case of skips
DMOVE T1,ENTINT ; Get the time at which we entered
RDTIME ENTINT ; Get current runtime
DSUB T1,ENTINT ; Compute neg amount of time we spent here
DMOVN T1,T1 ; Make it positive
DADD T1,TOTINT ; Accumulate total time spent here
DMOVEM T1,TOTINT ; Put it in the right place
UNBRK KNI ; Dismiss the interrupt
repeat 0,<
BUG. (HLT,KNIUEI,PHYKNI,HARD,<PHYKNI - Unexpected interrupt>,<<T1,CONI>,<T2,CDBSTS>>,<
Cause: The KLNI has interrupted the processor, however the monitor does not
beleive that there is a KLNI in this channel slot. Since the monitor
determined that this is NOT a KLNI (at system startup time via
KNITST), this interrupt should NOT have happened.
Action: Call field service.
Data: CONI - CONI KNI,...
CDBSTS - Contents of CDBSTS word of channel data block.
>)
> ; End of repeat 0
SUBTTL INTPRO - Determine what caused the interrupt, and handle it
; Call: T1/ CONI bits
; T2/ channel block address
; CALL INTPRO
; <+1 Return - Ignore>
; <+2 Return>
INTPRO: SAVEAC <P1,PS,PR,CM,UN>
MOVE PS,T2 ; Setup pointer to port storage
TXNE T1,CI.ERR ; MBUS or parity error?
JRST KNIERR ; Yes, do special handling
TXNN T1,CI.FQE ; Free queue error?
IFSKP.
MOVE T2,T1 ; Save CONI bits for a minute
MOVX T1,CI.FQE+CO.BTS ; Get bits for CONO
OPSTR <XCT>,PSCNO,(PS); Clear the condition
SKIPE NIBUGX ; Skip this if we aren't interested
BUG. (INF,KNIFQE,PHYKNI,SOFT,<PHYKNI - Free Queue Error>,,<
Cause: The KLNI received a packet for a protocol, and there were no free
packets available for that protocol type.
Action: Determine which protocol type ran out of packets, and fix the driver
for that protocol type.
>)
TXNN T2,CI.RQA ; Is there anything on the response queue?
RET ; No, just return
ENDIF.
MOVX T1,CI.RQA+CO.BTS ;Get bits for CONO
OPSTR <XCT>,PSCNO,(PS) ;Clear "response queue available"
; Here to process the response queue. Note that since we may come through
; here during error recovery, CONO's or CONI's to the KLNI should not be
; done after this point.
INTRQA: STKVAR <RSPCNT> ;Temp storage for count of entrys on queue
SETZM RSPCNT ;Zero it
LOAD T1,PSPCB,(PS) ;Get virtual address of the PCB
XMOVEI T1,PB.RQI+QH.IWD(T1) ;Get response queue header interlock addr
LOAD P1,PSPBA,(PS) ;Get physical address of the PCB
ADDX P1,PB.RQI+QH.FLI ;Compute phys addr of resp Q flink
MOVE T3,P1 ;Get another copy of the address
; No need for NIOFF/NION because we only come here at interrupt level, or
; when device is not running.
NIINT2: OPSTR <AOSN T2,>,QHIWD,(T1) ;Wait for interlock
JRST NIINT3 ; Got it
CAXG T2,TIMOUT ;Waited long enough?
JRST NIINT2 ;No, try again
BUG. (CHK,KNIRIT,PHYKNI,SOFT,<PHYKNI - Response queue interlock timed out>,,<
Cause: PHYKNI did not succeed in getting the response queue interlock after
5000. tries.
>,RTN)
NIINT3: MOVE T2,P1 ;Save physical q-header address for a moment
OPSTR <EXCH P1,>,QHFLI,(T1) ;Get forward link, make q's point to itself
OPSTR <EXCH T3,>,QHBLI,(T1) ;Do same to backward link
SETONE QHIWD,(T1) ;Release the interlock
CAMN P1,T2 ;Does the q-header point to itself
JRST QEMPTY ; Yes, shouldn't have gotten here...
MOVE T2,T3 ;Get address of last item on the queue
SETZ T3, ;Get a zero
CALL PMOVEM ;Make last entry on queue point to 0
NIINT5: MOVE T2,P1 ;Get physical address of q-entry
ADDI T2,QE.VIR ;Compute phys addr of virt addr of q-entry
CALL PMOVE ;Fetch virtual address of this q-entry
MOVE CM,T2 ;CM <= virtual address of q-entry
IFN FTHIST,<
CALL RECCMB ;Record the contents of the command block
>; End of FTHIST
LOAD P1,CMFLI,(CM) ;Get pointer to next entry
AOS RSPCNT ;Count one more
LOAD T1,CMERR,(CM) ;Get the error code
LOAD T4,CMOPC,(CM) ;Get the command opcode
CAXL T4,DSPEND ;Legal opcode ??
JRST UNKRES ; BUG. if not
SKIPE T1 ;Got an error?
CALL RSPERR ; Yes, process the error
STOR T1,CMERC,(CM) ;Save the error code
SKIPL T1 ;Skip this if command was aborted
CALL @CMDDSP(T4) ;Call the routine for completion
NOP
JUMPN P1,NIINT5 ;Process the next response if ptr non-zero
MOVE T1,RSPCNT ;Get the current count
OPSTR <CAMLE T1,>,PSRSP,(PS) ;Current greater than max ?
STOR T1,PSRSP,(PS) ; Yes, make it the new max
RET ;And return from the interrupt
ENDSV.
SUBTTL RSPERR Handle errors generated by a response
; This routine will process an error detected in a response. The error
; will be dispatched to a command specific routine, and then validated.
; An error code will be returned in T1.
EC.VXM==1B0 ; This error is valid for transmit
EC.VRC==1B1 ; This error is valid for receive
EC.VCL==1B2 ; This error is valid for close
DEFINE XX(code,arg)<TABENT code,<IFIW!arg>>
ERRDSP: TABBEG 0,37,IFIW!ILLERR
XX NI.EXC,XMTERR ; Excessive collisions
XX NI.CCF,XMTERR ; Carrier check failed
XX NI.CDF,XMTERR ; Collision detect check failed
;**; [7174] Change 1 line at ERRDSP:+3 HMP 28-Oct-85
XX NI.FTL,XRERR ; [7174 Frame too long
XX NI.RFD,XMTERR ; Remote failure to defer
XX NI.BCE,RCVERR ; Block check error (CRC error)
XX NI.FER,RCVERR ; Framing error
XX NI.DOV,RCVERR ; Data overrun
XX NI.FTS,XMTERR ; Frame too short
XX NI.QLV,RCVERR ; Queue length violation
XX NI.URC,CLOERR ; Unrecognized command
XX NI.BLV,BLVERR ; Buffer length violation
TABEND
RSPERR: LSH T1,-1 ; Right justify the error code
JRST @ERRDSP(T1) ; Process the error
; Here for errors which can only be caused by a transmit
XMTERR: CAIE T4,OP.SND ; Is it a transmit?
JRST ILLERR ; Nope, die
CAIN T1,NI.EXC ; Excessive collisions?
JRST EXCERR ; Yes, go handle it
CAIN T1,NI.CCF ; Carrier check failed?
JRST CCFERR ; Yes, go handle it
CAIN T1,NI.CDF ; Collision detect failed?
JRST CDFERR ; Yes, go handle collision detect failure
;**; [7174] Remove 2 lines after XMTERR:+7 HMP 22-Oct-85
CAIN T1,NI.RFD ; Remote failure to defer?
JRST RFDERR ; Yes, handle it
CAIN T1,NI.FTS ; Frame too short?
JRST FTSERR ; Yes, handle it
JRST ILLERR ; None of the above, die
; Here for errors that can occur during a receive
RCVERR: CAIE T4,OP.RCV ; Is this a receive?
JRST ILLERR ; Nope, die
CAIN T1,NI.BCE ; Block check error?
JRST ILLERR ; Yes, go handle it
CAIN T1,NI.FER ; Framing error?
JRST ILLERR ; Yes, process the framing error
CAIN T1,NI.DOV ; Data overrun?
JRST DOVERR ; Yes, process it
CAIN T1,NI.QLV ; Queue length violation?
JRST QLVERR ; Yes, process it
JRST ILLERR ; Didn't find it, die
; Here for errors that can occur during transmit or receive
;**; [7174] Add 3 lines after RCVERR:+10 HMP 28-Oct-85
XRERR: CAIN T1,NI.FTL ; [7174] Frame too long?
JRST FTLERR ; [7174] Yes, go process the error
JRST ILLERR ; [7174] No, thats all we expect, so die
; Here on errors that can occur during a close
CLOERR: CAIE T4,OP.FLS ; Is this a flush?
JRST ILLERR ; Nope, die
CAIN T1,NI.URC ; Unrecognised command?
JRST URCERR ; Yes, go process it
JRST ILLERR
; Here when we get an unrecognised command during a close
URCCOD==1234 ; Magic code that tells CLOSED that we got here
URCERR: MOVX T1,URCCOD ; Get the magic code
RET
; Here when we get a buffer length violation. This happens when the BSD chain
; contains inconsistent length information with respect to the command block
; or the free queue.
BLVERR: BUG. (HLT,KNIBLV,PHYKNI,SOFT,<PHYKNI - Buffer length violation>,,<
Cause: The BSD chain contained inconsistent length information for
the transmit or receive command that caused it.
>)
ILLERR: BUG. (HLT,KNIIEC,PHYKNI,HARD,<PHYKNI - Illegal port error code>,<<T1,CODE>,<T4,CMD>>,<
Cause: The port generated a response which contained:
a. An unknown error code
b. An inappropriate error code for the command
Data: CODE - Error Code
CMD- Command
>)
SUBTTL Transmit errors
; Here for excessive collisions
EXCERR: MOVX T1,UNEXC% ; Get error code
RET ; And pass it on
CCFERR: LOAD T1,CMTDR,(CM) ; Get the TDR value
BUG. (INF,KNICCF,PHYKNI,HARD,<PHYKNI - Carrier check failed>,<<T1,TDR>>,<
Cause: The NIA module did not detect it's own carrier while it was
transmitting.
Action: Make sure that both ends of the transceiver cable are securely
fastened. Also check Ethernet cable to see if it is properly
terminated.
Data: TDR - TDR value
>)
MOVX T1,UNCCF% ; Get the error code
RET
; Here on Collision Detect Check failures
CDFERR: BUG. (CHK,KNICDF,PHYKNI,HARD,<PHYKNI - Collision detect check failed>,,<
Cause: The H4000 did not assert the collision detect signal shortly after
completion of a transmission. (This signal is also known as the
"Heartbeat" of the H4000).
Action: Check the transceiver cable and make sure both ends are securely
fastened (to the H4000 and the NIA box). Check the H4000.
>)
SETZ T1, ; Indicate successful transmission
RET
; Here when we get a frame too long error
FTLERR: BUG. (CHK,KNIFTL,PHYKNI,HARD,<PHYKNI - Frame too long>,,<
Cause: The NIA module detected that it was transmitting a frame longer
than 1536. bytes.
Action: Check the NIA module.
>)
SETZ T1, ; Just return success
RET
; Here when a remote station fails to defer to us (ie: a late collision).
RFDERR: LOAD T1,CMTDR,(CM) ; Get the TDR
BUG. (INF,KNIRFD,PHYKNI,HARD,<PHYKNI - Remote failure to defer>,<<T1,TDR>>,<
Cause: A collision was detected after the NIA had "acquired" control of the
Ethernet cable. This is also known as a "late collision".
A collision may only occur during the transmission of the preamble
of a frame. This problem occurs when the collision is detected
after the preamble has been transmitted.
Action: Check the Ethernet cable. The maximum distance between any two
stations on the cable may not exceed 1500. meters. A longer cable
may result in late collisions of this sort. This problem may also
be caused by a malfunctioning Ethernet station. Check the other
Ethernet stations on the cable to see if they are having similar
problems.
Data: TDR - TDR value
>)
MOVX T1,UNRFD% ; Get error code for Remote Failure to Defer
RET
; Here when we attempt to transmit a frame with less than 46. bytes of data
; and we didn't specify padding.
FTSERR: BUG. (HLT,KNIFTS,PHYKNI,SOFT,<PHYKNI - Frame too short>,,<
Cause: The port was told to transmit a frame with less than 46. bytes of
user data and the pad flag (CMPAD) was not set. This should have
been detected by NISND.
>)
SUBTTL Here to handle receive errors
; Here when we get a NIA receive buffer overrun
DOVERR: BUG. (CHK,KNIDOV,PHYKNI,HARD,<PHYKNI - NIA buffer overrun>,,<
Cause: The NIA module did not have enough free space to store an
incoming datagram.
>)
LOAD PR,RDPID,(CM) ; Get the portal ID
LOAD T1,PRFQA,(PR) ; Get PTT entry address
LOAD T1,PTVIR,(T1) ; Get virt address of free queue header
CALL PUTQUE ; Put this buffer back on the free list
SETO T1, ; Indicate to NIINT that command has been
; blown away
RET
; Here when the datagram won't fit into the user's buffer
QLVERR: MOVX T1,UNRDL% ; Get code for Received Datagram too Long
LOAD PR,RDPID,(CM) ; Get the portal block
JE PRPAD,(PR),RTN ; Just return if not padding
MOVX T1,UNLER% ; Make it a Length Error if padding
RET
SUBTTL KNIERR Handle KLNI hardware errors
; Here when any CONI error bits are set. If we got a KLIPA CRAM parity
; error, see what the PC is. If the PC is between MINCPE and MAXCPE inclusive
; we have a planned CRAM parity error (ie: a ucode stopcode). Otherwise we
; have an uplanned CRAM parity error which is a CRAM hardware problem. If
; we get an EBUS parity error, Data Mover parity error, or an MBUS error,
; we just log the problem, and don't do any more analysis.
KNIERR: SAVEAC P1
MOVE P1,T1 ; Save original CONI
PUSH P,P1 ; Save P1 for a moment
TXNE P1,CI.RQA ; Response queue available?
CALL INTRQA ; Yes, clean up the response queue
POP P,P1 ; Restore P1
CALL NISTP ; Prevent the port from being restarted
CALL LGTAD ; Read the time and date
STOR T1,PSTPC,(PS) ; Save it for posterity
CALL RDLAR ; Read the LAR (PC at this point)
SETO T1, ; Port still running!?!? Use a funny PC...
STOR T1,PSLAR,(PS) ; Save the CRAM address
TXNN P1,CI.CPE ; CRAM parity error?
JRST HRDERR ; No, treat MBUS, EBUS, DATA MVR errors special
CAXL T1,MINCPE ; Before the first planned CRAM parity error?
JRST KNIPPE ; No, must be a micro-stopcode
; Here on an unplanned CRAM parity error
PARERR: SAVEAC P2
MOVE P2,T1 ; Save the PC
CALL RDCRAM ; Read the CRAM location
SETO T1, ; !?! Port running!?!
STOR T1,PSCRL,(PS) ; Save the MSB in the PSB
STOR T2,PSCRR,(PS) ; Save the LSB in the PSB
BUG. (CHK,KNIPER,PHYKNI,HARD,<PHYKNI - CRAM parity error>,<<P1,CONI>,<P2,ADDR>,<T1,LOCMSB>,<T2,LOCLSB>>,<
Cause: The KLNI has detected a parity error in it's Control RAM. This is
a hardware problem.
Action: Reload the ucode. If the problem persists call field service.
Data: CONI - CONI
ADDR - Address of parity error
LOCMSB & LOCLSB - Contents of memory location
>)
CALL STRLD ; Set state to RELOAD and start KNILDR
CALLRET LOGERR ; Log the problem and return
HRDERR: BUG. (CHK,KNIHED,PHYKNI,HARD,<PHYKNI - Hard error detected>,<<P1,CONI>,<T1,PC>>,<
Cause: MBUS ERROR, or EBUS PARITY ERROR was detected. This is a KLNI
hardware problem. The address (ADDR) and it's contents (LOCMSB
and LOCLSB) are printed out.
Action: Call field service.
Data: CONI - CONI KNI,
PC - PC (Microcode PC at time of problem)
>)
MOVX T1,UNS.BK ; Port is now busted
CALL SETSTA ; Tell everyone
CALLRET LOGERR ; Log the error and return
SUBTTL Planned CRAM Parity Errors
; We come here when the KLNI gets a CRAM parity error whose address is between
; MINCPE and MAXCPE (inclusive). In this case, the address is a special code
; which indicates a unique problem with the KLNI. This is rather analogous
; to a stopcode or BUGHLT for the KLNI microcode.
KNIPPE: LOAD T3,PSCBA,(PS) ; Get CBUS address
LSH T3,2 ; * 4 (length of channel logout area
DMOVE T3,KIEPT+1(T3) ; Get channel logout words 1&2
CALL @DIETAB-MINCPE(T1) ; Dispatch to the appropriate routine
CALL LOGERR ; Go log the problem
CALLRET STDUMP ; And dump the KLNI
DIETAB: TABBEG MINCPE,MAXCPE,FOO
TABENT 7750,<IFIW DIEIPE> ; INTERNAL.ERROR
TABENT 7751,<IFIW DIEFST> ; FAIL.SELF_TEST
TABENT 7752,<IFIW DIEEPE> ; FAIL.EBUS
TABENT 7753,<IFIW DIEEPE> ; FAIL.EBUS.QUE
TABENT 7754,<IFIW DIEPIE> ; FAIL.PLIPE
TABENT 7755,<IFIW DIECPE> ; FAIL.CBUSPE
TABENT 7756,<IFIW DIEDPE> ; FAIL.PAR_PRE
TABENT 7757,<IFIW DIECAE> ; FAIL.CBUS.AVAIL
TABENT 7760,<IFIW DIEERE> ; FAIL.EBUSRQ
TABENT 7761,<IFIW DIEGCE> ; FAIL.GRANT.CSR
TABENT 7762,<IFIW DIESWC> ; FAIL.CHANNEL
TABENT 7763,<IFIW DIESCE> ; SPUR.CHAN.ERR
TABENT 7764,<IFIW DIESTA> ; FAIL.XMT.ATTN
TABENT 7765,<IFIW DIEUBE> ; USED.BUFF.PE
TABENT 7766,<IFIW DIEFBE> ; FREE.BUFFER.PE
TABENT 7767,<IFIW DIEXPE> ; XMIT.BUFFER.PE
TABENT 7770,<IFIW DIEUPE> ; ERR020
TABENT 7771,<IFIW DIEUPE> ; ERR021
TABENT 7772,<IFIW DIEUPE> ; ERR022
TABENT 7773,<IFIW DIEUPE> ; ERR023
TABENT 7774,<IFIW DIEUPE> ; ERR024
TABENT 7775,<IFIW DIEUPE> ; ERR025
TABENT 7776,<IFIW PARERR> ; Regular CRAM parity error
TABENT 7777,<IFIW DIEUPE> ; ERR026
TABEND
SUBTTL Individual Planned CRAM Parity Errors
DIEUPE: BUG. (INF,KNIUPE,PHYKNI,HARD,<PHYKNI - NIA20 unknown planned CRAM parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 got a CRAM parity error in the range of 7750 to 7777. This
particular error falls into this range, but is not known to TOPS-20.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEIPE: BUG. (INF,KNIIPE,PHYKNI,HARD,<PHYKNI - Internal port error>,<<P1,CSR>,<P2,VERSION>,<T1,ADDR>>,<
Cause: The NIA20 detected an inconsistency with an operation it was
performing. The inconsistency can be caused by any number of things,
but the end result is that the function did not occur correctly or was
not logical.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
VERSION - Version number of the NIA20 microcode
ADDR - Address of parity error
>)
RET
DIEFST: BUG. (INF,KNIFST,PHYKNI,HARD,<PHYKNI - Failed self test>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: When the NIA20 is idle it performs a self test to check out various
pieces of logic (such as the ALU, the microsequencer, and the data
mover/formatter). It also performs a self test when it is first
started. In one of those cases, the self test failed.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEEPE: BUG. (INF,KNIEPE,PHYKNI,HARD,<PHYKNI - EBUS parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 received a word with bad parity from the EBUS.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEPIE: BUG. (INF,KNIPIE,PHYKNI,HARD,<PHYKNI - PLI parity error>,,<
Cause: More than five parity errors occurred when reading data over the PLI
interface.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
>)
RET
DIECPE: BUG. (INF,KNICPE,PHYKNI,HARD,<PHYKNI - CBUS parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 detected bad parity for data that was read over the CBUS.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEDPE: BUG. (INF,KNIDPE,PHYKNI,HARD,<PHYKNI - NIA20 data path error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The threshold (5) for data mover parity errors was exceeded.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIECAE: BUG. (INF,KNICAE,PHYKNI,HARD,<PHYKNI - CBUS available timeout>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 was unable to acquire control of the CBUS within 50
microseconds from the start of a CBUS request.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEERE: BUG. (INF,KNIERE,PHYKNI,HARD,<PHYKNI - EBUS request timeout>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 was unable to get control of the EBUS within 20 milliseconds
after making a PI request.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEGCE: BUG. (INF,KNIGCE,PHYKNI,HARD,<PHYKNI - Grant CSR timeout>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA20 was unable to acquire control of the CSR (CONI word) within
10 milliseconds after requesting it.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIESWC: BUG. (INF,KNISWC,PHYKNI,HARD,<PHYKNI - Channel short word count>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: When the NIA20 completed a CBUS transfer, the channel had a short word
count error.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIESCE: BUG. (INF,KNISCE,PHYKNI,HARD,<PHYKNI - Spurious channel error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: A spurious channel error occurs whenever the channel raises the error
signal, but no error bits are present in the channel logout area. This
error occurs after the threshold (5) of spurious channel errors has
been exceeded.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIESTA: BUG. (INF,KNISTA,PHYKNI,HARD,<PHYKNI - NIA20 spurious transmit attention>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA module set the PLI transmit attention bit, but there was no
transmit pending according to the microcode.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEUBE: BUG. (INF,KNIUBE,PHYKNI,HARD,<PHYKNI - NIA20 used buffer list parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The port received a PLI parity error while reading the NIA module's
user buffer list. This error is only reported after a threshold (5)
for this type of error has been exceeded.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEFBE: BUG. (INF,KNIFBE,PHYKNI,HARD,<PHYKNI - NIA20 free buffer list parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA receive status indicated that there was a free buffer list
parity error.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
DIEXPE: BUG. (INF,KNIXPE,PHYKNI,HARD,<PHYKNI - NIA20 transmit buffer parity error>,<<P1,CSR>,<T1,ADDR>,<T3,LOGOU1>,<T4,LOGOU2>>,<
Cause: The NIA transmit status indicated a transmit buffer parity error. This
error is not reported until a threshold (5) of this type of error has
been exceeded.
The NIA20 will be dumped and restarted by KNILDR.
Action: Contact Field Service.
Data: CSR - CONI KNI,
ADDR - Address of parity error
LOGOU1 - Channel logout word 1
LOGOU2 - Channel logout word 2
>)
RET
SUBTTL PERIODIC CHECKS
IFN FTHINI,RESCD
KNICHK::EA.ENT
IFN FTHINI,<
JRST @[KNICH2] ; Jump to the skyseg
XRESCD ; Change PSECTs
KNICH2:
>
SAVEPQ ; Save some ACs
MOVEI T1,KNICLK ; Get timer value
MOVEM T1,KNITIM ; Reset the timer
MOVE T1,TODCLK ; Get current time
CAML T1,CORTIM ; Is it time to check for stale blocks?
CALL CORCHK ; Yes, release the stale blocks
SKIPN CHNBAS ; Get base of channel blocks
JRST LNGTIM ; No channels, sleep for a long time
CALL ALLCHN ; The following code must run for all channels
; See if the channel is in the RUN state. If so, do normal timer stuff, if
; not, just ignore it.
LOAD T1,PSSST,(PS) ; Get the channel's internal state
CAXE T1,UNS.RN ; Are we running?
RET ; Nope, just quit
CALL NIRSI ; Give the KLNI something to do
TRNA ; Hmmm, command still pending, kill the KLNI
RET ; Everything's fine, just return
; There has been an outstanding read station info command for longer than
; the timeout period. BUGCHK and return.
OPSTR <XCT>,PSCNI,(PS) ; Read the status
MOVE P1,T1 ; Put it in a safe place
CALL NISTP ; Stop the channel gracefully
CALL RDLAR ; Read the LAR
SETO T1, ; Port is still running! Use a funny PC...
BUG. (CHK,KNISTP,PHYKNI,SOFT,<PHYKNI - KLNI stopped>,<<P1,CONI>,<T1,LAR>>,<
Cause: No response from KLNI after 5 seconds.
Data: CONI - CONI KNI,
LAR - Latched Address Register
>)
CALLRET STDUMP ; Take a dump and restart the channel
; Here when no KLNI's are present. Sleep for a long time
LNGTIM: HRLOI T1,377777 ; Get the largest positive integer
MOVEM T1,KNITIM ; Save it in the clock table
RET ; ...
SUBTTL Good Stuff - KLNI dump and reload logic description
comment ~
The primary philosophy behind this code is that the KLNI may be dumped or
reloaded in two different ways. The first way is manually, by someone
explicitly running KNILDR. The second way is automatically, by getting the
monitor to run the appropriate program.
There are two goals to this design.
1) Keep the monitor code as simple as possible.
2) Put as much brains as possible into KNILDR.
A monitor initiated dump/reload works as follows:
1) Some routine decides that the KLNI needs to be dumped/reloaded.
2) This routine calls STDUMP or STRLD depending upon the type of service
desired.
3) STDUMP puts sets the channel state to "DUMP". Goto step 5.
4) STRLD puts sets the channel state to "RELOAD".
5) Job 0 is told to run KNILDR.
6) Sometime later... KNILDR actually runs. It scans through all the available
channels examining their channel states. If a channel's state is not "DUMP"
or "RELOAD", it is ignored. The following steps are executed for each
channel in the DUMP or RELOAD state:
a) The channel is stopped by setting it's state to DUMP or RELOAD.
b) The channel is dumped or reloaded by doing I/O instructions.
c) The channel is restarted by setting it's state to RUN.
A user initiated dump/reload must follow these steps:
1) The channel is stopped by setting it's state to DUMP or RELOAD (whichever is
appropriate).
2) The channel is dumped or reloaded by doing I/O instructions.
3) The channel is restarted by setting it's state to RUN.
Notice the similarity between these steps, and steps 6abc in preceding section.
This is intentional. Both the monitor and the program will always exhibit
similar behavior independant of where the dump or reload request came from.
~
SUBTTL KNIJB0 - Run KNILDR if necessary
; Here to startup job 0. May be called at any time.
STDUMP: SKIPA T1,[UNS.DP] ; Here to start a KLNI dump
STRLD: MOVX T1,UNS.RE ; Here to start a KLNI reload
CALL SETSTA ; Set the new state
MOVE T1,TODCLK ; Get current time
STOR T1,PSTLR,(PS) ; Start timing KNILDR
AOS JB0STF ; Set our flag
AOS JB0FLG ; Tell the monitor to run job 0
RET ; All done
SWAPCD ; This should be swappable
; Here whenever job 0 runs. See if somebody requested that KNILDR be run.
; If so, run it and wait for completion. Otherwise, quit immedaitely.
KNIJB0::SKIPN JB0STF ; Do we have anything to do??
RET ; Nope, quit while we're ahead
IFN FTHINI,<
JRST @[KNIJBH] ; Yes, enter the skyseg
XSWAPCD ; This should be swappable
KNIJBH:
>
SETZM JB0STF ; Yes, say that we've been here...
; Here when dumping/reloading the KLNI. Run a job 0 fork with KNILDR in it.
MOVX T2,OWGP. (7,XADDR.([ASCIZ /SYSTEM:KNILDR.EXE/]))
MOVX T1,<GJ%SHT+GJ%OLD> ; Use short form GTJFN, file must exist
MOVEI T3,1 ; Use CCL entry point
SETZ T4, ; Don't care about fork number
CALLX (MSEC1,RUNDII) ; Run the program to completion
IFNSK.
BUG. (CHK,KNICFF,PHYKNI,SOFT,<PHYKNI - Cannot reload the KLNI>,<<T1,ERROR>>,<
Cause: The monitor was unable to find SYSTEM:KNILDR.EXE when it attempted to
reload or dump the port.
Action: Make sure that KNILDR.EXE is installed in SYSTEM:.
Data: ERROR - Error code from RUNDII (Probably a JSYS error).
>)
CALL ALLCHN ; Loop through all channels
LOAD T1,PSSST,(PS) ; Get the substate
CAIE T1,UNS.DP ; Dump?
CAIN T1,UNS.RE ; Or Reload?
JRST KNIJB1 ; Yes, funeral for a KLNI
CAIE T1,UNS.DR ; Dump/Reload?
RET ; Nope, just ignore the KLNI
KNIJB1: MOVX T1,UNS.CR ; Get new state - Can't reload
CALLRET SETSTA ; Tell everyone about it
ENDIF.
; Here after the successful completion of KNILDR
CALL ALLCHN ; Check the status of all channels
LOAD T1,PSSST,(PS) ; Get the substate
CAXN T1,UNS.RN ; Is the KLNI now running?
RET ; Yes, all done!
BUG. (CHK,KNIRLF,PHYKNI,SOFT,<PHYKNI - KLNI Reload Failed>,<<T1,STATE>>,<
Cause: KNILDR ran, but failed to reload the KLNI for some reason.
Data: STATE - State of the KLNI
>)
JRST KNIJB1 ; Put KLNI into a terminal state
IFE FTHINI,<
RESCD>
IFN FTHINI,<
XRESCD> ; Put us in the skyseg
SUBTTL READ/WRITE CRAM
;ROUTINE TO READ MICROCODE VERSION NUMBER
;CALL: CALL RDVER ; NO ARGUMENTS
; <+1 COULDN'T READ VERSION BECAUSE UCODE WAS RUNNING>
; <+2 Major version # in T1, minor version # in T2, edit # in T3>
;
RDVER: SAVEAC P1
MOVX T1,MICVER ; Read the version word
CALL RDCRAM ; Read it
RET ; Can't read CRAM while port is running...
MOVE P1,T1 ; Save the version # for a moment
MOVX T1,MICEDT ; Read the edit word
CALL RDCRAM ; Read it
RET ; ...
LOAD T3,UCEDT,T1 ; Isolate the edit #
LOAD T1,UCMAJ,P1 ; Isolate major version number
LOAD T2,UCMIN,P1 ; Isolate the minor version number
RETSKP ; And return success
;ROUTINE TO READ THE LAR (LATCHED ADDRESS REGISTER).
;CALL: CALL RDLAR ; NO ARGUMENTS
; <+1 COULDN'T READ LAR BECAUSE UCODE WAS RUNNING>
; <+2 LAR IN T1>
;
;ONLY USES T1
RDLAR: OPSTR <XCT>,PSCNI,(PS) ;READ THE CSR
TXNE T1,CO.MRN ;IS THE PORT RUNNING?
RET ; YES, QUIT NOW
TLZ T1,-1 ;PREVENT FURTHER INDIRECTION
PUSH P,T1 ;SAVE IT FOR A MINUTE
MOVX T1,CO.LAR ;GET BITS FOR CONI
OPSTR <XCT>,PSCNO,(PS) ;TELL PORT WE WANT TO READ IT'S LAR
DATAI KNI,T1 ;READ THE LAR
LOAD T2,MICPC,T1 ;RIGHT JUSTIFY ADDR
POP P,T1 ;RESTORE ORIGINAL CONI BITS
OPSTR <XCT>,PSCNO,(PS) ;RESTORE THE STATUS
MOVE T1,T2 ;GET LAR INTO RIGHT PLACE
RETSKP ;AND RETURN SUCCESS
;ROUTINE TO READ A CRAM LOCATION
;CALL: MOVx T1,cram-address
; CALL RDCRAM
; <+1 COULDN'T READ CRAM BECAUSE UCODE WAS RUNNING>
; <+2 T1 6-35 CONTAINS CRAM MSB'S, T2 6-35 CONTAINS CRAM LSB'S>
RDCRAM: MOVE T2,T1 ;SAVE ADDRESS FOR A MOMENT
OPSTR <XCT>,PSCNI,(PS) ;GET STATUS
TXNE T1,CO.MRN ;IS THE PORT RUNNING?
RET ; YES, QUIT NOW
TLZ T1,-1 ;CLEAR THE LEFT HALF TO PREVENT INDIRECTION
PUSH P,T1 ;SAVE IT FOR A MINUTE
SETZ T1, ;SETUP BITS FOR CONO
OPSTR <XCT>,PSCNO,(PS) ;CLEAR CO.LAR
STOR T2,MICPC,T2 ;PUT THE PC IN THE RIGHT PLACE
TXO T2,DO.LRA!1B13 ;SET UP TO READ THE MSB'S
DATAO KNI,T2 ;TELL THE HARDWARE ABOUT IT
DATAI KNI,T1 ;GET CONTENTS OF HIGH ORDER PART OF CRAM
TXZ T1,77B5 ;CLEAR OUT 0-5 SINCE THEY ARE MEANINGLESS
TXZ T2,1B13 ;SET UP TO READ THE LSB'S
DATAO KNI,T2 ;TELL THE HARDWARE ABOUT IT
DATAI KNI,T2 ;GET CONTENTS OF LOW ORDER PART OF CRAM
TXZ T2,77B5 ;CLEAR OUT 0-5 SINCE THEY ARE MEANINGLESS
MOVE T3,T1 ;SAVE T1 FOR A MOMENT
POP P,T1 ;RESTORE CONI BITS
OPSTR <XCT>,PSCNO,(PS) ;RESTORE STATUS
MOVE T1,T3 ;FIX T1
RETSKP
SUBTTL SEND DATAGRAM
;+
; THIS ROUTINE IS DISPATCHED TO THROUGH THE DLL DISPATCH TABLE.
; SEE NIDSP FOR REGISTER USAGE.
;
;-
NISND: TRVAR <TXTSIZ,NBSDS>
JE UNBSZ,(UN),NISNDA ; Jump if MSD style buffer(s)
CALL NISND5 ; Do non-MSD style xmit
JRST NISND8 ; Error return, free up CM block
JRST NISND9 ; All is well, proceed normally
; MSD style sends come here
NISNDA: CALL CNTFRG ; Count number of BSD's needed
RET ; Pass the error upwards
SETZ CM, ; Clear CM for error recovery
CALL BLDBSD ; Build the BSD's
JRST NISND8 ; Give bad return
;
; NON-MSD CODE REJOINS HERE
;
NISND9: CALL SETSND ; Setup the send datagram command entry
JRST NISND8 ; Got an error, clean un and return
CALL QUECMD ; Queue the command and exit
INCR PROXM,(PR) ; Update the outstanding xmit count
IFN NICSW,<
AOS IS.IEN
>
RETSKP ; Give good return
NISND8: JUMPE CM,RTN ;Just return if no CM block
EXCH CM,T1 ;Save error code for a moment, get command addr
CALL RXRCOR ;Release the command
MOVE T1,CM ;Get the error code back
RET ;And return
SUBTTL Byte pointer evaluation tables
BEGSTR BY ; Byte pointer info
FIELD OFF,1 ; Offset of 0 or 1
FIELD CHK,2 ; How to check this byte pointer's size
FIELD LSH,6 ; LSH factor for word alignment
FIELD NUM,3 ; Number of bytes remaining in word
ENDSTR
; Values for BYCHK
.BYILL==0 ; This byte pointer is illegal
.BYOK==1 ; This byte pointer is OK
.BYCSZ==2 ; Check the size manually
DEFINE X(pfield,check<3>)
<..Y==0 ;;Initial word offset of 0
..P==pfield ;;Initial position
IFL pfield-10,<..Y==1 ;;Next word
..P==^D36> ;;All 36 bits
<..Y>B0+<check>B2+<^D36-..P>B8+<..P/8>B11+pfield
>
DEFINE XX(size)
<..P==^D36
REPEAT ^D36/size+1,<
IFN size-10,FLD(.BYILL,BYCHK)
IFE size-10,<X(..P,.BYOK)
..P==..P-size>
>
>
PFIELD==0
BYTAB:
REPEAT 45,<
X(PFIELD,.BYCSZ)
PFIELD==PFIELD+1
>
XX(6)
XX(8)
XX(7)
XX(9)
XX(^D18)
XX(^D37)
; Non-MSD style send. Send data pointed at by UNBFA. This takes care of
; byte alignment, page boundaries, etc...
NISND5: SAVEAC <P1,P2>
MOVEI T1,3*BD.LST+SB.LST; Get core for BSD for non-MSD send
SETZ CM, ; Clear CM in case of allocation failure
CALL GXRCOR ; Allocate it
ERROR UNRES% ; No resources
MOVE CM,T1 ; Set up KLNI command pointer
XMOVEI P1,SB.LST(CM) ; Point to first BSD
MAP T1,(P1) ; Make allocated address physical
TXZ T1,ADRMSK ; Clear junk bits
STOR T1,SBBBA,(CM) ; Save as BSD base address for KLNI
OPSTR <DMOVE T1,>,UNBFA,(UN) ; Get byte pointer to buffer
OPSTR <DMOVEM T1,>,SBBFA,(CM) ; Save it for callback
LOAD T4,UNBSZ,(UN) ; Get the data length
LDB T2,[POINT 6,T1,5] ; Get it's P field
MOVE P2,BYTAB(T2) ; Get the byte pointer descriptor
LOAD T3,BYCHK,+P2 ; Get the size checking field
JRST @.+1(T3) ; Dispatch to the correct checking routine
IFIW ERET (UNIBP%) ; .BYILL - Illegal buffer pointer
IFIW NISND7 ; .BYOK - Size is OK
IFIW NISND6 ; .BYCHK - Check the size manually
IFIW KNIBT1 ; Bad BYTAB entry
; Manually check byte size, indexing or indirection, and extract E field
NISND6: LDB T3,[POINT 6,T1,11] ; Get the S field from the byte pointer
CAIE T3,8 ; 8 bit bytes?
ERROR UNIBP% ; Illegal byte size
; If T1 contains one-word byte pointer, set IFIW to fool next chunk of code.
; If T1 contains a two-word byte pointer, get second word (which is an
; indirect word of some sort).
TXNN T1,1B12 ; Two word byte pointer?
TXOA T1,<IFIW> ; No, make it look like local format indirect
LOAD T1,UNBFA,+1(UN) ; Yes, get 2nd word
; T1 now contains an indirect word. If extended format indirect and no
; indexing/indirection, we are done.
TXCN T1,77B5 ; IFIW=0 & I=0 & X=0 ???
JRST NISND7 ; Yes, global addr, proceed
; T1 contains indirect word (IFIW complemented). If complemented IFIW and
; no indexing/indirection, we are ok.
TXNE T1,<IFIW @(17)> ; Indexing or indirection?
ERROR UNIBP% ; Yes to either, no good
; Here for one-word globals, byte size is ok.
TLZA T1,-1 ; Through here for local indirect words
NISND7: TXZ T1,77B5 ; Remove all but Y field
TXNE P2,BYOFF ; Does the address need to be incremented?
ADDI T1,1 ; Yes, point to next word
LOAD T3,BYLSH,+P2 ; Get the shift factor
JUMPE T3,NISND3 ; Jump if word aligned
; Here when transmitting non-word aligned data. Fetch the first word and
; word align it. Save it in the BSD. Adjust the total length to account
; for the bytes we just took care of.
OPSTR <MAP T2,>,BDRES,(P1) ; Get addr of reserved word of BSD
STOR T2,BDSBA,(P1) ; Save that as the segment address
LOAD T2,UNADS,(UN) ; Get address space
XCT [MOVE T2,(T1) ; UNA.EV - Get word from Exec virtual
XCTU [MOVE T2,(T1)] ; UNA.UV - Get word from User virtual
JRST VMCBUG](T2) ; UNA.PH - Get word from physical
LSH T2,(T3) ; Word align the first word
STOR T2,BDRES,(P1) ; Put the data into the BSD
ADDI T1,1 ; Increment the data address
LOAD T2,BYNUM,+P2 ; Get number of bytes we just took care of
SUB T4,T2 ; Compute number remaining
STOR T2,BDSLN,(P1) ; Save length in the BSD (possibly wrong)
MAP T3,BD.LST(P1) ; Get physical address of next BSD
TXZ T3,ADRMSK ; Clear the junk bits
STOR T3,BDNXA,(P1) ; Point to next BSD
XMOVEI P1,BD.LST(P1) ; Point to next BSD
JUMPG T4,NISND3 ; Jump if no more to do
; The first word of data was the only word of data. Correct the BSD length
; and zap pointer to next BSD and finish up.
ADD T4,T2 ; T4 now contains correct BSD length
STOR T4,BDSLN,-BD.LST(P1) ; Install it
SETZRO BDNXA,-BD.LST(P1) ; Clear pointer to next BSD
JRST NISND2 ; We are all done
; At this point T1 points to word aligned data. T4 is the length in bytes.
; P1 points to a new BSD. For the moment, assume that buffer does not
; cross a page boundary.
NISND3: STOR T1,BDRES,(P1) ; Save virtual address of buffer
LOAD T2,UNADS,(UN) ; Get address space <<< (Match angle brackets)
XCT [MAP T2,(T1) ; UNA.EV - Exec virtual => physical
XCTU [MAP T2,(T1)] ; UNA.UV - User virtual => physical
TRN](T2) ; UNA.PH - physical => physical
; Make sure the page is locked down
LOAD T3,PHCPNO,+T2 ; Get just the page #
MOVE T3,@CST1X+T3 ; Get the lock status of this page
TXNN T3,<-PLKV> ; Is the page locked down?
ERROR UNIFB% ; Nope, bad buffer
STOR T2,BDSBA,(P1) ; Save the physical address of the data
STOR T4,BDSLN,(P1) ; Save the data length
MOVE T1,P1 ; Get address of BSD
LOAD T2,UNADS,(UN) ; Get address space descriptor
CALL FIXBSD ; Account for virtual page boundaries and such
RET ; Pass the error upwards
; Here after building BSD chain.
NISND2: SETZRO SBMSD,(CM) ; Make sure MSD is zero
LOAD T1,UNBSZ,(UN) ; Get the data length
STOR T1,SNTXL,(CM) ; Save text length
RETSKP ; And return success
SUBTTL Count MSD's
;
;This routine calculates how many BSD's will be needed to transmit
;an MSD style message.
;
CNTFRG: SETZM NBSDS ; Where total number of BSD's goes
SETZM TXTSIZ ; Total number of bytes for all MSD's
OPSTR <SKIPA T2,>,UNBFA,(UN) ; Get the address of the buffer
CNTFR1: LOAD T2,MDNXT,(T2) ; Get the next MSD if any
JUMPE T2,RSKP ; Return if we're all done
LOAD T1,MDBYT,(T2) ; Get the byte count
JUMPE T1,CNTFR1 ; Skip this MSD if it's empty
ADDM T1,TXTSIZ ; Add it in
MOVEI T1,2 ; Allocate 2 BSD's in case buffer crosses
ADDM T1,NBSDS ; non-physically contiguous page boundary
LDB T1,[POINT 6,$MDAUX(T2),5] ; Get the P field from this byte pointer
MOVE T1,BYTAB(T1) ; Get descriptor for this P field
TXNE T1,BYLSH ; Is the LSH factor non-zero?
AOS NBSDS ; Increment again if not word aligned
JRST CNTFR1 ; Loop back for rest of MSD's
SUBTTL BUILD BSD'S
;+
; THIS ROUTINE WILL ALLOCATE AND BUILD BSD FOR A SEND DATAGRAM FOR MSD STYLE
; BUFFERS.
;
; CALL WITH:
; NBSDS = NUMBER OF BSDS NEEDED
;
; RETURNS +1: ERROR
; +2: BSD'S BUILT
;-
BLDBSD: SAVEAC <P1,P2,P3>
STKVAR <BYTES>
MOVE T1,NBSDS ;GET NUMBER OF BSDS NEEDED
IMULI T1,BD.LST ;NUMBER OF FRAGMENTS*BSD LENGTH
ADDI T1,SB.LST ;PLUS ENTRY SIZE
CALL GXRCOR ;TRY TO ALLOCATE IT
RET ;NOT ENOUGH LEFT
MOVE CM,T1 ;Make CM point to command block
MOVE T2,TXTSIZ ;GET TOTAL TEXT SIZE
STOR T2,SNTXL,(CM) ;SAVE IT
XMOVEI P1,SB.LST(CM) ;Point to BSD start
MAP T1,(P1) ;MAKE IT PHYSICAL
TXZ T1,ADRMSK ;CLEAR JUNK
STOR T1,SBBBA,(CM) ;SAVE THE BSD BASE ADDRESS
LOAD P3,UNBFA,(UN) ;GET TOP MSD ADDRESS
STOR P3,SBMSD,(CM) ;SAVE MSD ADDRESS
SETZRO SBBFA,(CM) ;MAKE SURE NONMSD BUFFER IS ZERO
BLDBS1: LOAD T1,MDBYT,(P3) ;Get the byte count
JUMPE T1,BLDBS6 ;Skip this MSD if it is blank
STOR T1,BDSLN,(P1) ;Save it
SETZRO BDPAC,(P1) ;Packing mode is always zero
LOAD T1,MDAUX,(P3) ;Get the byte pointer
LDB P2,[POINT 6,T1,5] ;Get it's P field
MOVE P2,BYTAB(P2) ;Load up the descriptor for this P
LOAD T2,BYCHK,+P2 ;See what type of checking we have to do
JRST @.+1(T2) ;Dispatch based on type of check
IFIW RTN ;.BYILL - Illegal byte size, non-skip return
IFIW BLDBS3 ;.BYOK - Byte size is fine, proceed normally
IFIW BLDBS2 ;.BYCSZ - Check the size manually
IFIW KNIBT1 ;Illegal BYTAB entry
KNIBT1: BUG. (HLT,KNIBTB,PHYKNI,SOFT,<PHYKNI - Bad BYTAB entry>,<<P2,ENTRY>,<T1,BYTPTR>>,<
Cause: BYTAB has been corrupted.
Data: ENTRY - The corrupted entry
BYTPTR - The byte pointer used to fetch this entry.
>,RTN)
;Here when byte pointer is not one word global. Check byte size manually
BLDBS2: LDB T2,[POINT 6,T1,11] ;Get the S field
CAIE T2,8 ;8 bit bytes?
RET ; Nope, illegal byte size, non-skip return
BLDBS3: HRRZ T2,T1 ;Get Y field from byte pointer
OPSTR <ADD T2,>,MDALA,(P3) ;Point to data
TXNE P2,BYOFF ;Do we need to increment the address?
ADDI T2,1 ; Yes, an IBP would cross a word boundary
TXNE P2,BYLSH ;Do we need to move some bytes around???
JRST BLDBS4 ; Yes, do special stuff
;Here when we have word aligned data. This is the simplest case.
STOR T2,BDRES,(P1) ;Save virtual address of the data
LOAD T1,MDVMC,(P3) ;Get address space <<< (Match angle brackets)
XCT [MAP T2,(T2) ;Exec virtual => physical
XCTUU [MAP T2,(T2)];User virtual => physical
NOP](T1) ;Physical => physical
STOR T2,BDSBA,(P1) ;Save the segment address - physical
MOVE T1,P1 ;Get address of BSD
LOAD T2,MDVMC,(P3) ;Get the address space descriptor
CALL FIXBSD ;Correct for page boundarys
RET ; Pass the error upwards
MOVE P1,T1 ;Update BSD pointer
;See if any more MSD's. If so, set up next BSD and start over.
BLDBS5: LOAD P3,MDNXT,(P3) ;Get next segment address
JUMPE P3,RSKP ;Jump if all done
MAP T1,BD.LST(P1) ;Get physical address of next BSD
TXZ T1,ADRMSK ;Clear junk
STOR T1,BDNXA,(P1) ;Save as next BSD
XMOVEI P1,BD.LST(P1) ;Point to next BSD
JRST BLDBS1 ;Do next
;Here when skipping zero length MSD's
BLDBS6: LOAD P3,MDNXT,(P3) ;Get next segment address
JUMPN P3,BLDBS1 ;Jump if more to look at
RETSKP
;Here when bytes are not word aligned.
;Build a seperate BSD for the first word's worth of bytes. Left justify the
;bytes and stuff them into the reserved word of the BSD. If there are any
;bytes left over, build another BSD for the rest of them (only one more BSD
;is required at this point because the succeeding words will all contain left
;justified bytes).
BLDBS4: OPSTR <MAP T1,>,BDRES,(P1) ;Get phys addr of reserved word of BSD
STOR T1,BDSBA,(P1) ;Save that as the data segment address
LOAD T1,MDVMC,(P3) ;Get the address space
XCT [MOVE T1,(T2) ;Get 1st word from exec virtual
XCTU [MOVE T1,(T2)];Get 1st word from user virtual
JRST VMCBUG](T1) ;Get 1st word from physical... too hard for now
LOAD T3,BYLSH,+P2 ;Get the LSH factor
LSH T1,(T3) ;Left justify the bytes
STOR T1,BDRES,(P1) ;Put them into the BSD
LOAD T1,BYNUM,+P2 ;Get the potential number of bytes remaining
LOAD T3,MDBYT,(P3) ;Get actual number of bytes remaining
CAIL T1,(T3) ;Did this BSD satisfy this MSD?
JRST BLDBS5 ; Yes, we are all done
;At this point, we are building the second BSD for the word aligned bytes
;of this MSD.
STOR T1,BDSLN,(P1) ;No, save the actual segment size
SUB T3,T1 ;T3 = # of bytes remaining in this MSD
MAP T1,BD.LST(P1) ;Get physical address of next BSD
STOR T1,BDNXA,(P1) ;Save pointer to next BSD
XMOVEI P1,BD.LST(P1) ;Point to next BSD
STOR T3,BDSLN,(P1) ;Save length of this segment
STOR T2,BDRES,(P1) ;Save virtual buffer address
LOAD T1,MDVMC,(P3) ;Get address space <<< (Match angle brackets)
XCT [MAP T1,1(T2) ;Exec virtual => physical
XCTUU [MAP T1,1(T2)];User virtual => physical
ADDI T1,1](T1) ;Physical => physical
STOR T1,BDSBA,(P1) ;Save it
SETZRO BDPAC,(P1) ;Always use packing mode of 0
MOVE T1,P1 ;Get address of BSD
LOAD T2,MDVMC,(P3) ;Get address space descriptor
CALL FIXBSD ;Check for physical contiguity of buffer
RET ; Pass error upwards
MOVE P1,T1 ;Update BSD pointer
JRST BLDBS5 ;All done!
SUBTTL FIXBSD Correct buffer for physical contituity
; FIXBSD will see if the addressed BSD points to non-physically contiguous
; memory. If it does, then:
; 1) The BSD is shortened down to the page boundary
; 2) A new BSD is created which will handle all the bytes beyond the
; page boundary.
; 3) The BSD's are linked together.
; 4) The new BSD is returned in T1.
;
; This routine expects that BDSLN and BDSBA are set up as per the hardware
; description. BDRES should contain the 30 bit virtual address of the
; first word of the buffer. BDNXA may be destroyed.
;
; Call: MOVX T1,BSD-address
; MOVX T2,address-space-descriptor
; CALL FIXBSD
; <Return +1, error code in T1>
; <Return +2, success, (possible) new BSD address in T1>
;See if buffer segment crosses a page boundary
FIXBSD: SAVEAC <P1,P2> ; Use P1 as BSD pointer
DMOVE P1,T1 ; Make P1 point to BSD, P2 contains ASD
LOAD T1,BDSLN,(P1) ; Get the length of the buffer (in bytes)
MOVEI T1,3-4(T1) ; +3 to round up to word boundary, -4 to
; subtract one word
LSH T1,-2 ; Convert it to words
OPSTR <ADD T1,>,BDRES,(P1) ; Compute last word of buffer
MOVE T2,T1 ; Save virtual end of buffer for a moment
OPSTR <XOR T1,>,BDRES,(P1) ; Generate bit mask of differences
TXNN T1,VPGNO ; Page numbers the same?
JRST FIXBS1 ; Yes, return success
;Buffer segment crosses a page boundary. See if pages are physically
; contiguous.
; Generate physical end of buffer <<< (M.A.B.)
XCT [MAP T1,(T2) ; Exec virtual => physical
XCTU [MAP T1,(T2)]; User virtual => physical
NOP](P2) ; Physical => physical
TXZ T1,ADRMSK!777 ; Clear junk bits from last page
LOAD T2,BDSBA,(P1) ; Get physical address of start of buffer
SUB T1,T2 ; See how many pages we span
SKIPL T1 ; Skip if pages not consecutive
CAXLE T1,PGSIZ ; Skip if pages are consecutive
TRNA ; Pages aren't consecutive
JRST FIXBS1 ; Physically contiguous, all done!
;Buffer occupies non-physically contiguous memory.
ADD T1,T2 ; Restore end address
STOR T1,BDSBA,+BD.LST(P1); Save segment address in next BSD
MOVN T1,T2 ; T1(27-35) contains # words to page boundary
ANDI T1,777 ; T1 now has # words in 1st BSD
LSH T1,2 ; Convert to bytes
LOAD T2,BDSLN,(P1) ; Get total buffer length
STOR T1,BDSLN,(P1) ; Setup new BSD length
SUB T2,T1 ; Compute amount remaining for second BSD
STOR T2,BDSLN,+BD.LST(P1) ; Install final BSD's length
MAP T1,BD.LST(P1) ; Get physical address of next BSD
TXZ T1,ADRMSK ; Clear out junk bits
STOR T1,BDNXA,(P1) ; Make current BSD point to next BSD
XMOVEI P1,BD.LST(P1) ; Make P1 point to new BSD
SETZRO BDPAC,(P1) ; Always use industry compatible packing mode
; Here on good return
FIXBS1: MOVE T1,P1 ; Make T1 point to last BSD
RETSKP ; And return success
SUBTTL SETUP SEND DATAGRAM ENTRY
;+
; THIS ROUTINE SETS UP ALL COMMON FIELDS FOR A SEND DATAGRAM BOTH BSD
; AND NON-BSD.
;
; CALL WITH:
; CM/ Address of command block
; UN/ ADDRESS OF NIDLL TO PORT DRIVER INTERFACE BLOCK
;
; RETURNS +1: ALWAYS
;-
SETSND: LOAD T1,PRPAD,(PR) ; Get the pad flag
LOAD T2,SNTXL,(CM) ; Get the size
CAMGE T2,[DEC 46 ; Less than the minimum?
DEC 0](T1) ;
ERROR UNIBS% ; Yes, Illegal Buffer Size
CAMLE T2,[DEC 1500 ; Greater than the max?
DEC 1498](T1)
ERROR UNIBS% ; No, Illegal Buffer Size
MOVEI T1,OP.SND ; Opcode for send datagram
STOR T1,CMOPC,(CM) ; Save it
CALL FETADR ; Fetch address from UN block
TXNE T1,1B7 ; Transmitting a multicast address?
OPSTRM <AOS>,PSMXT,(PS); Yes, count it
STOR T1,SNHAD,(CM) ; Store the high order address
STOR T2,SNLAD,(CM) ; Store the low order address
LOAD T1,PRPRO,(PR) ; Get protocol type
STOR T1,SNPTY,(CM) ; Store protocol type
SETONE CMBSD,(CM) ; Set BSD format
STOR PR,SBPID,(CM) ; Store the portal ID
LOAD T1,UNRID,(UN) ; Get the request ID
STOR T1,SBRID,(CM) ; Save that with this command
LOAD T1,PRPAD,(PR) ; Get the PAD bit
STOR T1,CMPAD,(CM) ; Tell the KLNI about it
RETSKP ; Return to caller
ENDSV.
ENDTV.
;table to convert P,S field of OWGBP to P or S
;access table using the structures, OWGSZ & OWGPS, with index = P,S field
;or the routines GETSIZ & GETPOS
OWGBTB: 6,,44
6,,36
6,,30
6,,22
6,,14
6,,6
6,,0
10,,44
10,,34
10,,24
10,,14
10,,4
7,,44
7,,35
7,,26
7,,17
7,,10
7,,1
11,,44
11,,33
11,,22
11,,11
11,,0
22,,44
22,,22
22,,0
77,,77 ;illegal
DEFSTR OWGSZ,OWGBTB-^O45,17,18 ;size field
DEFSTR OWGPS,OWGBTB-^O45,35,18 ;position field
;get size field from a byte pointer, global or local
;CALL GETSIZ
;T1/ byte pointer
;returns +1 on with T1/ size
;preserves all other ACs
GETSIZ: SAVEAC P1
MOVE P1,T1 ;save pointer
LDB T1,[POINT 6,T1,5]
CAIGE T1,45 ;OWGBP ?
IFSKP.
LOAD T1,OWGSZ,(T1) ;yes. convert.
ELSE.
LDB T1,[POINT 6,P1,11] ;no. get size field
ENDIF.
RET
;get position field from a byte pointer, global or local
;CALL GETPOS
;T1/ byte pointer
;returns +1 with T1/ position
;preserves all other ACs
GETPOS: LDB T1,[POINT 6,T1,5]
CAIL T1,45 ;OWGBP ?
LOAD T1,OWGPS,(T1) ;yes. convert.
RET
;Get the Y field from the byte pointer pointed at by T1. This routine handles
;all cases (ie: one word locals, one word globals, two word globals).
IFN FTHINI,RESCD
BP2ADR::LDB T3,[POINT 6,T1,5] ; Get the byte pointer's P field
CAILE T3,44 ; One word global?
JRST GETBPO ; Yes, handle it differently
TXNE T1,1B12 ; Two word byte pointer?
JRST GET2WG ; Yes, another special case
TLZ T1,-1 ; One word local, 18 bit Y field
RET ; All done
GET2WG: LDB T1,[POINT 30,T2,35] ; Extract 30 bit address
TXNE T2,<IFIW> ; Extended format address?
TLZ T1,-1 ; No, use 18 bit Y field
RET
GETBPO: TXZ T1,77B5 ; Zero out the P field
RET ; And return
IFN FTHINI,XRESCD
SUBTTL SPECIFY RECEIVE BUFFER
;+
; THIS ROUTINE IS DISPATCHED TO THROUGH THE DLL DISPATCH TABLE TO ADD
; A BUFFER TO THE LIST FOR RECEIVES.
;
; WITH...
; STANDARD SETUP
;
; RETURNS +1: ERROR
; +2: BUFFER ACCEPTED.
;-
NISRB: SAVEAC P1
OPSTR <SKIPN P1,>,PRFQA,(PR) ; Get the PTT entry address
ERROR UNNPE% ; No protocol type enabled
; Allocate a KLNI command block
MOVEI T1,RD.LST+BD.LEN*2; Get KLNI command buffer
CALL GXRCOR ; Get it
ERROR UNRES% ; No memory
MOVE CM,T1 ; Setup standard pointer
XMOVEI T1,RD.LST(T1) ; Get address of first BSD
MAP T1,(T1) ; Make it physical
STOR T1,RDPBA,(CM) ; Make RDPBA point to 1st BSD
; Check buffer size. Make sure size is same as previous buffers.
LOAD T1,UNBSZ,(UN) ; Get buffer size
JUMPLE T1,ERET UNIBS% ; Jump if illegal buffer size
OPSTR <CAMN T1,>,PRBSZ,(PR) ; Does it match previous sizes?
JRST NISRB5 ; Yes, continue
JN PRBSZ,(PR),ERET UNIBS% ; No, jump if size was already set
LOAD T4,PTVIR,(P1) ; Get address of free-Q header
STOR T1,QHLEN,(T4) ; Install size of q entries
; Check the buffer pointer. Make sure it specifies 8 bit bytes, no indexing,
; no indirection, word aligned, physically contiguous, locked pages.
; Also, extract Y field from byte pointer and make it physical.
;Check byte pointer for 8 bit bytes and word alignment
NISRB5: LOAD T1,UNBFA,(UN) ; Get byte pointer to start of buffer
LDB T2,[POINT 6,T1,5] ; Get it's P field
MOVE T2,BYTAB(T2) ; Get the byte pointer descriptor
LOAD T3,BYCHK,+T2 ; Get the size checking field
JRST @.+1(T3) ; Dispatch to the correct checking routine
IFIW ERET (UNIBP%) ; .BYILL - Illegal buffer pointer
IFIW NISRB7 ; .BYOK - Size is OK
IFIW NISRB6 ; .BYCHK - Check the size manually
IFIW KNIBT1 ; Bad BYTAB entry
; Manually check byte size, indexing or indirection, and extract E field
NISRB6: LDB T3,[POINT 6,T1,11] ; Get the S field from the byte pointer
CAIE T3,8 ; 8 bit bytes?
ERROR UNIBP% ; Illegal byte size
; If T1 contains one-word byte pointer, set IFIW to fool next chunk of code.
; If T1 contains a two-word byte pointer, get second word (which is an
; indirect word of some sort).
TXNN T1,1B12 ; Two word byte pointer?
TXOA T1,<IFIW> ; No, make it look like local format indirect
LOAD T1,UNBFA,+1(UN) ; Yes, get 2nd word
; T1 now contains an indirect word. If extended format indirect and no
; indexing/indirection, we are done.
TXCN T1,77B5 ; IFIW=0 & I=0 & X=0 ???
JRST NISRB7 ; Yes, global addr, proceed
; T1 contains indirect word (IFIW complemented). If complemented IFIW and
; no indexing/indirection, we are ok.
TXNE T1,<IFIW @(17)> ; Indexing or indirection?
ERROR UNIBP% ; Yes to either, no good
; Here for one-word globals, byte size is ok.
TLZA T1,-1 ; Through here for local indirect words
NISRB7: TXZ T1,77B5 ; Remove all but Y field
LOAD T3,BYLSH,+T2 ; Get the shift factor
JUMPN T3,ERET UNIFB% ; Jump if not word aligned
TXNE T2,BYOFF ; Does the address need to be incremented?
ADDI T1,1 ; Yes, point to next word
STOR T1,BDRES,+RD.LST(CM) ; Save virtual address of this buffer segment
LOAD T2,UNADS,(UN) ; Get address space indicator <<<(M.A.B.)
XCT [MAP T2,(T1) ; UNA.EV - Exec virtual => physical
XCTU [MAP T2,(T1)] ; UNA.UV - User virtual => physical
TRN](T2) ; UNA.PH - Physical => physical
; Make sure the page is locked down
LOAD T3,PHCPNO,+T2 ; Get just the page #
MOVE T3,@CST1X+T3 ; Get the lock status of this page
TXNN T3,<-PLKV> ; Is the page locked down?
ERROR UNIFB% ; Nope, bad buffer
STOR T2,BDSBA,+RD.LST(CM) ; Make BSD point to this segment
LOAD T4,QHLEN,(T4) ; Get theoretical size of this segment
STOR T4,BDSLN,+RD.LST(CM) ; Setup size of this segment
XMOVEI T1,RD.LST(CM) ; Setup pointer to BSD
LOAD T2,UNADS,(UN) ; Setup Address Space Descriptor
CALL FIXBSD ; Account for virtual page boundaries and such
RET ; Pass the error upwards
STOR PR,RDPID,(CM) ; Save portal ID in receive buffer
OPSTR <DMOVE T1,>,UNBFA,(UN) ; Get the buffer address
OPSTR <DMOVEM T1,>,RDVBA,(CM) ; Save given address in return word
LOAD T1,UNRID,(UN) ; Get request ID
STOR T1,RDRID,(CM) ; Save that too
LOAD T1,PTVIR,(P1) ; Get virtual address of q-interlock
CALL PUTQUE ; Put it on the queue
NOP ; It was empty
INCR PRORC,(PR) ; Increment the number of outstanding receives
RETSKP ; Give good return
SUBTTL READ/CLEAR PERFORMANCE COUNTERS
;+
; THIS ROUTINE IS CALLED TO QUEUE A READ/READ CLEAR COUNTERS COMMAND.
;
; RETURNS +1: ERROR, CODE IN T1
; +2: COMMAND QUEUED
;
;-
NIRPC: LOAD T1,UNBSZ,(UN) ; Get length of buffer
MOVX T2,PC.LEN ; Get minimum buffer length
STOR T2,UNBSZ,(UN) ; Save it in case of error return
JUMPLE T1,ERET UNIBS% ; Jump if it's negative
CAXGE T1,PC.LEN ; Is it big enough ??
ERROR UNIBS% ; Nope, Illegal buffer size
LOAD T1,UNSPI,(UN) ; Get source portal ID
LOAD PS,PRCHN,(T1) ; Get channel associated with that portal
JUMPLE PS,NIDSP1 ; BUGHLT if channel ptr .LE. 0
OPSTR <CAME PS,>,PSCHK,(PS) ; Is the check word Kosher?
JRST NIDSP1 ; Nope, BUGHLT
MOVX T1,NF.RPC ; Indicate function is read portal counters
CALLRET RDCTR ; Read the actual counters
NIRDC: LOAD T1,UNCHN,(UN) ; Get the channel #
CALL FNDCHN ; Look for it's status block
ERROR UNNSC% ; Error - No Such Channel
MOVE PS,T1 ; Setup the pointer
LOAD T1,UNBSZ,(UN) ; Get length of buffer
MOVX T2,CC.LEN ; Get minimum buffer length
STOR T2,UNBSZ,(UN) ; Save it in case of error return
JUMPLE T1,ERET UNIBS% ; Jump if it's negative
CAXGE T1,CC.LEN ; Is it big enough ??
ERROR UNIBS% ; Nope, Illegal buffer size
MOVX T1,NF.RDC ; Indicate function is read channel counters
; CALLRET RDCTR ; Read the actual counters
RDCTR: MOVE CM,T1 ; Save invoking command for a moment
MOVX T1,C1.LST ; Get length of read counters command
CALL GETCOR ; Allocate the command block
ERROR UNRES% ; No resources
EXCH CM,T1 ; CM <= command block addr, T1 <= function code
STOR T1,C1FNC,(CM) ; Save the function code
LOAD T1,UNBFA,(UN) ; Get user's buffer address
STOR T1,C1BFA,(CM) ; Save it in the command block
STOR PR,C1PID,(CM) ; Save the portal ID for the callback
LOAD T1,UNRID,(UN) ; Get request ID
STOR T1,C1RID,(CM) ; Save it for later
LOAD T1,UNSPI,(UN) ; Get secondary portal ID
STOR T1,C1SPI,(CM) ; Save it for later
MOVEI T1,OP.RCC ; Opcode
STOR T1,CMOPC,(CM) ; Save the opcode
LOAD T1,UNZRO,(UN) ; Get the "zero counters" bit
STOR T1,C1ZRO,(CM) ; Indicate we are zeroing the counters
SETONE CMCLR,(CM) ; Always clear the port counters
CALL QUECMD ; Queue the command
RETSKP ; Give good return
SUBTTL Read/Read clear counters response
RCRES: XMOVEI T1,RCBADR ; Get hardware counter block address
LOAD T2,PSSHC,(PS) ; Get address of shadow counter block
MOVX T3,RC.LEN ; Get length of counter block
RCRES2: MOVE T4,(T1) ; Get an entry from the hardware block
ADDM T4,(T2) ; Add it to the shadow block
XMOVEI T1,1(T1) ; Increment the source pointer
XMOVEI T2,1(T2) ; And the destination pointer
SOJG T3,RCRES2 ; Loop through the whole block
; Now correct for transmit and receive failure bit masks
XMOVEI T1,RCBADR ; Get address of read counters block
LOAD T2,PSSHC,(PS) ; Get address of shadow block
LOAD T3,RCXFM,(T2) ; Get transmit failure mask from shadow
OPSTR <SUB T3,>,RCXFM,(T1) ; Correct for the addition we just performed
OPSTR <IOR T3,>,RCXFM,(T1); And OR in the bit mask to make right result
STOR T3,RCXFM,(T2) ; Save the result in the shadow block
LOAD T3,RCRFM,(T2) ; Get receive failure mask from shadow
OPSTR <SUB T3,>,RCRFM,(T1) ; Correct for the addition we just performed
OPSTR <IOR T3,>,RCRFM,(T1); And OR in the bit mask to make right result
STOR T3,RCRFM,(T2) ; Save the result in the shadow block
OPSTR <SKIPN UN,>,PSINT,(PS) ; Get control buffer
JRST NOCTL ; None ??
LOAD PR,C1PID,(CM) ; Get Portal ID
LOAD T1,C1BFA,(CM) ; Get users buffer address
STOR T1,UNBFA,(UN) ; Save buffer address
LOAD T1,C1RID,(CM) ; Get the request ID
STOR T1,UNRID,(UN) ; Save that too
LOAD T1,C1FNC,(CM) ; Get the function code
CAXN T1,NF.RDC ; Is it "read channel counters"
JRST RCRCC ; Yes, process channel counters
CAXN T1,NF.RPC ; Read portal counters?
JRST RCRPC ; Yes, go to it
BUG. (HLT,KNIICF,PHYKNI,SOFT,<PHYKNI - Illegal read counters function>,,<
Cause: The read counters callback routine detected an illegal function code
in the field C1FNC of the command block.
>)
SUBTTL Complete reading of channel counters
BEGSTR CT ; Define structure counter descriptors
FIELD SRC,9 ; Source (RC block) offset
FIELD DST,9 ; Destination block offset
HWORD CTR ; NM counter number
ENDSTR
RCRCC: SAVEAC P1
MOVX T1,CC.LEN ; Get length of CC block
STOR T1,UNBSZ,(UN) ; Save if for the user
; Now copy all data out of the main "read counters block" into the user's
; block.
LOAD T1,PSTLZ,(PS) ; Get last time at which counters were zeroed
CALL CMPSLZ ; Compute seconds since last zeroed
LOAD T3,C1BFA,(CM) ; Get buffer address
STOR T1,CCSLZ,(T3) ; Save seconds since last zeroed
XMOVEI P1,CCTAB ; Get address of channel counters table
TXO T3,<<T1>>B5 ; Make an EFIW indexed by T1
MOVX T4,CCTLEN ; Setup length of CC table
CCCOPY: LOAD T1,CTSRC,(P1) ; Get offset of source counter
OPSTR <ADD T1,>,PSSHC,(PS) ; Add in base of shadow counters
MOVE T2,(T1) ; Fetch the counter
LOAD T1,CTDST,(P1) ; Get offset of dest counter
MOVEM T2,@T3 ; Store the counter in the user's block
LOADE T2,CTCTR,(P1) ; Get NM counter number
JUMPL T2,CCCOP1 ; Don't install counter # if negative
SUBI T1,1 ; Point to previous word
MOVEM T2,@T3 ; And stuff counter number into user's block
CCCOP1: XMOVEI P1,1(P1) ; Increment the CCTAB pointer
SOJG T4,CCCOPY ; Loop over the whole CC table
; Now correct the Bytes Received counter, and the Receive Failures counters
; to account for CRC's and port craziness.
LOAD T1,C1BFA,(CM) ; Get user's buffer address
LOAD T2,CCBYR,(T1) ; Get Bytes Received counter
LOAD T3,CCDGR,(T1) ; Get the number of datagrams received
LSH T3,2 ; Multiply that by 4
SUB T2,T3 ; Sub 4 bytes (CRC length) for
; each received datagram
STOR T2,CCBYR,(T1) ; Save it
LOAD T2,CCRF,(T1) ; Get the Receive Failures counter
OPSTR <SUB T2,>,PSMXT,(PS) ; Subtract the # multicasts's we xmitted
STOR T2,CCRF,(T1) ; Save it
SKIPN T2 ; Do we now have 0 Receive Failures?
SETZRO CCRFM,(T1) ; Yes, the mask should be zero
JE C1ZRO,(CM),RCRCC1 ; Skip this if not zeroing counters
CALL ZERSHD ; Zero the shadow counters
RCRCC1: MOVEI T1,NF.RDC ; Function code
LOAD T3,CMERC,(CM) ; Get the error code
CALL DLLCBK ; Pass it upwards
MOVE T1,CM ; Get address of command block
CALLRET RELCOR ; Release it
; Reset seconds since last zeroed, and the shadow counters
ZERSHD: MOVE T1,TODCLK ; Get current time
STOR T1,PSTLZ,(PS) ; Indicate counters were just zeroed
MOVX T1,RC.LEN ; Number of words to clear
LOAD T2,PSSHC,(PS) ; Start at beginning of shadow counters block
SETZM (T2) ; Clear first word of shadow counter block
XMOVEI T3,1(T2) ; Get address +1
EXTEND T1,[XBLT] ; Zapp the entire block
SETZRO PSMXT,(PS) ; Reset the # of multicasts xmitted
RET
DEFINE XX (source,dest,ctr)<
BYTE (9) RC.'source,CC.'dest (18) ctr
>
CCTAB: XX BR,BYR,0 ; Bytes received
XX BX,BYS,0 ; Bytes sent
XX FR,DGR,0 ; Datagrams received
XX FX,DGS,0 ; Datagrams sent
XX MCB,MBR,0 ; Multicast bytes received
XX MCF,MDR,0 ; Multicast datagrams received
XX FXD,DSD,0 ; Datagrams sent, initially deferred
XX FXS,DS1,0 ; Datagrams sent, single collision
XX FXM,DSM,0 ; Datagrams sent, multiple collisions
XX XF,SF,0 ; Send failures
XX XFM,SFM,-1 ; Send failure bit mask
XX RF,RF,0 ; Receive failure
XX RFM,RFM,-1 ; Receive failure bit mask
XX UFD,UFD,0 ; Unrecognised frame destination
XX DOV,DOV,0 ; Data overrun
XX SBU,SBU,0 ; System buffer unavailable
XX UBU,UBU,0 ; User buffer unavailable
CCTLEN==.-CCTAB
SUBTTL Complete reading of portal counters
RCRPC: SAVEAC P1
LOAD P1,C1SPI,(CM) ; Get secondary portal ID
STOR P1,UNSPI,(UN) ; Save it for the user
LOAD T1,PRTLZ,(P1) ; Get time at which counters were zeroed
CALL CMPSLZ ; Convert it to seconds since last zeroed
LOAD T3,C1BFA,(CM) ; Get buffer address
STOR T1,PCSLZ,(T3) ; Save seconds since last zeroed
MOVX T1,PC.LEN ; Get length of CC block
STOR T1,UNBSZ,(UN) ; Save if for the user
LOAD T1,PRBYR,(P1) ; Bytes received
STOR T1,PCBYR,(T3)
LOAD T1,PRDGR,(P1) ; Datagrams received
STOR T1,PCDGR,(T3)
LOAD T1,PRBYS,(P1) ; Bytes sent
STOR T1,PCBYS,(T3)
LOAD T1,PRDGS,(P1) ; Datagrams sent
STOR T1,PCDGS,(T3)
; Fetch the lost buffers count from the appropriate place in the read counters
; block. **** Note that this code may not work for unknown protocol queue****
LOAD T1,PRFQA,(P1) ; Get free queue address
LOAD T2,PSPTT,(PS) ; Get start of PTT for this channel
SUB T1,T2 ; Compute offset from start of PTT
IDIVI T1,PT.LEN ; Compute offset into read counters block
OPSTR <ADD T1,>,PSSHC,(PS) ; Add start of shadow counters table
LOAD T2,RCD01,(T1) ; Fetch the lost buffer count
STOR T2,PCUBU,(T3) ; User buffer unavailable
JE C1ZRO,(CM),RCRPC2 ; Skip this if not zeroing counters
MOVE T2,TODCLK ; Get current time
STOR T2,PRTLZ,(P1) ; Indicate that we just zeroed the counters
SETZRO RCD01,(T1) ; Reset the lost buffer count
SETZRO PRBYR,(P1) ; Clear bytes received
SETZRO PRDGR,(P1) ; Clear datagrams received
SETZRO PRBYS,(P1) ; Clear bytes sent
SETZRO PRDGS,(P1) ; Clear datagrams sent
RCRPC2: MOVX T1,NF.RPC ; Tell the user that
LOAD T3,CMERC,(CM) ; Get the error code
CALL DLLCBK ; we are done reading his counters
MOVE T1,CM ; Get command block address
CALLRET RELCOR ; Release the memory
SUBTTL CMPSLZ - Compute seconds since last zeroed
; Call: MOVX T1,TODCLK time at which counters were zeroed
; CALL CMPSLZ
; <Return +1 Always T1/ Seconds since last zeroed>
CMPSLZ: SUB T1,TODCLK ; T1 <= -amount of time since last zeroing
SUBI T1,^D500 ; Add 1/2 a second for rounding
IDIV T1,[-^D1000] ; Convert it to positive seconds
RET ; And return it to the user
SUBTTL NISCS - Set Channel State
NISCS: LOAD T1,UNCHN,(UN) ; Get channel #
CALL FNDCHN ; Look it up
ERROR UNNSC% ; Error - No such channel
MOVE PS,T1 ; Make it official
LOAD T1,UNSST,(UN) ; Get the new state
LOAD T2,PSSST,(PS) ; Get the current state
CAMN T1,T2 ; Is the state changing?
RETSKP ; No, we're all done
CAXL T1,UNS.VG ; Is it too small?
CAXLE T1,UNS.MX ; Or too big?
ERROR UNICS% ; Yes to either, bomb him out
JRST @.+1-UNS.VG(T1) ; Dispatch to the right routine
TABBEG UNS.VG,UNS.MX,FOO
TABENT UNS.VG,<IFIW ERET UNICS%> ; Virgin - Can't set to virgin state
TABENT UNS.RE,<IFIW NISCS1> ; Reload - Reload the KLNI microcode
TABENT UNS.CR,<IFIW ERET UNICS%> ; Can't Reload - Can't set this
TABENT UNS.IN,<IFIW ERET UNICS%> ; Init - Can't set to INIT state
TABENT UNS.RN,<IFIW NIINIA> ; Run - Startup the KLNI
TABENT UNS.DP,<IFIW NISCS1> ; Dump - Just dump the KLNI
TABENT UNS.DR,<IFIW NISCS1> ; Dump & Reload - Dump the KLNI and restart it
TABENT UNS.BK,<IFIW ERET UNICS%> ; Broken - KLNI cannot be initialized
TABENT UNS.OF,<IFIW NISCS1> ; Off - Turn off the KLNI
TABENT UNS.RR,<IFIW NISCS2> ; Request Reload - Make KNILDR run
TABEND
; Here to set the state to anything except RUN. Call with T1/ new state
NISCS1: SAVEAC P1
MOVE P1,T1 ; Save the new state in a safe place
NIOFF
CALL NISTP ; Stop the port
MOVE T1,P1 ; Get the new state back
CALL SETSTA ; Tell everybody about the new state
NION
RETSKP ; And return success
; Here to force KNILDR to reload a KLNI.
NISCS2: NIOFF ; Test and change of state must be interlocked
CAXE T2,UNS.RN ; Are we running?
IFSKP.
NION ; Enable interrupts
ERROR UNICS% ; Yes, don't allow this
ENDIF.
CALL STRLD ; Make CHKR run KNILDR
NION
RETSKP ; All done!
SUBTTL NIRPI - Read Portal Information
NIRPI: LOAD T1,PSCHN,(PS) ; Get the logical channel number
STOR T1,UNCHN,(UN) ; Return the channel #
OPSTR <SKIPG T1,>,UNBSZ,(UN) ; Does he want the multicasts?
RETSKP ; No, return now
SAVEAC <P1,P2,P3>
LOAD P1,PSMTT,(PS) ; Get the multicast table base
LOAD P2,UNBFA,(UN) ; Get the buffer address
SETZM (P2) ; Zero out count word
SUBI T1,1 ; Account for header word
ADDI P2,1 ; Skip header word
LOAD T2,PRMUL,(PR) ; Get the multicast bit mask
SETZ P3, ; Reset total # of multicasts
NIRPI1: JUMPE T2,NIRPI2 ; Jump if no more to do
JFFO T2,.+1 ; Look for an address
ADDI P3,1 ; Increment number of multicasts
LSH T2,2(T3) ; Remove the entry we just acquired
ADD P1,T3 ; Point to the MTT entry for this bit
SUBI T1,MT.LEN ; Account for this entry
JUMPL T1,NIRPI1 ; Don't store multicast if no room in buffer
OPSTR <DMOVE T3,>,MTHAD,(P1) ; Get the address
ADDI P1,MT.LEN ; Point to next address
TXZ T3,17 ; Clear low 4 bits of high order address
AND T4,[777774,,0] ; Clear all bit top 16 bits of low order
DMOVEM T3,(P2) ; Store the address
ADDI P2,MT.LEN ; Update the buffer pointer
LOAD T3,UNBFA,(UN) ; Get the buffer address
HRLM P3,(T3) ; Update the number of addresses returned
JRST NIRPI1 ; And do it again
NIRPI2: LOAD T3,UNBFA,(UN) ; Get the buffer address again
HRRM P3,(T3) ; Update the total multicast count
RETSKP ; And return success
SUBTTL QUEUE A COMMAND
;+
; THIS ROUTINE WILL PUT A COMMAND ON THE COMMAND QUEUE AND NOTIFY THE
; KLIPA IF NEED BE.
;
; CALL QUECMD
;
; Q2/ ADDRESS OF QUEUE ENTRY
; P2/ PRTTBL ADDRESS
;
; RETURNS +1: ALWAYS
;-
QUECMD: SETONE CMRSP,(CM) ;MAKE SURE THE RESPONSE BIT IS SET
LOAD T1,PSPCB,(PS) ;GET PCB BASE ADDRESS
; XMOVEI T1,PB.CQI(T1) ;GET THE ADDRESS OF THE INTERLOCK WORD
IFN FTHIST,<
CALL RECCMB ; Record the CM block
>; End of FTHIST
CALL PUTQUE ;PUT IT ON THE QUEUE
NOP ; IGNORE SKIP RETURN
OPSTR <XCT>,PSCQA,(PS) ;TELL KLIPA THAT COMMAND QUEUE IS AVAILABLE
RET
SUBTTL FNDPT - Find the PTT entry for a protocol type
; This routine will find the PTT entry for a given protocol type. If that
; protocol type is not found, it will return the address of the first free
; PTT slot.
;
; Call: MOVX T1,protocol_type
; CALL FNDPT
; <Return +1, protocol type not found,
; T1/ "fixed" protocol type,
; T2/ addr of 1st free entry or 0>
; <Return +2, success T1/ "fixed" protocol type,
; T2/ address of PTT entry>
FNDPT: CAME T1,[-2] ; Promiscuous?
CAMN T1,[-3] ; Or Unknown?
IFNSK. ; Yes to either
OPSTR <XMOVEI T2,>,PSUNK,(PS) ; Get address of pseudo PTT
JE PTFRE,(T2),RSKP ; Skip return if it's in use
RET ; Otherwise, give error & return address
ENDIF.
CALL SWAB ; Swap the bytes
MOVEI T3,NPTT ; Number of protocol types
SETZ T4, ; No free slots yet
OPSTR <SKIPA T2,>,PSPTT,(PS) ; Get the base address of the PTT
FNDPT2: ADDI T2,PT.LEN ; Advance to the next entry
TMNN PTFRE,(T2) ; Skip if free
IFSKP.
JUMPN T4,FNDPT1 ; Skip this if we have an entry already
MOVE T4,T2 ; Remember this address
JRST FNDPT1 ; Go on to next PTT slot
ENDIF.
OPSTR <CAMN T1,>,PTTYP,(T2) ; This the one ?
RETSKP ; Yes, skip return
FNDPT1: SOJG T3,FNDPT2 ; Back to the top
MOVE T2,T4 ; Get address of 1st free PTT slot
RET ; None found
SUBTTL RESPONSE - MESSAGE AVAILABLE
;+
; THIS ROUTINE IS DISPATCHED TO THROUGH THE COMMAND DISPATCH TABLE
; WITH
; Q2 = ENTRY ADDRESS
; P2 = PRTTBL ADDRESS
;-
MSGAVA:
IFN NICSW,<
AOS IS.IEN+1
>
OPSTR <SKIPN UN,>,PSINT,(PS) ; Get control buffer for interrupt level
JRST NOCTL ; None ??
LOAD PR,RDPID,(CM) ; Get portal ID
OPSTR <DMOVE T1,>,RDDA1,(CM) ; Get high order part of address
TXNN T1,1B7 ; Is it a multicast address?
JRST MSGAV2 ; No, proceed normally
; We have a multicast frame. Determine if this portal is enabled for this
; multicast address.
TXO T2,MTENA ; Set enable bit so we get a match in the MTT
SAVEAC P1 ; Get a perm ac
LOAD P1,PSMTT,(PS) ; Get address of MCAT
LOAD T3,PRMUL,(PR) ; Get the multicast bit map
JRST MULAV1 ; Start the search
MULAVA: LSH T3,2(T4) ; Remove leading 0's + 2 bits because each
; entry is two bits long
ADD P1,T4 ; Point to appropriate MCAT entry
OPSTR <CAME T1,>,MTHAD,(P1) ; Does the high order match?
JRST MULAV2 ; Nope, try again
OPSTR <CAMN T2,>,MTLAD,(P1) ; Does the low order address match?
JRST MSGAV2 ; Yes, accept the datagram
MULAV2: ADDI P1,MT.LEN ; Skip over the entry we just checked
MULAV1: JFFO T3,MULAVA ; Jump if there are some enabled addresses
; See if this is a promiscuous or unknown protocol type portal. If so,
; pass on the datagram.
LOADE T3,PRPRO,(PR) ; Get the protocol type
JUMPL T3,MSGAV2 ; Jump if it's promiscuous or unknown
;Here when a multicast is received for a portal that doesn't have it enabled
SKIPN NIBUGX ; Don't print these if not interested
IFSKP.
SAVEAC P2 ; Need yet another AC
OPSTR <DMOVE P1,>,RDDA1,(CM) ; Get destination Ethernet address
OPSTR <DMOVE T3,>,RDSA1,(CM) ; Get source Ethernet address
LOAD T1,RDPTY,(CM) ; Get protocol type
CALL SWAB ; Normalize it
BUG. (INF,KNIDMD,NISRV,SOFT,<Portal not enabled for this multicast>,<<P1,HIDST>,<P2,LODST>,<T3,HISRC>,<T4,LOSRC>>,<
Cause: A portal received a multicast frame on an address it wasn't enabled
for. The frame will be discarded, and the buffer will be re-used.
Data: HIDST - High order destination address
LODST - Low order destination address
HISRC - High order source address
LOSRC - Low order source address
>)
BUG. (INF,KNIDM1,NISRV,SOFT,<KNIDMD continued>,<<T1,PROTO>>,<
Cause: Additional data for KNIDMD.
Data: PROTO - Protocol type
>)
ENDIF.
LOAD T1,PRFQA,(PR) ; Get PTT entry address
LOAD T1,PTVIR,(T1) ; Get virt address of free queue header
CALLRET PUTQUE ; Put this buffer back on the free list
MSGAV2: LOAD T1,RDRID,(CM) ; Get request ID
STOR T1,UNRID,(UN) ; Set request ID
OPSTR <DMOVE T1,>,RDVBA,(CM) ; Get the buffer pointer
OPSTR <DMOVEM T1,>,UNBFA,(UN) ; Save it
LOAD T1,RDPTY,(CM) ; Protocol type
CALL SWAB ; Swap the bytes so humans can stand it
STOR T1,UNPRO,(UN) ; Save it
OPSTR <DMOVE T1,>,RDDA1,(CM) ; Get destination Ethernet address
OPSTR <DMOVEM T1,>,UNDAD,(UN) ; Store the dest address
OPSTR <DMOVE T1,>,RDSA1,(CM) ; Get source Ethernet address
OPSTR <DMOVEM T1,>,UNSAD,(UN) ; Store it
LOAD T1,RDSIZ,(CM) ; Get size
SUBI T1,4 ; Subtract length of CRC
OPSTR <ADDM T1,>,PRBYR,(PR) ; Keep track of bytes received
INCR PRDGR,(PR) ; and datagrams received
JE PRPAD,(PR),MSGAV4 ; Jump if padding is not enabled
OPSTR SKIPE,CMERC,(CM) ; Did we get an error?
JRST MSGAV4 ; Yes, just return it to the user
LOAD T2,BDSBA,+RD.LST(CM) ; Get physical buffer address
CALL PMOVE ; Get 1st word of buffer
LSH T2,-^D20 ; Right justify the data length field
EXCH T1,T2 ; T1 <= data length field, T2 <= frame length
CALL SWAB ; Make data length field useable
MOVX T3,UNLER% ; Prepare for a length error
CAMLE T1,T2 ; Data length field > frame length?
JRST MSGAV1 ; Yes, not Kosher
OPSTR <IBP>,UNBFA,(UN) ; Increment the user's pointer
OPSTR <IBP>,UNBFA,(UN) ; twice (to skip the data length field).
MSGAV4: LOAD T3,CMERC,(CM) ; Get the error code
MSGAV1: STOR T1,UNBSZ,(UN) ; Save the data length
DECR PRORC,(PR) ; Decrement the number of outstanding rcvs
MOVEI T1,NF.RCV ; Data recieved
CALL DLLCBK ; Call the portal back
MOVE T1,CM ; Get the entry address
CALL RXRCOR ; And return it
RETSKP
SUBTTL RESPONSE - DATAGRAM SENT
;+
; THIS ROUTINE IS DISPATCHED TO THROUGH THE COMMAND DISPATCH TABLE
; WITH
; Q2 = ENTRY ADDRESS
; P2 = PRTTBL ADDRESS
;-
DGSNT: OPSTR <SKIPN UN,>,PSINT,(PS) ; Get interrupt level control buffer
JRST NOCTL ; None
JE CMBSD,(CM),DGSNT5 ; Jump if non-BSD
LOAD PR,SBPID,(CM) ; Get the portal ID
LOAD T1,SBRID,(CM) ; Get request ID
STOR T1,UNRID,(UN) ; Make it available to the user
OPSTR <SKIPN T1,>,SBMSD,(CM) ; Get MSD base address
OPSTR <DMOVE T1,>,SBBFA,(CM) ; If not MSD, get buffer address
OPSTR <DMOVEM T1,>,UNBFA,(UN) ; Save it
LOAD T1,SNTXL,(CM) ; Get the length of the data
STOR T1,UNBSZ,(UN) ; Stuff it
OPSTR <ADDM T1,>,PRBYS,(PR) ; Keep track of bytes transmitted
INCR PRDGS,(PR) ; and datagrams transmitted
DECR PROXM,(PR) ; Decrement the outstanding xmit count
MOVEI T1,NF.XMT ; Get the function code
LOAD T3,CMERC,(CM) ; Get the error code
CALL DLLCBK ; Send to NISRV
MOVE T1,CM ; Get address of queue entry
CALL RXRCOR ; Return it
RETSKP ; Give good return
;NON-BSD SENT
DGSNT5: BUG. (HLT,KNINBS,PHYKNI,SOFT,<PHYKNI - Non-BSD datagram sent>,<<CM,BUFFER>>,<
Cause: A NON-BSD style datagram was sent. The driver does not send this
style.
Data: BUFFER - Buffer address
>) ;+++debug+++
RETSKP ;RETURN
SUBTTL NIRSI - Read KLNI Station Information
; Read the KLNI's station info. When the response happens do:
;
; 1) If the channel is in the initializing state:
; a) Copy all variables from the response into the shadow area
; b) Copy all variables that aren't valid from the response into the
; variables area.
;
; 2) If the channel is not in the initializing state, compare all the variables
; in the response with those in the shadow area. If they match, all is
; well, otherwise shutdown the KLNI and complain.
;
NIRSI: SETZ CM, ; First get a 0
OPSTR <EXCH CM,>,PSRSI,(PS) ; Acquire command queue entry
JUMPE CM,RTN ; Return if command is already active
MOVEI T1,OP.RSI ; Get the opcode for this command
STOR T1,CMOPC,(CM) ; Save it
CALL QUECMD ; Queue the command
RETSKP ; And give a skip return
; Read Station Information response
NSARD: STOR CM,PSRSI,(PS) ; Give buffer back
LOAD T1,RSVAR,(CM) ; Get the station varibles
OPSTR <DMOVE T2,>,RSHAD,(CM) ; Get the current station address
LOAD T4,PSSST,(PS) ; Get the current KLNI state
CAXE T4,UNS.IN ; Is it initializing?
IFSKP.
; Here upon completion of first KLNI command. Save the ROM address, and
; setup the shadow variables.
OPSTR <DMOVEM T2,>,PSHRA,(PS) ; Save the ROM address
OPSTR <DMOVEM T2,>,PSSAD,(PS) ; Setup the shadow address
TMNN PSVAD,(PS) ; Has the Ethernet address been set?
OPSTR <DMOVEM T2,>,PSHAD,(PS) ; No, put it into the variables area
STOR T1,PSSVA,(PS) ; Save shadow variables
LOAD T2,PSVBT,(PS) ; Get the mask of valid bits
LOAD T3,PSVAR,(PS) ; Get the bits that the user explicitly set
TDZ T1,T2 ; Zero all the KLNI bits that we have set
AND T3,T2 ; Zero all the bits the user hasn't set
OR T1,T3 ; Combine the KLNI var with the user's vars
STOR T1,PSVAR,(PS) ; Save the resultant variables
CALL NIWSI ; Update the new set of variables
MOVX T1,UNS.RN ; Port is now running
CALL SETSTA ; Tell everyone about it
ELSE.
; Here when KLNI is not initializing. Compare returned values with expected
; values in the shadow variables.
OPSTR <CAME T1,>,PSSVA,(PS) ; Does the port and my database match?
JRST BADVAR ; Nope, complain and shut down the port
OPSTR <CAMN T2,>,PSSAD,(PS) ; Does the high order address match?
OPSTR <CAME T3,>,PSSAD,+1(PS) ; And does the low order address match?
JRST BADADR ; Nope, complain and shut down the port
ENDIF.
RETSKP ; Good return
BADVAR: LOAD T2,PSVAR,(PS) ; Get the monitor's copy of the variables.
BUG. (CHK,KNIVAR,PHYKNI,SOFT,<Monitor variables do not match KLNI variables>,<<T1,KLNI>,<T2,MON>>,<
Cause: PHYKNI just read some status variables from the KLNI and found them
different from the shadow copies stored in the monitor.
Action: The port will be shutdown.
Data: KLNI - KLNI's version of the variables
MON - Monitor's version of the variables
>)
BADVA1: CALL NISTP ; Stop the KLNI
CALL STDUMP ; Take a dump of the KLNI
STOR CM,PSRSI,(PS) ; Give buffer back
RET
BADADR: LOAD T3,PSHAD,(PS) ; Get the monitor's copy of the address
LOAD T4,PSLAD,(PS) ; "
BUG. (CHK,KNIADR,PHYKNI,SOFT,<Monitor address does not match KLNI address>,<<T1,KLNHIO>,<T2,KLNLO>,<T3,MONHIO>,<T4,MONLO>>,<
Cause: PHYKNI just read the Ethernet address from the KLNI and found it
different from the shadow copy stored in the monitor.
Action: The port will be shutdown.
Data: KLNHIO & KLNLO - KLNI's copy of the Ethernet address
MONHIO & MONLO - Monitor's copy of the Ethernet address
>)
JRST BADVA1 ; Shutdown the port
SUBTTL NIRCI - Read Channel Information
NIRCI: LOAD T1,UNCHN,(UN) ; Get the channel # user supplied us
CALL FNDCHN ; Lookup the channel block
ERROR UNNSC% ; Error - No Such Channel
MOVE PS,T1 ; Put pointer into proper AC
OPSTR <DMOVE T1,>,PSHRA,(PS) ; Get high order ROM address
OPSTR <DMOVEM T1,>,UNHAD,(UN) ; Give it to caller
OPSTR <DMOVE T1,>,PSHAD,(PS) ; Get current high order address
OPSTR <DMOVEM T1,>,UNCAR,(UN) ; Return high order address
LOAD T1,PSSTA,(PS) ; Get the channel status
STOR T1,UNSTA,(UN) ; Make that the save it
RETSKP ; And return success
SUBTTL NICLO - Flush all commands from a portal
NICLO: CALL ALLCHE ; Do this for all channels
MOVX T1,CM.LEN+FL.LEN ; Just get a small command block
CALL GETCOR ; Allocate the memory
ERROR UNRES% ; No memory???
MOVE CM,T1 ; Put pointer in special AC
MOVX T1,OP.FLS ; Get the flush opcode
STOR T1,CMOPC,(CM) ; Install it
MOVX T1,'FLUSH' ; Get special keyword
STOR T1,FLCHK,(CM) ; Install it in the check word
STOR PR,FLPID,(CM) ; Install the PID
CALL QUECMD ; Queue it up
; See if the channel is running. If not, we have to manually search through
; the command queue, returning all commands queued up by this portal.
NIOFF ; No interrupts please
LOAD T1,PSSST,(PS) ; Get the internal state
CAXN T1,UNS.RN ; Is the KLNI running?
JRST NICLO1 ; Yes, we're all done
SAVEAC P1
NICLO3: LOAD T1,PSPCB,(PS) ; Get address of command queue
CALL REMQUE ; Get an item off the queue
JRST NICLO1 ; Error, queue should never be empty
LOAD P1,CMOPC,(CM) ; Get the opcode
XCT PIDFET(P1) ; Fetch the portal ID
CAME PR,T1 ; Is this the desired portal?
JRST NICLO2 ; Nope, requeue the command
MOVX T1,UNCAB% ; Get the command abort error code
STOR T1,CMERC,(CM) ; Put the error code into the command block
CALL @CMDDSP(P1) ; Process the command
NOP ; In case of skip returns
CAXN P1,OP.FLS ; Did we just process a close?
JRST NICLO1 ; Yes, we're all done
JRST NICLO3 ; Try again
NICLO2: CALL QUECMD ; Requeue the command
JRST NICLO3 ; And try again
NICLO1: NION ; Allow interrupts
RETSKP ; And return
; Table of instructions used for fetching portal IDs from various commands.
PIDFET: TABBEG OP.FLS,OP.WSI,<FOO>
TABENT OP.FLS,<LOAD T1,FLPID,(CM)> ; Close command
TABENT OP.SND,<LOAD T1,SBPID,(CM)> ; Xmit command
TABENT OP.LDM,<SETZ T1,> ; Load multicast command
TABENT OP.LDP,<SETZ T1,> ; Load PTT command
TABENT OP.RCC,<LOAD T1,C1PID,(CM)> ; Read counters command
TABENT OP.RCV,<CALL UNKRES> ; Receive command
TABENT OP.WPL,<CALL UNKRES> ; Write PLI command
TABENT OP.RPL,<CALL UNKRES> ; Read PLI command
TABENT OP.RSI,<SETZ T1,> ; Read station info command
TABENT OP.WSI,<SETZ T1,> ; Write station info command
TABEND
SUBTTL CLOSED - Command flush completion
CLOSED: LOAD T1,CMERC,(CM) ; Get the error code
CAXE T1,URCCOD ; Is it the magic code?
CAXN T1,UNCAB% ; Or a command abort?
TRNA ; Yes to either, alls fine
JRST BADFLS ; Nope, die
OPSTR <SKIPN UN,>,PSINT,(PS) ; Get interrupt level control buffer
JRST NOCTL ; None
LOAD T1,FLCHK,(CM) ; Get check word
CAXE T1,'FLUSH' ; Is it the magic value?
JRST BADFLS ; Nope, complain about it
SETZRO FLCHK,(CM) ; Yes, zapp it
LOAD PR,FLPID,(CM) ; Setup portal block pointer
MOVX T1,NF.CLO ; Indicate that all commands are flushed
CALL DLLCBK ; And inform the user
MOVE T1,CM ; Get address of command block
CALLRET RELCOR ; Release the command block
BADFLS: BUG. (HLT,KNIIRC,PHYKNI,SOFT,<Illegal status on close>,<<T1,STATUS>>,<
Cause: The status field contained an unexpected value upon return from the
close function.
Data: STATUS - Status
>)
SUBTTL NISCA - Set Channel Address
NISCA: LOAD T1,UNCHN,(UN) ; Get channel number
CALL FNDCHN ; Look foor the channel block
ERROR UNNSC% ; Error - No Such Channel
MOVE PS,T1 ; Setup channel block pointer
CALL FETADR ; Get address from UN block
TXNE T1,1B7 ; Is it a multicast?
ERROR UNICA% ; Yes, Illegal channel address
NIOFF ; No interrupts
;**;[7286] Change 1 line at NISCA: + 10 L JDM 14-APR-86
OPSTRM <DMOVEM T1,>,PSHAD,(PS) ; Store the new address
SETONE PSVAD,(PS) ; Indicate that the address is valid
NION ; Enable the interrupts
;**;[7326] Change 1 line at NISCA: + 14 L JDM 23-JUN-86
OPSTRM <DMOVEM T1,>,UNCAR,(UN) ; [7326]Save the address we loaded
; [7326]for those who get the callback
CALL NIWSI ; Write the new station info
MOVX T1,NF.SCA ; Get the callback code
CALL DLLCBK ; Tell everyone about the address change
RETSKP ; Return success
SUBTTL PHYSICAL MOVER
;SUBROUTINE TO GET THE CONTENTS OF A GIVEN PHYSICAL ADDRESS
;CALL: T2/DESIRED PHYSICA ADDRESS
; RETURNS +1, WITH T2=CONTENTS
;PRESERVES T1
PMOVE: SAVEAC <T1> ;SAVE T1
LOAD T1,PGWD,T2 ;WORD NUMBER
LOAD T2,PHCPNO,T2 ;PHYSICAL PAGE NUMBER
CALL MOVRCA ;GET THE CONTENTS
MOVE T2,T1 ;RETURNS THE ANSWER IN T2
JRST PMOVER ;RESTORE T1 AND RETURN
;ROUTINE TO STORE INTO A GIVEN PHYSICAL ADDRESS
;CALL: T3/CONTENTS TO BE STORED
; T2/ADDRESS TO STORE IT
;RETURNS +1 ALWAYS
;PRESERVES T1
PMOVEM: SAVEAC <T1> ;SAVE T1
LOAD T1,PGWD,T2 ;WORD NUMBER
LOAD T2,PHCPNO,T2 ;PAGE NUMBER
CALL STORCA ;STORE T3 THERE
PMOVER: RET ;AND RETURN TO CALLER
SUBTTL PUT AN ENTRY ON THE QUEUE
;SUBROUTINE TO INSERT A PACKET ONTO A QUEUE
;CALL WITH Q2=ADDRESS OF PACKET, T1= ADDR OF INTERLOCK WORD OF QUEUE
;RETURNS TO CALL+1 IF QUEUE WAS EMPTY
;RETURNS TO CALL+2 IF QUEUE WAS NON-EMPTY BEFORE INSERTION
;
;DESTROTS T1,T2,T3
PUTQUE: NIOFF ;IF WE INTERRUPT OWNING AN INTERLOCK
; WE HANG THE KLIPA
PUTQU1: AOSN T2,QH.IWD(T1) ;GET INTERLOCK
JRST PUTQU2 ;GOT IT
CAXG T2,TIMOUT ;WAITED LONG ENOUGH?
JRST PUTQU1 ;NO, TRY AGAIN
AOS TIMCNT ;YES. DO IT ANYWAY. BUMP COUNTER
PUTQU2: MOVEM CM,QE.VIR(CM) ;SAVE VIRTUAL ADDR IN PACKET BUFFER
MAP T3,QE.FLI(CM) ;PHYSICAL ADDR OF PACKET
TXZ T3,ADRMSK ;CLEAR JUNK
MAP T2,QH.FLI(T1) ;PHYSICAL ADDR OF QUEUE HEADER
TXZ T2,ADRMSK ;CLEAR JUNK
CAME T2,QH.FLI(T1) ;FLINK POINT AT ITSELF (EMPTY QUEUE)?
JRST PUTQU3 ;NO
MOVEM T2,QE.FLI(CM) ;YES. POINT PACKET BACK AT QUEUE HEADER
MOVEM T2,QE.BLI(CM)
MOVEM T3,QH.BLI(T1) ;POINT PCB FLINK AND BLINK AT PACKET
MOVEM T3,QH.FLI(T1)
QRET: SETOM QH.IWD(T1) ;RELEASE INTERLOCK
NION ;TURN INTERRUPTS BACK ON
RET ;RETURN TO CALLER
PUTQU3: MOVEM T2,QE.FLI(CM) ;POINT FLINK OF PACKET AT PCB
MOVE T2,QH.BLI(T1) ;GET FORMER END OF QUEUE
MOVEM T3,QH.BLI(T1) ;POINT QUEUE TAIL AT THIS PACKET
MOVEM T2,QE.BLI(CM) ;POINT BLINK OF THIS PACKET AT FORMER END
CALL PMOVEM ;POINT BLINK OF FORMER END AT THIS PACKET
QRETS: SETOM QH.IWD(T1) ;RESET THE INTERLOCK
NION ;TURN INTERRUPTS BACK ON
RETSKP ;SKIP RETURN
SUBTTL REMOVE AN ENTRY FROM A QUEUE
;SUBROUTINE TO REMOVE FIRST PACKET FROM A QUEUE
;CALL WITH T1=ADDRESS OF INTERLOCK WORD OF QUEUE
;RETURNS WITH Q2=ADDRESS OF 1ST PACKET ON QUEUE (WHICH IS NOW UNQUEUED)
;RETURNS TO CALL+1 IF QUEUE IS EMPTY BEFORE REMOVAL
;RETURNS TO CALL+2 WITH T2=-1 IF QUEUE IS STILL NOT EMPTY, ELSE 0
;
;DESTROYS T1,T2,T3
REMQUE: NIOFF ;NO INTERRUPTS
REMQU1: AOSN T2,QH.IWD(T1) ;WAIT FOR INTERLOCK
JRST REMQU2 ;GOT IT
CAXG T2,TIMOUT ;WAITED LONG ENOUGH?
JRST REMQU1 ;NO, TRY AGAIN
AOS TIMCNT
REMQU2: CALL CHKMPT ;IS QUEUE ALREADY EMPTY?
JRST QRET ;EMPTY
MOVE T2,QH.FLI(T1) ;GET 1ST PACKET FROM QUEUE
ADDI T2,QE.VIR ;POINT AT VIRTUAL ADDRESS OF PACKET
CALL PMOVE
MOVE CM,T2 ;VIRTUAL ADDR OF PACKET IN CM
DMOVE T2,QE.FLI(CM) ;GET FLINK, BLINK OF THIS PACKET
CAME T2,T3 ;FLINK=BLINK?
JRST REMQU3 ;NO, QUEUE IS STILL NON-EMPTY
DMOVEM T2,QH.FLI(T1) ;YES. QUEUE IS EMPTY. POINT HEADER AT ITSELF
SETZ T2, ;SET INDICATOR
JRST QRETS ;AND SKIP - RETURN
REMQU3: MOVEM T2,QH.FLI(T1) ;POINT QUEUE HEADER AT NEXT PACKET
ADDI T2,QE.BLI ;POINT AT FLINK OF NEXT PACKET
CALL PMOVEM ;POINT ENXT PACKET BACK AT HEADER
SETO T2, ;SET INDICATOR
JRST QRETS ;SKIP RETURN
;ROUTINE TO CHECK IF A QUEUE IS EMPTY
;CALL WITH T1=ADDRESS OF INTERLOCK WORD OF QUEUE
;RETURNS WITH T1 UNCHANGED
;NON-SKIP RETURN IF QUEUE IS EMPTY
;SKIP RETURN IF QUEUE IS NON-EMPTY
CHKMPT: MAP T2,QH.FLI(T1) ;GET PHYSICAL ADDRESS OF QUEUE HEADER
TXZ T2,ADRMSK ;CLEAR JUNK
CAMN T2,QH.FLI(T1) ;DOES QUEUE POINT AT ITSELF (EMPTY) ?
RET ;YES, NON-SKIP
RETSKP ;NO, SKIP
SUBTTL CORE MANAGER
;+
; THIS ROUTINE IS CALLED TO ALLOCATE WORDS FROM THE RESIDENT FREE SPACE
; POOL. IT RETURNS ALL ALLOCATIONS ON A FOUR WORD BOUNDARY. THE ALLOCATED
; ADDRESS IS SAVED IN THE FOUR WORD BOUNDARY ADDRESS -1. THE ENTIRE BLOCK
; IS ZEROED.
;
; CALL WITH:
; T1/ NUMBER OF WORDS NEEDED
;
; RETURNS +1: ALLOCATION FAILURE
; +2: ALLOCATION MADE. T1=BUFFER ADDRESS
;-
GETCOR: STKVAR <WORDS,ADDRESS> ;PLACE TO SAVE NUMBER OF WORDS AND ADDRESS
MOVEM T1,WORDS ;SAVE NUMBER OF WORDS
HRLI T1,.RESP1 ;HIGHEST PRIORITY
MOVEI T2,.RESGP ;FROM THE GENERAL POOL
CALL ASGRES ;GET WORDS
RET ;GIVE ERROR RETURN
MOVEM T1,ADDRESS ;SAVE THE ADDRESS
MOVE T2,WORDS ;GET NUMBER OF WORDS BACK
CALL CHKBUF ;MAKE SURE IT IS CONTIGUOUS PHYSICALLY
IFNSK.
MOVE T1,WORDS ;GET NUMBER OF WORDS BACK
CALL GETCOR ;TRY AGAIN
RET ; TRIED TWICE, GIVE UP
EXCH T1,ADDRESS ;SWAP NEW ADDRESS WITH OLD ADDRESS
CALL RELCOR ;RELEASE THE OLD BLOCK
ENDIF.
MOVE T1,ADDRESS ;GET ADDRESS BACK
RETSKP ;AND GIVE GOOD RETURN
ENDSV.
;+
; ROUTINE TO RELEASE ALLOCATED FREE CORE. ALLOCATED ADDRESS STORED IN
; ADDRESS -1.
;
; CALL WITH:
; T1/ BUFFER ADDRESS. ADDRESS ALLOCATED BY GETCOR.
;
; RETURNS +1: ALWAYS
;-
RELCOR: CALLRET RELRES ;FREE THEM AND RETURN
SUBTTL GXRCOR - Get core for transmits and receives
GXRCOR: NIOFF ; Disable interrupts
SKIPN T2,XRCQUE ; Any command blocks available?
JRST GXRCO3 ; Nope, get more from ASGRES
XMOVEI T3,XRCQUE ; Setup previous address
GXRCO2: CAMG T1,-1(T2) ; Is this block big enough?
JRST GXRCO1 ; Yes, give it away
MOVE T3,T2 ; Remember previous block
MOVE T2,0(T2) ; Nope, point to next block
JUMPN T2,GXRCO2 ; And loop till done
GXRCO3: NION ; Turn interrupts back on
PUSH P,T1 ; Save Size for a moment
ADDI T1,1 ; Account for size word
CALL GETCOR ; Get the memory
JRST PA1 ; Adjust the stack and return
POP P,(T1) ; Put the size into the block
ADDI T1,1 ; Point to the next word
RETSKP ; And return success
GXRCO1: MOVE T1,T2 ; Get block address into T1
MOVE T2,0(T2) ; Get next block address
MOVEM T2,0(T3) ; Make previous block point to next block
NION
; Zero the core we are returing
SETZM (T1) ; Clear the first word
MOVE T2,-1(T1) ; Get the length of the block
MOVE T3,T1 ; Get the address of the first word
XMOVEI T4,1(T3) ; Get the address of the second word
EXTEND T2,[XBLT] ; Clear the whole block
RETSKP ; All done
RXRCOR: SETZM 0(T1) ; Zero the next block pointer
MOVE T2,TODCLK ; Get a timestamp
MOVEM T2,1(T1) ; Stamp the block
NIOFF ; No interrupts please
MOVE T2,XRCQUE ; Get the first block on the queue
MOVEM T2,0(T1) ; Make this block point to the first
MOVEM T1,XRCQUE ; Make this block be the new first
ONRET: NION ; Allow interrupts
RET
; Here once a minute to release grubby blocks from the XRCQUE
CORCHK: ADDI T1,^D60000 ; Make it one more minute
MOVEM T1,CORTIM ; Don't do this till a minute
NIOFF ; No interrupts please
SKIPN T2,XRCQUE ; Get the queue head
JRST ONRET ; Q is empty, just return
SAVEAC <P1,P2,P3>
MOVE P1,T2 ; Get q head setup
XMOVEI P2,XRCQUE ; Get the queue head
SUBI T1,^D120000 ; Compute age of grubbiness
MOVE P3,T1 ; Put time in a safe place
CORCH2: CAML P3,1(P1) ; Is this block too grubby?
JRST CORCH1 ; Yes, release it
MOVE P2,P1 ; Remember previous block
MOVE P1,0(P1) ; Nope, point to next block
JUMPN P1,CORCH2 ; And loop over all blocks
NION
RET
CORCH1: MOVE T1,P1 ; Get block address into T1
MOVE P1,0(P1) ; Get next block address
MOVEM P1,0(P2) ; Make previous block point to next block
SUBI T1,1 ; Point to true start of block
CALL RELCOR ; Release the memory
JUMPN P1,CORCH2 ; Loop over all blocks
NION
RET
SUBTTL CHECK BUFFER PHYSICAL RANGE
;ROUTINE TO ADDRESS CHECK ANY BUFFER. NOTE THAT THE BUFFER SHOULD BE .LE.
;1000 WORDS FOR THIS ROUTINE TO WORK CORRECTLY.
;CALL WITH
; T1 = BUFFER ADDRESS
; T2 = # OF WORDS LONG
;RETURNS
; +1: ERROR
; +2: BUFFER IS PHYSICALLY CONTIGUOUS
;-
CHKBUF: ADD T2,T1 ;ADD START ADDRESS TO LENGTH
MAP T1,(T1) ;GET PHYSICAL ADDRESS OF START OF BUFFER
MAP T2,-1(T2) ;GET PHYSICAL ADDRESS OF END OF BUFFER
TXZ T1,ADRMSK+PGWD ;CLEAR ACCESS BITS AND WORD WITHIN PAGE
TXZ T2,ADRMSK+PGWD ;CLEAR ACCESS BITS AND WORD WITHIN PAGE
SUB T2,T1 ;SEE HOW MANY PAGES WE SPAN
JUMPL T2,RTN ;CATCH CASE OF PHYSICAL RUNNING BACKWARDS
CAXG T2,1_PGSFT ;IS IT GREATER THAN ONE?
AOS (P) ; NO, WE ARE FINE
RET ;YES, PUNT
SUBTTL STOP THE KLNI (FREEZE)
NISTP: MOVX T1,NOP ; Get a No-op
STOR T1,PSCQA,(PS) ; Prevent QUECMD from starting the port
OPSTR <XCT>,PSCNI,(PS) ; Read the CSR
TXNN T1,CO.MRN ; Is the port running?
JRST NISTP1 ; Nope, don't bother
MOVX T1,CO.DIS+CO.MRN ; Setup bits for CONO
OPSTR <XCT>,PSCNO,(PS) ; Disable the port
MOVEI T2,TIMOUT ; Loop count
DO.
OPSTR <XCT>,PSCNI,(PS); Read the status
TXNN T1,CI.DCP ; Disable complete?
SOJG T2,TOP. ; Continue checking
ENDDO.
NISTP1: SETZ T1, ; Get bits for CONO
OPSTR <XCT>,PSCNO,(PS) ; Clear the run flop irregardless
MOVE T1,CHNTAB+5 ; Get our CDB
MOVX T2,CS.MAI ; Get the maint bit
IORM T2,CDBSTS(T1) ; Set it in the CDB
RET ; and return
SUBTTL INICOM - Setup initial KLNI commands
; This routine will ensure that the first four commands on the command
; queue are Read Station Info, Write Station Info, Load PTT, Load MCAT.
; These commands must be done first to ensure that the KLNI is in a
; consistent state when it finally gets running.
INICOM: OPSTR XCT,PSCNI,(PS) ; Get the status
TXNE T1,CO.MRN ; Is the KLNI running?
RET ; Yes, that's not good
SAVEAC <P1,P2,P3>
STKVAR (GODRET)
SETZM GODRET ; Indicate that we want good return
LOAD P3,PSPCB,(PS) ; Get address of PCB
OPSTR <DMOVE P1,>,PBCQF,(P3) ; Get flink and blink of command queue
OPSTR <MAP T2,>,PBCQF,(P3) ; Get physical address of command queue
TXZ T2,ADRMSK ; Clear junk bits
STOR T2,PBCQF,(P3) ; Make the flink point to itself
STOR T2,PBCQB,(P3) ; Make the blink point to the flink
CALL NIRSI ; Issue a Read station info as the 1st command.
NOP ; Command is busy?!?
CALL LDPTT ; Load the protocol type table
CALL LDMCT ; Load the multicast table
OPSTR <MAP T1,>,PBCQF,(P3) ; Get the physical address of the flink
TXZ T1,ADRMSK ; Clear junk bits
CAMN T1,P1 ; Was the command queue empty?
JRST INICO1 ; Yes, quit now
LOAD T2,PBCQB,(P3) ; Get address of last command in queue
MOVE T3,P1 ; Get address of 1st command in old queue
CALL PMOVEM ; Make last command point to first old cmd
MOVE T2,P1 ; Get address of 1st command in old queue
ADDX T2,QE.BLI ; Get address of it's blink
LOAD T3,PBCQB,(P3) ; Get address of last command in queue
CALL PMOVEM ; Make blink in 1st command in old queue
; point to last command in new queue
MOVE T2,P2 ; Get address of last command in old queue
OPSTR <MAP T3,>,PBCQF,(P3) ; Get address of cmd q header
TXZ T3,ADRMSK ; Clear junk bits
CALL PMOVEM ; Make flink in last cmd in old queue point
; to cmd q header
STOR P2,PBCQB,(P3) ; Make cmd q blink point to last command in
; old queue
INICO1: SKIPE GODRET ; Do we want to give a good return?
RET ; Nope, quit now
RETSKP
SUBTTL ENABLE KLIPA NI PORT
;+
; THIS ROUTINE IS CALLED BY NININI TO GET THE KLIPA NI PORT RUNNING.
;
; INPUTS:
;
; Q3 = PCB ADDRESS
; P1 = CDB ADDRESS
; P2 = PORT STORAGE ADDRESS
;
; RETURNS:
;
; +1 = CAN'T START THE KLIPA
; +2 = KLIPA NI PORT IS NOW ENABLED AND RUNNING
;-
UCVMAJ: EXP 1 ; Acceptable major version #
UCVMIN: EXP 0 ; Acceptable minor version #
ENBKLP: CALL RDVER ; Read the ucode version
RET ; Port running!?!??
STOR T1,PSUMA,(PS) ; Save major version #
STOR T2,PSUMI,(PS) ; Save minor version #
STOR T3,PSUED,(PS) ; Save the edit #
CAMN T1,UCVMAJ ; Does the major version # match?
CAME T2,UCVMIN ; Yes, Does the minor version # match?
IFNSK.
BUG. (CHK,KNIVER,PHYKNI,SOFT,<Bad KLNI microcode version>,<<T1,BADMAJ>,<T2,BADMIN>,<<XADDR. UCVMAJ>,GODMAJ>,<<XADDR. UCVMIN>,GODMIN>>,<
Cause: PHYKNI has read the microcode version number from the KLNI, and has
determined that it is below the minimum revision level required for
proper port/driver operation. The port will not be started in this
case.
Action: Obtain the proper version of the KLNI microcode. The minimum
acceptable version is indicated by the second additional data item.
Data: BADMAJ - Major version number read from the KLNI
BADMIN - Minor version number read from the KLNI
GODMAJ - Major version number we require
GODMIN - Minor version number we require
>)
RET ; Don't start the port
ENDIF.
MOVX T1,CO.CPT ; Get ready to
OPSTR XCT,PSCNO,(PS) ; clear the port
LOAD T1,PSPBA,(PS) ; Get physical addr of 1st word of PCB
ADDX T1,<CHXFR!CHLST!FLD(3,CHCNT)+PB.PBA>; XFER 3 words and HALT
LOAD T2,PSCBA,(PS) ; Get CBUS address
LSH T2,2 ; * 4
MOVEM T1,KIEPT(T2) ; Save in channel area
MOVX T1,DO.LRA ; Get bits for DATAO
OPSTR <XCT>,PSDTO,(PS) ; Set start address to 0
MOVX T1,CO.DIS+CO.MRN ; Get bits for CONO
OPSTR <XCT>,PSCNO,(PS) ; Go from uninitialized to disabled
MOVEI T3,TIMOUT ; Loop count
DO.
OPSTR <XCT>,PSCNI,(PS); Read the status
TXNN T1,CI.DCP ; Disable complete?
SOJG T3,TOP. ; Continue checking
ENDDO.
JUMPE T3,INIERR ; Go away if timed out
LOAD T1,PSPBA,(PS) ; Get physical base address of PCB
ADDX T1,PB.CCW ; Address of channel command word
TXO T1,CHJMP ; Make it a jump command
MOVEM T1,KIEPT(T2) ; Save it in the channel jump word
LOAD T1,PSCNO,(PS) ; Get the CONO for this channel
TXC T1,<Z CO.BTS+CO.CQA(T1)> ; Clear index AC, set Command Queue Avail
STOR T1,PSCQA,(PS) ; Allow QUECMD to kick the port
MOVX T1,CO.BTS ; Get the enable bit, PIA and Uproc run
OPSTR <XCT>,PSCNO,(PS) ; Enable the port for normal operation
MOVEI T2,TIMOUT ; Get the loop count
DO.
OPSTR <XCT>,PSCNI,(PS); Read the status
TXNN T1,CI.ECP ; Enable complete?
SOJG T2,TOP. ; Continue checking
ENDDO.
JUMPE T2,INIERR ; Go away if timed out
OPSTR XCT,PSCQA,(PS) ; Start up the command queue
RETSKP ; Indicate success
; Here when we timed out during port initialization. See if any error bits
; are set in T1.
INIERR: TXNE T1,CI.ERR ; Any error bits set?
JRST KNIERR ; Yes, complain and log the problem
BUG. (CHK,KNIINF,PHYKNI,HARD,<PHYKNI - KLNI initialization timed out>,<<T1,CONI>>,<
Cause: The KLNI timed out during initialization. Either "disable complete"
didn't set or "enable complete" didn't set (the CONI will indicate
which). This is very likely a hardware problem, because the microcode
version number was valid, and there was no specific error indication
in the CONI.
Action: Try reloading the KLNI microcode. If the problem still persists call
field service.
Data: CONI - CONI KNI,
>)
CALLRET NISTP ; Stop the KLNI gracefully
SUBTTL INITIALIZE THE PORT CONTROL BLOCK
;+
; THIS ROUTINE IS CALLED BY ENBKLP TO SETUP THE PCB BEFORE ENABLING THE
; KLIPA NI PORT.
;
; CALL
;
; RETURNS
; +1 = ALWAYS
;-
; Do the command queue first
QUNLOK: TDZA T1,T1 ; Only unlock interlocks
PCBINI: SETO T1, ; Reset queue headers
SAVEAC <P1,P2>
MOVEM T1,P2 ; Remember the unlock only flag
LOAD P1,PSPCB,(PS) ; Get PCB virt address
OPSTR <XMOVEI T1,>,PBCQI,(P1) ; Get command queue header
CALL INIQH ; Initialize the command queue header
; Now do the response queue
OPSTR <XMOVEI T1,>,PBRQI,(P1) ; Get the response queue header
CALL INIQH ; Initialize the response queue header
; The unknown protocol type free queue
OPSTR <XMOVEI T1,>,PBUQI,(P1) ; Get the queue flink address
CALL INIQH ; Initialize the UPT queue header
;...
;...
; Setup the protocol type table
XMOVEI T1,PTTADR ; Protocol type table address
STOR T1,PSPTT,(PS) ; Save in port storage
MAP T1,(T1) ; Make it physical
TXZ T1,ADRMSK ; Clear junk
STOR T1,PBPTT,(P1) ; Save it in PCB
; Setup the free queues and their pointers in the PTT
XMOVEI T1,FRQADR ; Get free queue headers address
LOAD T3,PSPTT,(PS) ; Get virt address of PTT
MOVEI T4,NPTT ; Setup loop count
SETFQ1: STOR T1,PTVIR,(T3) ; Save the virtual address of header
MOVX T2,PTFRE ; Get the PTT entry free bit
SKIPE P2 ; Skip if just unlocking interlocks
IORM T2,$PTFRE(T3) ; Indicate entry is unused
CALL INIQH ; Setup the free queue header
SKIPE P2 ; Skip if just unlocking interlocks
STOR T2,PTFRQ,(T3) ; Save the physical address of the flink
ADDI T1,QH.LEN ; Advance to next queue header
ADDI T3,PT.LEN ; Advance to next protocol type entry
SOJG T4,SETFQ1 ; Loop for all
JUMPE P2,RTN ; Just return now if unlocking interlocks
; Set up the fake PTT entry for the unknown protocol type queue
OPSTR <XMOVEI T1,>,PBUQI,(P1) ; Get address of the unknown free queue
OPSTR <XMOVEI T3,>,PSUNK,(PS) ; Get address of pseudo PTT
STOR T1,PTVIR,(T3) ; Save the virtual address of the q header
OPSTR <MAP T2,>,QHFLI,(T1) ; Make address physical
TXZ T2,ADRMSK ; Clear access bits
STOR T2,PTFRQ,(T3) ; Save the physical address of the flink
SETONE PTFRE,(T3) ; Indicate entry is unused
; Setup the multicast table
XMOVEI T1,MCTADR ; Multicast table address
STOR T1,PSMTT,(PS) ; Save in ports storage
MAP T1,(T1) ; Make physical
TXZ T1,ADRMSK ; Clear junk
STOR T1,PBMTT,(P1) ; Save in PCB
; Setup the counters block
XMOVEI T1,RCBADR ; Get address of read counters block
MAP T1,(T1) ; Make it physical
TXZ T1,ADRMSK ; Clear out junk bits
STOR T1,PBRCB,(P1) ; Tell the port about it
RET
; Initialize a KLNI queue header
; Call: movx T1,virtual address of queue header
; movx P2,flag, if 0 just reset interlock
; CALL INIQH
; <Return +1 always, T1 unchanged, T2/ phys addr of flink of Q header>
; All other ACs are unchanged
INIQH: SETONE QHIWD,(T1) ; Initilize the interlock word
JUMPE P2,RTN ; Jump if just resetting interlocks
OPSTR <MAP T2,>,QHFLI,(T1) ; Get physical addr of command queue flink
TXZ T2,ADRMSK ; Clear junk
STOR T2,QHFLI,(T1) ; Make flink point to itself
STOR T2,QHBLI,(T1) ; Make blink point to flink
SETZRO QHLEN,(T1) ; Clear the length/reserved word
RET
SUBTTL Assign protocol type
; This routine assigns the protocol type in UNPRO on the channel in UNCHN
; in an interlocked manner.
ASGPRO: LOAD T1,UNCHN,(UN) ; Get the channel number from the UN block
CALL FNDCHN ; Lookup that channel
ERROR UNNSC% ; No such channel
STOR T1,PRCHN,(PR) ; Save the channel block address in portal
MOVE PS,T1 ; Setup channel block pointer
NIOFF ; Disable interrupts for a while
CALL NIEPT ; Try to enable the protocol type
JRST ONRET ; Got an error, NION & return failure
ONRSKP: NION ; Enable the interrupts
RETSKP ; And return success
NIEPT: LOADE T1,UNPRO,(UN) ; Get the protocol type
CAML T1,[-3] ; Less than the smallest legal protocol type
CAILE T1,177777 ; Or greater than the largest legal?
ERROR UNIVP% ; Yes, invalid protocol type
CALL FNDPT ; Try to find it
SKIPA ; Not there, good
ERROR UNPIU% ; Protocol already in use
STOR T1,PRPRO,(PR) ; Store the protocol type
STOR T2,PRFQA,(PR) ; Save free q address for NISRB
STOR T1,PTTYP,(T2) ; Put the protocol type into the PTT
SETZRO PTFRE,(T2) ; Entry is no longer free
SETONE PTENA,(T2) ; Enable this entry
CAMN T1,[-3] ; Unknown mode?
RETSKP ; Yes, all done
CAME T1,[-2] ; Promiscuous mode?
IFSKP. ; Yes...
SETONE <PSPMC,PSPRM>,(PS) ; Set promiscuous mode & all multicast
SETONE <PSVPM,PSVPR>,(PS) ; Indicate these bits are valid
CALL NIWSI ; Tell the KLNI about them
RETSKP ; All done!
ENDIF.
CALL LDPTT ; Tell the channel about it
RETSKP ; And return successful
SUBTTL DISABLE A PROTOCOL TYPE
;+
; THIS ROUTINE IS CALLED BY THE DLL TO DISABLE A PROTOCOL TYPE
;
; RETURNS +1: ERROR
; +2: PROTOCOL DISABLED
;-
NIDPT: NIOFF ; No interrupts
SAVEAC <P1,P2>
LOAD P1,PRFQA,(PR) ; Get the PTT entry address
JUMPLE P1,ILLPTY ; Error if .LE. 0
JE PTENA,(P1),ILLPTY ; Error if protocol type wasn't enabled
LOADE P2,PRPRO,(PR) ; Get the protocol type from portal block
SKIPGE P2 ; Is it one of the funny ones?
IFSKP. ; No, perform a sanity check
LOAD T2,PTTYP,(P1) ; Get protocol type from PTT
CAME P2,T2 ; Do they match?
JRST ILLPTY ; No, error
ENDIF.
SETZRO PTENA,(P1) ; Disable the protocol type
LOAD T2,PTVIR,(P1) ; Get virtual address of free buffer list
SETZRO QHLEN,(T2) ; Zero the length
SKIPL P2 ; Unknown or promiscuous?
CALL LDPTT ; No, load a new PTT
CAME P2,[-2] ; Promiscuous?
IFSKP. ; Yes, disable it in the KLNI
SETZRO <PSPMC,PSPRM>,(PS) ; Clear promiscuous mode & all multicast
CALL NIWSI ; Tell the KLNI about them
ENDIF.
; Free up all receive buffers
NIDPT2: LOAD T1,PTVIR,(P1) ; Get address of free queue header interlock
CALL REMQUE ; Get something off the queue
JRST NIDPT1 ; Nothing on the queue
MOVX T1,UNRAB% ; Get the receive abort error code
STOR T1,CMERC,(CM) ; Put it into the response
CALL MSGAV2 ; Return the message to it's owner
NOP
JRST NIDPT2 ; Look for more
NIDPT1: SETONE PTFRE,(P1) ; Indicate that the entry is free
; Disable all multicasts associated with this portal
NIDPT3: OPSTR <SKIPN T2,>,PRMUL,(PR) ; Get the enabled multicast bit table
JRST ONRSKP ; Nothing enabled, just return
JFFO T2,.+1 ; Find the MTT table offset for this bit
OPSTR <ADD T3,>,PSMTT,(PS) ; Point to the MTT entry
CALL NIDRA2 ; Disable this address
BUG. (HLT,KNIADE,PHYKNI,SOFT,<PHYKNI - Multicast address disable error>,,<
Cause: NIDPT got an error from NIDRA when attempting to disable a multicast
address that was supposedly enabled.
>)
JRST NIDPT3 ; Go look for more addresses
SUBTTL NISRA - Specify receive address
;+
; THIS ROUTINE IS CALLED BY THE DLL TO SPECIFY A MULTICAST ADDRESS.
; STANDARD SETUP.
;
; RETURNS +1: ERROR
; +2: ADDRESS ASSIGNED
;
;-
NISRA: SAVEAC P1
CALL FETADR ; Fetch the multicast address from UNDAD
TXNN T1,1B7 ; Is it really a multicast address?
ERROR UNIMA% ; Nope, quit now
NIOFF ; Interlock search and set of multicast table
CALL FNDMT ; Is it already enabled?
IFNSK. ; Nope, set it and enable it
; Not already enabled, setup the MTT slot and tell the KLNI about it
JUMPE T3,[NION ; Jump if no free slots
ERROR UNNRE%] ; No room for entry
; Found a free entry, set the multicast address
OPSTR <DMOVEM T1,>,MTHAD,(T3) ; Install the multicast address
SETONE MTENA,(T3) ; Set the enable bit
MOVE P1,T3 ; Save address of MCAT entry
MOVX T1,NF.EMA ; Indicate we are enabling multicast address
CALL LDMCT ; Tell KLNI about the change
MOVE T3,P1 ; Restore the address of the MCAT entry
ENDIF.
MOVE T2,T3 ; Get a copy of the base address
OPSTR <SUB T2,>,PSMTT,(PS) ; Subtract base address of table
MOVNS T2 ; Shifting right
MOVX T1,1B0 ; Get a single bit
LSH T1,(T2) ; Shift it into place
OPSTR <TDNE T1,>,PRMUL,(PR) ; Does he have this enabled?
JRST ONRSKP ; Yes, don't do it again
OPSTR <IORM T1,>,PRMUL,(PR) ; Add this address to the table
INCR MTUSE,(T3) ; Increment the use count for this address
NION ; Enable the interrupts
RETSKP ; Return to caller
SUBTTL NIDRA - Disable a multicast address
;+
; THIS ROUTINE IS CALLED TO DISABLE A MULTICAST ADDRESS
;
;-
NIDRA: CALL FETADR ; Fetch the Ethernet address
TXNN T1,1B7 ; Is it really a multicast address?
ERROR UNIMA% ; Nope, quit now
NIOFF ; Disable interrupts
CALL NIDRA1 ; Do the work
JRST ONRET ; Enable interrupts & pass error upwards
JRST ONRSKP ; Enable interrupts & Skip return
NIDRA1: CALL FNDMT ; Try to find it
ERROR UNANE% ; Address not enabled
; The address is in the MTT, see if this portal has the address enabled
NIDRA2: ; Here from NIDPT
MOVE T1,T3 ; Get a copy of the MTT entry address
OPSTR <SUB T1,>,PSMTT,(PS) ; Subtract base address of MTT
MOVNS T1 ; Make offset negative (for right shift)
MOVX T2,1B0 ; Get a single bit
LSH T2,(T1) ; Shift it into place
OPSTR <TDNN T2,>,PRMUL,(PR) ; Is this protocol type enabled?
ERROR UNANE% ; Address not enabled
OPSTR <ANDCAM T2,>,PRMUL,(PR) ; Turn off the bit in his table
DECR MTUSE,(T3) ; Decrement the use count
JN MTUSE,(T3),RSKP ; Jump if use count is non-zero
; Here when we have to disable the multicast address
SETZRO MTENA,(T3) ; Disable the address
CALL LDMCT ; Tell KLNI about the change
RETSKP ; And return success
SUBTTL FNDMT - Find enabled MTT entry for a given multicast address
; Find the MTT entry associated with a given mulitcast address. If the
; address is not found, return the address of the first free MTT slot, or
; 0 if none are available.
;
; Call: MOVX T1,high_order_addr
; MOVX T2,low_order_addr
; CALL FNDMT
; <Return +1, address not found,
; T1 & T2/ untouched, T3/ addr of 1st free MTT slot or 0>
; <Return +2, success,
; T1 & T2/ untouched, T3/ addr of MTT slot containing mcast>
;
FNDMT: SAVEAC <P1,P2,P3>
DMOVE P1,T1 ; Put the address in a safe place
SETZ P3, ; Clear the free MTT entry indicator
LOAD T3,PSMTT,(PS) ; Get the MTT base address
MOVX T4,NMTT ; Number of supported multicast addresses
DO. ; Loop over the whole table
TMNN MTENA,(T3) ; Is this entry enabled?
IFSKP. ; Yes, see if it matches
OPSTR <DMOVE T1,>,MTHAD,(T3) ; Get the address
TRZ T1,17 ; Mask it down
TXZ T2,3777777 ; Mask the low order
CAMN T1,P1 ; High order match?
CAME T2,P2 ; Low order match?
TRNA ; No to either
JRST FNDMT1 ; Yes, quit the loop
ELSE. ; Entry not enabled
SKIPN P3 ; Do we have a free entry yet?
MOVE P3,T3 ; No, use this one
ENDIF.
ADDI T3,MT.LST ; Advance to next
SOJG T4,TOP. ; Loop for all
ENDDO.
MOVE T3,P3 ; Get the first free entry
DMOVE T1,P1 ; Get the mulitcast address back
RET ; Return failure
FNDMT1: DMOVE T1,P1 ; Restore the address
RETSKP ; Return success
SUBTTL BUILD LOAD TABLES COMMANDS
;+
; THESE ROUTINES ARE CALLED TO TELL THE KLIPA THAT EITHER THE MULTICAST
; ADDRESS TABLE OR THE PROTOCOL TYPE TABLE HAS CHANGED.
;
; RETURNS +1: ALWAYS
;-
LDMCT: SETZ CM, ; First get a 0
NIOFF ; No interrupts please
OPSTR <EXCH CM,>,PSLMT,(PS) ; Acquire command queue entry
SKIPE CM ; Is the buffer in use?
IFSKP. ; Yes, set indicator for later
SETONE PSLMC,(PS) ; Set flag to do later
NION ; OK to interrupt again
RET ; Give good return
ENDIF.
NION ; Enable interrupts
MOVEI T1,OP.LDM ; Opcode for load multicast address table
STOR T1,CMOPC,(CM) ; Save it
CALLRET QUECMD ; Queue the command
; Response to load multicast table command
LMCRES: STOR CM,PSLMT,(PS) ; Give buffer back
TMNN PSLMC,(PS) ; Do we have a deferred one?
RETSKP ; Nope, all done
SETZRO PSLMC,(PS) ; Yes, clear the deferral flag
CALLRET LDMCT ; Go load the table again
SUBTTL LDPTT - Load Protocol Type Table
; Setup the protocols that the KLNI should be sensitive to.
LDPTT: SETZ CM, ; First get a 0
NIOFF ; No interrupts please
OPSTR <EXCH CM,>,PSLPT,(PS) ; Acquire command queue entry
SKIPE CM ; Is the buffer in use?
IFSKP. ; Yes, set indicator for later
SETONE PSLPP,(PS) ; Set flag to do later
NION ; OK to interrupt again
RET ; Give good return
ENDIF.
NION ; Enable interrupts
MOVEI T1,OP.LDP ; Opcode for loading protocol type table
STOR T1,CMOPC,(CM) ; Save it
CALLRET QUECMD ; Queue the command
; Here for response from load PTT command
LPTRES: STOR CM,PSLPT,(PS) ; Give buffer back
TMNN PSLPP,(PS) ; Do we have a deferred one?
RETSKP ; Nope, all done
SETZRO PSLPP,(PS) ; Yes, clear the deferral flag
CALLRET LDPTT ; Go load the table again
SUBTTL NIWSI - Write station information
; This routine is called to transfer a new set of KLNI variables into the
; KLNI. The variables transferred are:
;
; PSHAD/LAD - Channel Ethernet address
; PSCRC - Allow CRC errors
; PSPMC - Promiscuous multicast mode
; PSH40 - H4000 mode
; PSPRM - Promiscuous mode
; PSRTY - # of retries for various operations
NIWSI: SETZ CM, ; First get a 0
NIOFF ; No interrupts please
OPSTR <EXCH CM,>,PSWSI,(PS) ; Acquire command q entry for WSI
SKIPE CM ; Is the buffer in use?
IFSKP. ; Yes, set indicator for later
SETONE PSLSI,(PS) ; Set flag to do it later
NION ; OK to interrupt again
RET ; Give good return
ENDIF.
NION ; Enable interrupts
LOAD T2,PSHAD,(PS) ; Get channel's Ethernet address to set
STOR T2,WSHAD,(CM) ; Store it in the command
LOAD T2,PSLAD,(PS) ; Get low order
STOR T2,WSLAD,(CM) ; Save it
MOVEI T1,OP.WSI ; Get the command opcode
STOR T1,CMOPC,(CM) ; Store the opcode
LOAD T1,PSVAR,(PS) ; Get current mode bits
STOR T1,WSVAR,(CM) ; Save them in the command
MOVX T1,NRETRY ; Get the number of retrys allowed
STOR T1,WSRTY,(CM) ; And save it
CALLRET QUECMD ; Queue the command
; Here when done with Write Station Info command. Copy the variables we just
; set in the KLNI into the monitor's shadow variables.
WRTNSA: OPSTR <DMOVE T1,>,WSHAD,(CM) ; Get the station address
OPSTR <DMOVEM T1,>,PSSAD,(PS) ; Put it into the shadow area
LOAD T1,WSVAR,(CM) ; Get the variables
STOR T1,PSSVA,(PS) ; Put them in the shadow area
STOR CM,PSWSI,(PS) ; Give the WSI command back
TMNN PSLSI,(PS) ; Do we have a deferred command?
RETSKP ; Nope, all done
SETZRO PSLSI,(PS) ; Yes, clear the deferral flag
CALLRET NIWSI ; Go load the variables again
SUBTTL LOGERR GENERATE ERROR.SYS ENTRIES
LOGERR: SAVEAC <P2,P3,P5> ; Save a P
MOVX T1,KP%LEN ; Size of KLIPA entry
MOVX T2,KP%SIZ ; Size of strings
CALL ALCSEB ; Get the SEB
RET ; No memory, give up for now
LOAD P5,PSCBA,(PS) ; Get CBUS address
LSH P5,2 ; * 4 (Length of channel logout area)
MOVE P3,T1 ; Put SEB pointer into a safe place
LOAD P2,PSPCB,(PS) ; Get PCB address into a safe place
MOVE T2,[-SEBTSZ,,SEBTAB] ; Get arg for SEBCPY
CALL SEBCPY ; Copy the easy stuff
JFCL ; Really shouldn't happen
LOAD T1,PSUED,(PS) ; Get microcode version
IORX T1,KP%NI ; Indicate this is an NI
MOVEM T1,SEBDAT+KP%VER(P3) ; Save the version info
MOVE T1,P3 ; Restore SEB address
CALLRET QUESEB ; And queue up the SEB
SEBTAB: ;SEBPTR offset,type(SBT{WD,STR,EVC,FNA}),data
SEBPTR 0,SBTEVC,SEC%KP ; KLIPA event
SEBPTR KP%CSR,SBTWD,P1 ; CONI
; SEBPTR KP%VER,SBTWD,PS.UCV(PS) ; Microcode version
SEBPTR KP%DSP,SBTWD,PS.TPC(PS) ; Error disposition
SEBPTR KP%CRA,SBTWD,PS.LAR(PS) ; CRAM address
SEBPTR KP%CRD,SBTWD,PS.CRL(PS) ; CRAM data left (1'st 30 bits)
SEBPTR KP%CRD+1,SBTWD,PS.CRR(PS); CRAM data right (next 30 bits)
SEBPTR KP%LG0,SBTWD,KIEPT+0(P5) ; Channel logout word 0
SEBPTR KP%LG1,SBTWD,KIEPT+1(P5) ; Channel logout word 1
SEBPTR KP%LG2,SBTWD,KIEPT+2(P5) ; Channel logout word 2
SEBPTR KP%ECW,SBTWD,PB.CCW(P2) ; CCW at time of error
SEBPTR KP%PE0,SBTWD,PB.ER0(P2) ; First PCB error logout word
SEBPTR KP%PE1,SBTWD,PB.ER1(P2) ; Second PCB error logout word
SEBTSZ==.-SEBTAB
SUBTTL COMMON BUGS
ILLPTY: BUG. (HLT,KNIIPT,PHYKNI,SOFT,<PHYKNI - Illegal protocol type on close>,<<T1,PTYPE>>,<
Cause: A protocol type was specified on the close that was NOT enabled.
Data: PTYPE - The specified protocol type.
>)
RET
QEMPTY: BUG. (CHK,KNIQUE,PHYKNI,SOFT,<PHYKNI - Queue empty on entry>,<<T1,QUE>>,<
Cause: A queue was empty when the routine REMQUE was called.
Data: QUE - The queue header address.
>)
RET
UNKRES: BUG. (HLT,KNIUOP,PHYKNI,HARD,<PHYKNI - Unknown response>,<<T1,RESP>>,<
Cause: The port gave us a response we don't know about.
Data: RESP - Response
>)
RET
ILLFNC: BUG. (CHK,KNIIFD,PHYKNI,SOFT,<PHYKNI - Illegal function from DLL>,<<T1,PASED>,<T2,BLKADR>,<T3,FNC>>,<
Cause: The NIDLL called the driver with a function we don't handle yet.
Data: BLKADR -The function block address.
FNC - The function code
>)
RET
NOCTL: BUG. (HLT,KNINIB,PHYKNI,SOFT,<PHYKNI - No control buffer at interrupt level>,,<
Cause: The Port Storage (PS) block was not set up with the address of a UN
block to be used at interrupt level.
>)
RET
VMCBUG: BUG. (CHK,KNIIAM,PHYKNI,SOFT,<PHYKNI - Illegal addressing mode>,<<T2,ADR>>,<
Cause: An illegal addressing mode was specified.
Data: ADR - The mode specfied.
>)
RET
SUBTTL Miscellaneous routines
; Swap the right justified bytes in T1
SWAB: DPB T1,[POINT 8,T1,19] ; Move the bottom byte to the top
LSH T1,-8 ; Right justify the whole mess
RET
SWAP6B: MOVE T2,(T1) ; Get 1st word of bytes
LSHC T2,-^D12 ; Put 1st byte at top of T3
DPB T2,[POINT 8,T3,15] ; Put 2nd byte next
DPB T2,[POINT 16,T3,31] ; Put 3rd byte next
LSH T2,-^D16 ; Put last byte into position
DPB T2,[POINT 8,T3,31] ; Put in 4th byte
MOVE T1,1(T1) ; Get 2nd word of bytes
LSHC T1,-^D12 ; Isolate 5th and 6th bytes
DPB T1,[POINT 8,T2,15] ; Put 6th byte into place
MOVE T1,T3 ; Get 1 thru 4 into T1
TRZ T1,17 ; Clear unwanted bits in high address
TDZ T2,[000003,,-1] ; Clear unwanted bits in low address
RET ; And return (that wasn't so bad!)
; Fetch an Ethernet address from a UN block.
FETADR: JN UNPTR,(UN),FETAD1 ; Jump if user supplied a byte pointer
; Immediate address
OPSTR <DMOVE T1,>,UNDAD,(UN) ; Get the address
TXZ T1,17
TXZ T2,3777777
RET
FETAD1: OPSTR <DMOVE T3,>,UNDAD,(UN) ; Fetch byte pointer
ILDB T1,T3 ; Byte 0
LSHC T1,-8 ; Put it into place
ILDB T1,T3 ; Byte 1
LSHC T1,-8 ; Shift it in
ILDB T1,T3 ; Byte 2
LSHC T1,-8 ; Shift it in
ILDB T1,T3 ; Byte 3
LSHC T1,-12 ; Shift it in & right justify 0-3
ILDB T1,T3 ; Byte 4
ILDB T3,T3 ; Byte 5
DPB T3,[POINT 8,T1,19] ; Install byte 5
LSH T1,-8 ; Right justify 4 & 5 into place
EXCH T1,T2 ; Correct the order
RET
RSI (NIPIFG,-1) ; Indicates NI interrupts are off
.NIOFF: CONSO PI,PIPIIP ; Are we at interrupt level?
NOSKED ; No, disable the scheduler
CHNOFF NIPIA ; Disable the KLNI channel
AOS NIPIFG ; Indicate another nested interlock
RET ; And return to caller
.NION: SOSGE NIPIFG ; Should we enable the interrupts?
CHNON NIPIA ; Enable the KLNI interrupt channel
CONSO PI,PIPIIP ; Are we at interrupt level?
OKSKED ; No, don't forget to enable the scheduler
RET
SUBTTL History buffer routines
IFN FTHIST,<
..FOO==.
PHASE 0
.HBFCN:! BLOCK 1 ; Function code
.HBUNA:! BLOCK 1 ; UN block address
.HBPC:! BLOCK 1 ; PC of the caller
.HBCPI:! BLOCK 1 ; CONI PI,
.HBTIM:! BLOCK 2 ; Two word RDTIME value
.HBUNB:! BLOCK UN.SPI ; UN block
.HBLEN:! BLOCK 0 ; Total length
DEPHASE
RELOC ..FOO
RSI UNBUFF,0 ; Pointer to start of recording buffer
RSI UNNEXT,0 ; Pointer to next useable HB block
RSI UNLAST,0 ; Pointer to last useable HB block
RSI NUMUNB,0 ; Number of HB blocks to allocate
; Record UN block. Arguments: T1/ fcn code, T2/ UN block pointer
; Uses no AC's.
RECUNB: SKIPN UNBUFF ; Buffer initialized?
CALL INIUNB ; Nope, go init the buffer
PUSH P,T1 ; Save our work AC's
PUSH P,T2
PUSH P,T3
PIOFF ; Absolutely no interrupts, please
MOVE T3,UNNEXT ; Get pointer to next free slot
CAMLE T3,UNLAST ; Are we beyond the end?
MOVE T3,UNBUFF ; Yes, reset to the beginning
MOVEM T3,UNNEXT ; Save the pointer
DMOVEM T1,.HBFCN(T3) ; Save function code & un block address
MOVEI T1,UN.SPI ; Setup length of transfer
ADDI T3,.HBUNB ; Point to dest address
EXTEND T1,[XBLT] ; Copy the UN block into the buffer
MOVE T3,UNNEXT ; Get address buffer (again)
RDTIME .HBTIM(T3) ; Save the current time
MOVE T1,-3(P) ; Get callers PC
MOVEM T1,.HBPC(T3) ; Save it in the UN block
CONI PI,.HBCPI(T3) ; Get the PI's too
ADDI T3,.HBLEN ; Point to next block
MOVEM T3,UNNEXT ; Save it for later
PION ; Enable the interrupts
POP P,T3
POP P,T2
POP P,T1
RET
; Record CM block. Arguments: CM/ Pointer to CM block
; Uses no AC's.
RECCMB: SKIPN UNBUFF ; Buffer initialized?
CALL INIUNB ; Nope, go init the buffer
PUSH P,T1 ; Save our work AC's
PUSH P,T2
PUSH P,T3
PIOFF ; Absolutely no interrupts, please
MOVE T3,UNNEXT ; Get pointer to next free slot
CAMLE T3,UNLAST ; Are we beyond the end?
MOVE T3,UNBUFF ; Yes, reset to the beginning
MOVEM T3,UNNEXT ; Save the pointer
SETOM .HBFCN(T3) ; Make function code look invalid
MOVEM CM,.HBUNA(T3) ; Save command block address
MOVEI T1,UN.SPI ; Setup length of transfer
MOVE T2,CM ; Get address of command block
ADDI T3,.HBUNB ; Point to dest address
EXTEND T1,[XBLT] ; Copy the CM block into the buffer
MOVE T3,UNNEXT ; Get address buffer (again)
RDTIME .HBTIM(T3) ; Save the time in the buffer
MOVE T1,-3(P) ; Get callers PC
MOVEM T1,.HBPC(T3) ; Save it in the UN block
CONI PI,.HBCPI(T3) ; Get the PI's too
ADDI T3,.HBLEN ; Point to next block
MOVEM T3,UNNEXT ; Save it for later
PION ; Enable the interrupts
POP P,T3
POP P,T2
POP P,T1
RET
SUBTTL Initialize the history buffer
; Still under IFN FTHIST
INIUNB: SKIPN NUMUNB ; Want to record UN blocks?
JRST [ADJSP P,-1 ; Pop call off the stack
RET] ; And return
SAVET ; Preserve all T's
MOVE T1,NUMUNB ; Get number of UN block desired
IMULI T1,.HBLEN ; Convert to words
HRLI T1,.RESP1 ; Priority 1
MOVX T2,.RESGP ; From the general pool
CALL ASGRES ; Get the memory
RET
PIOFF
MOVEM T1,UNBUFF ; Install pointer to UN buffer
MOVEM T1,UNNEXT ; Install pointer to next block
MOVE T2,NUMUNB ; Get number of UN blocks
IMULI T2,.HBLEN ; Convert it to words
ADD T1,T2 ; Point to end of buffer
SUBI T1,.HBLEN ; Point to last HB block
MOVEM T1,UNLAST ; Save it
PION
RET
>; End of IFN FTHIST
SUBTTL FNDCHN - Find channel block associated with channel # in UNCHN
; Call: MOVX T1,channel #
; CALL FNDCHN
; <Error return, invalid channel #>
; <Good return, PS block addr in T1>
FNDCHN: SKIPA T2,CHNBAS ; Get channel list base address
FNDCH1: LOAD T2,PSNXT,(T2) ; Get next channel block
JUMPE T2,RTN ; Jump if we reached the end
OPSTR <CAME T1,>,PSCHN,(T2) ; Do the channel numbers match?
JRST FNDCH1 ; No, try again
MOVE T1,T2 ; Put block address into T1
RETSKP ; Yes, return success
; ALLCHN is a co-routine that will loop through all channels in existence.
; Skip and non-skip returns are treated the same.
ALLCHN: SKIPA PS,CHNBAS ; Get base of channel list
ALLCH1: LOAD PS,PSNXT,(PS) ; Get next channel block
JUMPE PS,ALLCH2 ; Jump when we reach end of list
CALL @(P) ; Call back the caller
NOP ; Ignore skip/non-skip
JRST ALLCH1 ; Loop for the rest
ALLCH2: ADJSP P,-1 ; Pop the caller off the stack
RET ; and return to his caller
; ALLCHE is the same as ALLCHN except that it will terminate on errors
; (non-skip returns) and pass skip returns back to it's callers.
ALLCHE: SKIPA PS,CHNBAS ; Get base of channel list
ALLCE1: LOAD PS,PSNXT,(PS) ; Get next channel block
JUMPE PS,ALLCE2 ; Jump when we reach end of list
CALL @(P) ; Call back the caller
TRNA ; Got an error, propagate it upwards
JRST ALLCE1 ; Loop for the rest
ADJSP P,-1 ; Pop the caller off the stack
RET ; and return error to the caller
ALLCE2: ADJSP P,-1 ; Pop the caller off the stack
RETSKP ; and return success to his caller
; The following instruction is used by the routine REDLIS in NISRV for
; fetching the channel number from a PS block.
CHNFET: LOAD T1,PSCHN,(PR)
;**;[7134] Add routine XCKNI CEG 15-AUG-85
;XCKNI - STOP THE NI PORT
; CALL XCKNI ;(/)
; RETURNS +1
RESCD
XCKNI:: SKIPE NIHERE ;[7134] NI IN USE?
CONO KNI,CO.CPT ;[7134] YES, SHOOT IT
RET ;[7134]
TNXEND
END