1 /****^  ***********************************************************
   2         *                                                         *
   3         * Copyright, (C) Honeywell Bull Inc., 1988                *
   4         *                                                         *
   5         * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   6         *                                                         *
   7         * Copyright (c) 1972 by Massachusetts Institute of        *
   8         * Technology and Honeywell Information Systems, Inc.      *
   9         *                                                         *
  10         *********************************************************** */
  11 
  12 
  13 /****^  HISTORY COMMENTS:
  14   1) change(88-06-13,Berno), approve(88-07-13,MCR7928),
  15      audit(88-06-13,Parisek), install(88-07-19,MR12.2-1061):
  16      Created to implement the uncp multiplexer interface.
  17                                                    END HISTORY COMMENTS */
  18 
  19 /* format: style4,delnl,insnl,^ifthendo */
  20 uncp_util:
  21      procedure;
  22 
  23 /* This procedure contains entries called through hphcs_ used to load and dump an
  24    *  FNP. The "wire" entry is used to wire the segment containing the core image so that
  25    *  DIA I/O will be possible; the "load" entry initiates the bootload I/O; the
  26    *  "release" entry releases the aste of the coreimage.
  27    *  The "fdump" entry dumps all of FNP memory into a segment supplied
  28    *  by the caller.
  29    *
  30    *  Written 5/19/76 by Robert S. Coren
  31    *  Modified 10/28/76 by Robert S. Coren to save version number and report core image name
  32    *  Modified 04/15/77 by Robert S. Coren to correct bug in queue buffer freeing
  33    *  Modified 9/27/78 by J. Stern for multiplexing changes
  34    *  Modified 79 May 14 by Art Beattie to get memory size and FNP type from caller for fdump entry.
  35    *  Modified April 1981 by Chris Jones for io_manager conversion
  36    *  Modified February 1982 by C. Hornig for MR10 io_manager.
  37    *  Modified 830714 BIM to remove the release entrypoint. abort is suffcient.
  38    *  Modified 83-12-20 BIM for reconfiguration.
  39    *  Modified 84-05-18 BIM for better maintenance of io_manager_assigned bit.
  40    *  Modified 1984-08-02 BIM for code return from load.
  41    *  Modified 1984-07-26 BIM for paged I/O on loads.
  42    *  Modified 1985-01-29, BIM: fix dump_mpx to leave chn unassigned.
  43    *  Modified 1985-03-12, E. Swenson to fix unitialized timeout flag to
  44    *     prevent spurious timeout errors.
  45 
  46    *  THE FOLLOWING HISTORY COMMENTS REFER TO UNCP IMPLEMENTATION, AS THIS
  47    *  WAS ORIGINALLY A COPY OF dn355_util.
  48 
  49    *  Modified in September 1985 for MR11.
  50    *  Modified in December 1986 for DSA-compact. fd
  51    *  Modified in January 1987 for MR12.0
  52    *  Modified in June and July 1987
  53 
  54    *  Date of the last modification  07/07/87.
  55 */
  56 
  57 
  58 /* PARAMETERS */
  59 
  60 /* Added the DN7100   */
  61 dcl  a_data_ptr ptr;
  62 dcl  cent fixed bin (15) unsigned init (1);                 /* DN7100 address modulo 128 */
  63 dcl  un fixed bin (12) unsigned init (1);                   /* Transfer of a word */
  64 dcl  a_devx fixed bin;                                      /* ioam release param */
  65 dcl  a_fnp_no fixed bin;
  66 dcl  a_fnp_mem_size fixed bin;                              /* FNP memory size in 1024 18-bit words */
  67 dcl  a_fnp_type fixed bin;
  68 dcl  a_ptr ptr;
  69 dcl  a_count fixed bin;                                     /* number of words to wire */
  70 dcl  a_code fixed bin (35);                                 /* OUTPUT */
  71 dcl  a_ev_chan fixed bin (71);
  72 dcl  a_absadr fixed bin (24);                               /* OUTPUT from wire and info, INPUT to load */
  73 dcl  norm_int_cell fixed bin;                               /* OUTPUT */
  74 dcl  emergency_int_cell fixed bin;                          /* OUTPUT */
  75 dcl  a_ints bit (2) aligned;                                /* OUTPUT rcvd interrupts */
  76 dcl  a_level fixed bin (3);                                 /* INPUT level on which to interrupt fnp */
  77 dcl  a_fnp_addr fixed bin (15);                             /* INPUT data address in fnp */
  78 
  79 /* AUTOMATIC */
  80 
  81 dcl  auto_absadr fixed bin (24);
  82 dcl  fnp_no fixed bin;
  83 dcl  fnp_mem_size fixed bin;
  84 dcl  fnp_type fixed bin;
  85 dcl  fnp_addr fixed bin (15);
  86 dcl  opcode bit (6) aligned;
  87 dcl  temp_fnp_name char (32);
  88 dcl  segptr ptr;
  89 dcl  nwords fixed bin;
  90 dcl  code fixed bin (35);
  91 dcl  devx fixed bin;
  92 dcl  abs_addr_string bit (24);                              /* representation of absolute address as bit string */
  93 dcl  i fixed bin;
  94 dcl  abs_address fixed bin (26);
  95 dcl  data_ptr ptr;
  96 dcl  offset fixed bin;
  97 dcl  fnp_tally fixed bin;
  98 dcl  start_time fixed bin (71);
  99 dcl  version char (4);
 100 dcl  load_info_ptr ptr;
 101 dcl  locked bit (1) aligned init ("0"b);
 102 dcl  config_locked bit (1) aligned init ("0"b);
 103 
 104 declare  message fixed bin (71);
 105 declare  1 auto_fnp_msg aligned like fnp_msg;
 106 
 107 /* Ajoute pour le DN 7100  */
 108 
 109 
 110 /* BUILTINS */
 111 
 112 dcl  (addr, addrel, addwordno, baseno, bin, bit, clock, divide, fixed, min,
 113      null, segno, string, substr, unspec) builtin;
 114 
 115 
 116 /* ENTRIES */
 117 
 118 dcl  config_$find_2 entry (character (4) aligned, character (4) aligned, pointer);
 119 dcl  uncp_multiplexer$assign entry (fixed binary, fixed binary (35));
 120 dcl  uncp_multiplexer$unassign entry (fixed binary, fixed binary (35));
 121 dcl  uncp_multiplexer$fnp_lock entry (pointer, fixed binary (35));
 122 dcl  uncp_multiplexer$fnp_unlock entry (pointer);
 123 dcl  get_fnp_name_ entry (fixed bin) returns (char (32));
 124 dcl  ioam_$assign entry (fixed bin, entry, fixed bin (35));
 125 dcl  ioam_$unassign entry (fixed bin, fixed bin (35));
 126 dcl  priv_channel_manager$get_devx entry (char (*), fixed bin, fixed bin (35));
 127 dcl  dn355_util$compute_parity entry (bit (36)) returns (bit (36));
 128 dcl  absadr entry (ptr, fixed bin (35)) returns (fixed bin (24));
 129 dcl  ioi_page_table$get entry (fixed binary (19), fixed binary, fixed binary (35));
 130 dcl  ioi_page_table$ptx_to_ptp entry (fixed binary) returns (pointer);
 131 dcl  ioi_page_table$put entry (fixed binary, fixed binary (35));
 132 dcl  pxss$notify entry (fixed bin);
 133 dcl  pxss$addevent entry (fixed bin);
 134 dcl  pxss$delevent entry (fixed bin);
 135 dcl  pxss$wait entry;
 136 dcl  pxss$ring_0_wakeup entry (bit (36) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
 137 dcl  get_ptrs_$given_segno entry (fixed bin) returns (ptr);
 138 dcl  uncp$interrupt entry;
 139 dcl  uncp$send_global_wcd entry (ptr, fixed bin (8), fixed bin, bit (*) aligned);
 140 dcl  syserr entry options (variable);
 141 dcl  syserr$error_code entry options (variable);
 142 dcl  lock$wait entry (ptr, char (4) aligned, fixed bin (35));
 143 dcl  lock$lock_fast entry (pointer);
 144 dcl  lock$unlock_fast entry (pointer);
 145 dcl  lock$unlock entry (ptr, char (4) aligned);
 146 dcl  pc_abs$wire_abs_contig entry (ptr, fixed bin, fixed bin, fixed bin (35));
 147 dcl  pc_abs$unwire_abs entry (ptr, fixed bin, fixed bin);
 148 
 149 /* EXTERNAL STATIC */
 150 
 151 dcl  (
 152      error_table_$io_no_permission,
 153      error_table_$invalid_state,
 154      error_table_$bad_mpx_load_data,
 155      error_table_$no_io_interrupt,
 156 /*     error_table_$rqover,*/
 157      error_table_$io_configured,
 158      error_table_$io_not_configured,
 159      error_table_$io_not_assigned,
 160      error_table_$io_not_defined
 161      ) fixed bin (35) ext static;
 162 
 163 dcl  pds$processid bit (36) ext static;
 164 dcl  pds$process_group_id char (32) ext static;
 165 dcl  tc_data$initializer_id bit (36) aligned external static;
 166 dcl  tty_buf$fnp_config_flags (1:8) bit (1) unaligned external static;
 167 dcl  tty_buf$lct_ptr pointer external static;
 168 dcl  sst$astsize fixed bin external;
 169 dcl  sys_info$page_size fixed bin external;
 170 
 171 
 172 /* INTERNAL STATIC */
 173 
 174 dcl  (
 175      FNP_DOWN init (2)
 176      ) fixed bin int static options (constant);
 177 dcl  SIZE_1024 fixed bin int static options (constant) init (1024);
 178 dcl  NORM_CELL fixed bin int static options (constant) init (3);
 179 dcl  EMER_CELL fixed bin int static options (constant) init (7);
 180 dcl  SECONDS_30 fixed bin (35) int static options (constant) init (30000000);
 181 dcl  MIN_TALLY fixed bin int static options (constant) init (308);
 182 dcl  BIT_75 bit (6) int static options (constant) init ("75"b3);
 183 dcl  BIT_76 bit (6) int static options (constant) init ("76"b3);
 184 dcl  SIZE_256 fixed bin int static options (constant) init (256);
 185 dcl  LOW_MBX_PTW fixed bin int static options (constant) init (1);
 186 dcl  HIGH_MBX_PTW fixed bin int static options (constant) init (3);
 187 dcl  fdump_seg_event char (4) aligned init ("fnpd") static options (constant);
 188 dcl  cleanup condition;
 189 
 190 
 191 /* BASED */
 192 
 193 dcl  tally_words (fnp_tally) bit (36) aligned based;
 194 
 195 dcl  1 dump_355_control aligned based (data_ptr),           /* word used to supply 355 address and tally for fdump */
 196        2 address_mode bit (3) unaligned,                    /* always 36-bit addressing ("001"b) */
 197        2 fnp_address bit (15) unaligned,
 198        2 tally fixed bin (17) unaligned;
 199 
 200 dcl  1 dump_6670_control aligned based (data_ptr),          /* word used to supply DN6670 address and tally for fdump */
 201        2 fnp_address fixed bin (18) unsigned unaligned,
 202        2 unpaged bit (1) unaligned,
 203        2 mbz bit (5) unaligned,
 204        2 tally fixed bin (12) unsigned unaligned;
 205 
 206 dcl  1 load_info aligned based (load_info_ptr),             /* used to assign baud rates and line types at bootload time */
 207        2 ev_chan fixed bin (71),
 208        2 no_entries fixed bin,
 209        2 entries (0 refer (load_info.no_entries)),
 210          3 devx fixed bin,
 211          3 baud_rate fixed bin,
 212          3 line_type fixed bin,
 213        2 version char (4),                                  /* version number of the DNS software */
 214        2 pointeur_image_dns ptr,                            /* pointer to the beginning of the segment   */
 215        2 image fixed bin (24),                              /* memory size */
 216        2 etape fixed bin;                                   /* Stages of loading */
 217                                                             /* 1 - It is assumed that the Datanet is already loaded */
 218                                                             /* 2 - It loads the Datanet from Multics */
 219                                                             /* 3 - Loading the Datanet from diskette */
 220 
 221 /* Added for the DN7100 */
 222 dcl  1 d7100 aligned based (data_ptr),                      /* To give the address and size for clearing of the DN7100. */
 223        2 pcw,
 224          3 adr_mode bit (3) unaligned init ("001"b),
 225          3 fnp_address fixed bin (15) unsigned unaligned,   /* DN7100 address to clear */
 226          3 poids_fort bit (1) unaligned init ("1"b),        /* 1 = strong points (cad X 2**7 ) */
 227          3 pad3 bit (5) unaligned init ("00000"b),
 228          3 tally fixed bin (12) unsigned unaligned,         /* Dimension of the zone to clear */
 229        2 working_location (7) fixed bin (35) unaligned,
 230        2 verrou_mot,
 231          3 pad bit (35) unaligned,
 232          3 verrou bit (1) unaligned,
 233        2 control_information unaligned,
 234          3 pad1 bit (1) unaligned,
 235          3 administrative_header bit (4) unaligned,
 236          3 node_type_ofresponder bit (4) unaligned,
 237          3 pad2 bit (1) unaligned,
 238          3 software_level_of_responder bit (8) unaligned,
 239          3 node_ID_of_responder bit (18) unaligned,
 240          3 Time_of_response bit (36) unaligned,
 241          3 Node_ID_of_originator bit (18) unaligned,
 242          3 pad3 bit (1) unaligned,
 243          3 Origin_type bit (8) unaligned,
 244          3 pad4 bit (1) unaligned,
 245          3 Specific_origin bit (8) unaligned,
 246          3 pad5 bit (1) unaligned,
 247          3 RFU bit (8) unaligned,
 248          3 pad6 bit (1) unaligned,
 249          3 Type bit (8) unaligned,
 250          3 pad7 bit (1) unaligned,
 251          3 Class bit (8) unaligned,
 252          3 pad8 bit (1) unaligned,
 253          3 Code bit (8) unaligned,
 254          3 pad8b bit (2) unaligned,
 255          3 Length_of_commmand bit (16) unaligned,
 256          3 pad9 bit (1) unaligned,
 257          3 Format_of_response bit (8) unaligned,
 258          3 pad10 bit (1) unaligned,
 259          3 Importance_level bit (8) unaligned,
 260          3 Length_of_response bit (18) unaligned,
 261          3 S2_link_ident bit (18) unaligned;
 262 
 263 /* This structure is used by the commands RIM, SIM. */
 264 /*
 265 dcl  1 command_parameters aligned based (commandp),
 266        2 S2_link_identification bit (36) unaligned,
 267        2 Argument bit (18) unaligned,
 268        2 command_error unaligned,
 269          3 mode_4 bit (18) unaligned,
 270          3 error_code bit (18) unaligned;
 271 */
 272 /* This structure is used by the command START NODE  */
 273 /*
 274 dcl  1 cmd_parameters aligned based (commandp),
 275        2 S2_link_identification bit (36) unaligned,
 276        2 Starting_address bit (36) unaligned,
 277        2 Option_string_length bit (18) unaligned,
 278        2 Option_string char (2) init ("GO") unaligned,
 279        2 cmd_error unaligned,
 280          3 mode_4 bit (18) unaligned,
 281          3 error_code bit (18) unaligned;
 282 
 283 dcl  commandp pointer;
 284 
 285 dcl  1 format_32 based,
 286        2 rien bit (4) unaligned,
 287        2 bit8_32 (4) bit (8) unaligned;
 288 
 289 dcl  1 format_36 based,
 290        2 bit9 (4),
 291          3 bit0 bit (1) unaligned,
 292          3 bit8_36 bit (8) unaligned;
 293 */
 294 ^L
 295 load:
 296      entry (a_fnp_no, a_data_ptr, a_code);                  /* For the DN7100 */
 297 
 298 
 299 
 300 /* entry to initiate bootload I/O for loading an FNP */
 301 
 302           fnp_no = a_fnp_no;
 303           load_info_ptr = a_data_ptr;
 304           call validate_fnp_ret ("load");
 305           call validate_assigned_ret ("load");
 306 
 307           if datanet_info.trace
 308           then call syserr (ANNOUNCE, "uncp_util$load: FNP ^d ADDR ^o", fnp_no, auto_absadr);
 309 
 310           call assign_interrupt (uncp$interrupt, code);
 311 
 312           if fnp_info.bootloading
 313           then do;                                          /* we can't do it while it's already happening */
 314                code = error_table_$invalid_state;
 315                call syserr (ANNOUNCE, "uncp_util$load: FNP load already in progress for FNP ^a.", fnp_info.fnp_tag);
 316                go to load_return;
 317           end;
 318 
 319 
 320           if fnp_info.running
 321           then do;
 322                code = error_table_$invalid_state;
 323                if datanet_info.trace
 324                then call syserr (ANNOUNCE, "uncp_util$load: FNP ^a is running.", fnp_info.fnp_tag);
 325                go to load_return;
 326           end;
 327 
 328 
 329 /* process the load_info data */
 330 
 331           if load_info.no_entries ^= fnp_info.no_of_channels
 332           then do;
 333 
 334                a_code = error_table_$bad_mpx_load_data;
 335                go to load_return;
 336           end;
 337 
 338           n_pcbs = fnp_info.no_of_channels;
 339 
 340           do i = 1 to load_info.no_entries;                 /* get baud rates to store in pcbs */
 341                pcbp = addr (fnp_info.pcb_array_ptr -> pcb_array (i));
 342                if load_info (i).devx ^= pcb.devx            /* load_info does not match pcb_array */
 343                then do;
 344                     a_code = error_table_$bad_mpx_load_data;
 345                     go to load_return;
 346                end;
 347                pcb.baud_rate = load_info (i).baud_rate;
 348                pcb.line_type = load_info (i).line_type;
 349 
 350 
 351           end;
 352 
 353 /* it's okay to try to load */
 354 
 355           version = "    ";
 356 
 357           fnp_info.boot_ev_chan = load_info.ev_chan;
 358           fnp_info.boot_process_id = pds$processid;
 359           fnp_info.version = version;
 360           fnp_info.fnp_mem_size = fnp_mem_size * SIZE_1024;
 361           fnp_info.bootloading = "1"b;
 362 
 363           datanet_mbx.dia_pcw.command = ""b;                /* last command */
 364           datanet_mbx.mailbox_requests = 0;                 /* clear fields in mbx for this load */
 365           datanet_mbx.term_inpt_mpx_wd = "0"b;
 366           datanet_mbx.last_mbx_req_count = 0;
 367           string (datanet_mbx.mbx_used_flags) = "0"b;
 368 
 369           datanet_mbx.crash_data.fault_code = 0;
 370           datanet_mbx.crash_data.ic = 0;
 371           datanet_mbx.crash_data.iom_fault_status = 0;
 372           datanet_mbx.crash_data.fault_word = 0;
 373 
 374 
 375           ttybp = addr (tty_buf$);
 376           fnp_dump_ptr = addr (fnp_dump_seg$);
 377 
 378 
 379 deux_ten:
 380 send_wcd:
 381 
 382           call uncp$send_global_wcd (fnpp, init_complete, 0, ""b);
 383 
 384 /* Sortie normale meme si l init_complete n a pas ete effective  */
 385 
 386           code = 0;                                         /* all is well so far */
 387           go to fin;
 388 
 389 
 390 unwire_load_buffer:
 391           call unwire_dump_seg;
 392 restore_load_interrupt:
 393           call assign_interrupt (uncp$interrupt, code);     /* let uncp take over interrupts again */
 394 
 395 unlock_load_seg:
 396           call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
 397 ret_bad_load_code:
 398 fin:
 399           a_code = code;
 400           return;
 401 
 402 load_return:
 403           if code ^= 0 & (datanet_info.trace | datanet_info.debug_stop)
 404           then do;
 405                call syserr$error_code (ANNOUNCE, code, "uncp_util$load: Error loading FNP ^a.", fnp_info.fnp_tag);
 406                call STOP_CHECK ("load");
 407           end;
 408           a_code = code;
 409           return;
 410 ^L
 411 
 412 info:
 413      entry (a_fnp_no, a_absadr, norm_int_cell, emergency_int_cell, a_code);
 414 
 415 /* entry called to return address of mailbox area and FNP interrupt cells */
 416 
 417           fnp_no = a_fnp_no;
 418           call validate_fnp_ret ("info");
 419 
 420           a_absadr = absadr (fnp_info.mbx_pt, code);
 421           if code = 0
 422           then do;                                          /* provided everything's ok */
 423                norm_int_cell = NORM_CELL;                   /* customary assignments */
 424                emergency_int_cell = EMER_CELL;
 425           end;
 426 
 427           a_code = code;
 428           return;
 429 ^L
 430 fill_page_table:
 431      entry (a_fnp_no, a_code);
 432 
 433           fnp_no = a_fnp_no;
 434           call validate_fnp_ret ("fill_page_table");
 435           call validate_assigned_ret ("fill_page_table");
 436           if fnp_info.ptx ^= -1 | fnp_info.ptp ^= null ()
 437           then do;
 438                call syserr (ANNOUNCE, "uncp_util$fill_page_table: page table already assigned for FNP ^a.",
 439                     fnp_info.fnp_tag);
 440                call STOP_CHECK ("fill_page_table");
 441           end;
 442           call get_page_table (code);
 443           if code ^= 0 & (datanet_info.trace | datanet_info.debug_stop)
 444           then do;
 445                call syserr$error_code (ANNOUNCE, code, "uncp_util$fill_page_table: ioi_page_table$get failed for FNP ^a.",
 446                     fnp_info.fnp_tag);
 447                call STOP_CHECK ("fill_page_table");
 448           end;
 449           a_code = code;
 450           return;
 451 
 452 free_page_table:
 453      entry (a_fnp_no, a_code);
 454 
 455           fnp_no = a_fnp_no;
 456           call validate_fnp_ret ("free_page_table");
 457           if fnp_info.ptx = -1
 458           then do;
 459                call syserr (ANNOUNCE, "uncp_util$free_page_table: no page table assigned for FNP ^a.", fnp_info.fnp_tag);
 460                go to ret_bad_code;
 461           end;
 462           call ioi_page_table$put (fnp_info.ptx, code);
 463           fnp_info.ptx = -1;
 464           fnp_info.ptp = null ();
 465           a_code = code;
 466           return;
 467 ^L
 468 
 469 /* RECONFIGURATION ENTRYPOINTS */
 470 
 471 /* Configure -- add a FNP to the available collection for assignment */
 472 
 473 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 474    fnp_util$configure. */
 475 
 476 configure:
 477      entry (a_fnp_no, a_code);
 478 
 479           fnp_no = a_fnp_no;
 480           call validate_fnp_ret ("configure");
 481           call lock_fnp;
 482           if fnp_info.available
 483           then do;
 484                code = error_table_$io_configured;
 485                if datanet_info.trace | datanet_info.debug_stop
 486                then call syserr (ANNOUNCE, "uncp_util$configure: FNP ^a already configured.", fnp_info.fnp_tag);
 487                call STOP_CHECK ("configure");
 488                go to configure_return;
 489           end;
 490           fnp_info.available = "1"b;
 491           fnp_info.io_manager_assigned = "0"b;              /* clean up */
 492           fnp_info.flags = "0"b;                            /* state information */
 493 configure_return:
 494           call unlock_fnp;
 495           if code = 0
 496           then do;
 497                call config_$find_2 ("prph", "fnp" || fnp_info.fnp_tag, prph_fnp_cardp);
 498                prph_fnp_card.state = "on";
 499                call syserr (ANNOUNCE, "uncp_util: FNP ^a added to configuration^[ by ^a^].", fnp_info.fnp_tag,
 500                     pds$processid ^= tc_data$initializer_id, pds$process_group_id);
 501           end;
 502           a_code = code;
 503           return;
 504 
 505 /**** Deconfigure -- remove from configuration.
 506       This entrypoint causes a FNP crash for the selected FNP.
 507 */
 508 
 509 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 510    fnp_util$deconfigure. */
 511 
 512 deconfigure:
 513      entry (a_fnp_no, a_code);
 514 
 515           fnp_no = a_fnp_no;
 516           call validate_fnp_ret ("deconfigure");
 517           call lock_fnp;
 518 
 519           if ^fnp_info.available
 520           then do;
 521                code = error_table_$io_not_configured;
 522                go to deconfigure_return;
 523           end;
 524 
 525           fnp_info.available = "0"b;                        /* throttle init_multiplexer */
 526 
 527           if ^fnp_info.io_manager_assigned
 528           then go to deconfigure_return;
 529 
 530           /*** here is the interesting part. What we do depends on who is active */
 531 
 532           if fnp_info.t_and_d_in_progress
 533           then do;
 534                call unlock_fnp;                             /* must lock in correct order */
 535                call release_t_and_d;                        /* unassigns channel */
 536                go to deconfigure_return_unlocked;
 537           end;
 538           else do;
 539                call mask_dia;                               /* stop it from writing to us or sending stuff */
 540                call uncp_multiplexer$unassign (fnp_no, (0));/* has to succeed, we are under lock */
 541                /*** turns off io_manager_assigned for us, nailing io_manager callers */
 542                auto_fnp_msg.fnp_no = fnp_info.fnp_number;
 543                auto_fnp_msg.state = FNP_DOWN;
 544                auto_fnp_msg.flags = "0"b;
 545                auto_fnp_msg.deconfigured = "1"b;
 546                unspec (message) = unspec (auto_fnp_msg);
 547                call pxss$ring_0_wakeup (fnp_info.boot_process_id, fnp_info.boot_ev_chan, message, (0));
 548           end;
 549 
 550           /*** all callers of io_manager must hold LCTE lock and check io_manager_assigned */
 551 
 552 deconfigure_return:
 553           call unlock_fnp;
 554 deconfigure_return_unlocked:
 555           if code = 0
 556           then do;
 557                call config_$find_2 ("prph", "fnp" || fnp_info.fnp_tag, prph_fnp_cardp);
 558                prph_fnp_card.state = "off";
 559                call syserr (ANNOUNCE, "uncp_util: FNP ^a deleted from configuration^[ by ^a^].", fnp_info.fnp_tag,
 560                     pds$processid ^= tc_data$initializer_id, pds$process_group_id);
 561           end;
 562           a_code = code;
 563           return;
 564 ^L
 565 abort:
 566      entry (a_fnp_no, a_code);
 567 
 568 /* entry called to abort bootload */
 569           fnp_no = a_fnp_no;
 570           call validate_fnp_ret ("abort");
 571           fnp_info.bootloading, fnp_info.running = "0"b;
 572           a_code = code;
 573           return;
 574 ^L
 575 
 576 fdump:
 577      entry (a_fnp_no, a_fnp_type, a_fnp_mem_size, a_ptr, a_code);
 578 
 579 /* entry to read in contents of FNP core for fdump_fnp_.  It is passed a pointer
 580    *  to the segment in which the dump is supposed to be put.  The one-page fnp_dump_seg
 581    *  is wired down, and FNP core is read into it in chunks.
 582    *
 583    *  This entry had to be greatly modified for the clearing of the Datanet 7100.
 584    *  Called by the initializer command "dump_mpx" through uncp_multiplexer$hpriv_control
 585       froma "dump" control order passed through hphcs_$tty_order -> priv_channel_manager -> cmtv.
 586       This entry is currently NON-OPERATIONAL.
 587 
 588 */
 589 
 590           fnp_no = a_fnp_no;
 591           fnp_type = a_fnp_type;
 592           fnp_mem_size = a_fnp_mem_size;
 593           segptr = a_ptr;
 594 
 595           call validate_fnp_ret ("fdump");
 596 
 597 
 598           ttybp = addr (tty_buf$);
 599           fnp_dump_ptr = addr (fnp_dump_seg$);
 600           on cleanup
 601                begin;
 602                if fnp_dump_seg.lock = pds$processid
 603                then call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
 604           end;
 605           go to ret_bad_code;
 606 /*
 607           call lock$wait (addr (fnp_dump_seg.lock), fdump_seg_event, code);
 608           if code ^= 0
 609           then go to ret_bad_code;
 610           call assign_interrupt (dump_interrupt, code);     /* we will handle DIA interrupts for this *
 611           if code ^= 0
 612           then go to unlock_dump_seg;
 613 
 614           call wire_dump_seg;
 615           if code ^= 0
 616           then go to restore_interrupt;
 617 
 618           data_ptr = addr (fnp_dump_seg.data);
 619 
 620 
 621 
 622           fnp_size = fnp_mem_size * 512;                    /* size of FNP core in 36-bit words *
 623 
 624 /* before we start, set up handler for record-quota overflow *
 625 
 626           on record_quota_overflow
 627                begin;
 628                code = error_table_$rqover;
 629                go to unwire_buffer;
 630           end;
 631 ^L
 632 
 633 /* Subroutine to quiet the mmpo which we leave to clear the memory by blocks.
 634    We have three minutes for the job.
 635 
 636           call init_mmpo;
 637           if a_code ^= 0
 638           then go to unwire_buffer;
 639 
 640 
 641 /* loop reading chunks of FNP memory *
 642 /* Go read blocks of 768 Multics words ( 512+256 ) *
 643 
 644 /* Address of the 7100 modulo 256.    *
 645           fnp_info.running = "0"b;                          /* It is no longer in running state *
 646           fnp_addr, offset = 0;
 647           fnp_tally = 768;
 648           do while (fnp_tally > 0);
 649                call setup_dump_ctl_word;
 650                call fdump_seg_io ("75"b3);                  /*  test data xfer *
 651                if code ^= 0
 652                then go to unwire_buffer;
 653 
 654 /* Now copy the data into the permanent seg *
 655 
 656                ptr (segptr, offset) -> tally_words = addr (fnp_dump_seg.data (2)) -> tally_words;
 657                                                             /* word 0 and 1 are control words *
 658                offset = offset + 768;
 659                fnp_tally = min (768, fnp_size - offset);
 660           end;
 661 
 662 /* Ajouter pour le DN 7100 ************************ *
 663 
 664 /*  The MMPO has to safeguard the first 100 words of memory in high memory
 665     (address of the end of memory - 400).  It must then replace this zone in
 666      its place *
 667 
 668           offset = fnp_size - 512;                          /* start of the saved zone *
 669           segpt1 = ptr (segptr, offset);
 670           segptr = a_ptr;                                   /* start of the segment *
 671           fnp_tally = SIZE_128;                             /* cad 100 words hex of 16 bits expressed in L68 36 bit decimal words *
 672           segptr -> tally_words = segpt1 -> tally_words;    /* Yo!  It's done *
 673 ^L
 674 unwire_buffer:
 675           call unwire_dump_seg;                             /* and unwire buffer *
 676 
 677 restore_interrupt:
 678           call assign_interrupt (uncp$interrupt, code);
 679 */
 680 
 681 
 682 unlock_dump_seg:
 683           call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
 684 ret_bad_code:
 685           a_code = code;
 686           return;
 687 
 688 
 689 fdump_seg_io:
 690      proc (a_diaop);
 691 
 692 dcl  a_diaop bit (6) aligned;
 693 
 694           start_time = clock ();
 695           fnp_dump_seg.fdump = "1"b;                        /* so notify can be done */
 696           call pxss$addevent (tty_ev);
 697           call connect_to_dia (a_diaop);
 698           call pxss$wait;                                   /* wait for interrupt */
 699 
 700           do while (fnp_dump_seg.fdump);                    /* when we get notify, make sure it's the right one */
 701                if clock () - start_time > SECONDS_30        /* if it's been more than 30 seconds */
 702                then do;                                     /* punt */
 703                     code = error_table_$no_io_interrupt;
 704                     return;
 705                end;
 706 
 707                call pxss$addevent (tty_ev);
 708                if fnp_info.t_and_d_in_progress
 709                then if fnp_info.t_and_d_lev_3_occurred | fnp_info.t_and_d_lev_7_occurred
 710                     then do;
 711                          code = 0;
 712                          return;
 713                     end;
 714                if fnp_dump_seg.fdump                        /* it wasn't */
 715                then call pxss$wait;                         /* wait some more */
 716                else call pxss$delevent (tty_ev);            /* otherwise we needn't have added event */
 717           end;
 718           code = 0;
 719      end fdump_seg_io;
 720 
 721 dump_interrupt:
 722      entry (a_fnp_no, a_level, a_dummy);
 723 
 724 /* this is our temporary FNP interrupt handler while doing fdump i/o */
 725 
 726 dcl  a_dummy bit (36) aligned parameter;
 727 
 728           fnp_dump_ptr = addr (fnp_dump_seg$);
 729           infop = addr (dn355_data$);
 730           if datanet_info.trace
 731           then call syserr (ANNOUNCE,
 732                     "uncp_util (dump_interrupt): Interrupt for FNP ^d level ^d. fnp_dump_seg.fdump = ""^b""b", a_fnp_no,
 733                     a_level, fnp_dump_seg.fdump);
 734           if fnp_dump_seg.fdump                             /* if we're really interested in this one */
 735           then do;
 736                fnp_dump_seg.fdump = "0"b;                   /* so we'll recognize notify */
 737                call pxss$notify (tty_ev);
 738           end;
 739           return;
 740 ^L
 741 
 742 ^L
 743 
 744 
 745 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 746    fnp_util$fnp_tandd_setup. */
 747 
 748 fnp_tandd_setup:
 749      entry (a_fnp_no, a_ev_chan, a_code);
 750 
 751           fnp_no = a_fnp_no;
 752           call validate_fnp_ret ("fnp_tandd_setup");
 753 
 754 /* Must set up lcte ptr first if not done already, or lock
 755    won't work.  Chicken/egg problem notwithstanding, this will
 756    work, because other guy doing same thing. */
 757 
 758           temp_fnp_name = get_fnp_name_ (fnp_no);
 759           if fnp_info.lcte_ptr = null
 760           then do;
 761                call priv_channel_manager$get_devx (temp_fnp_name, devx, code);
 762                if code ^= 0
 763                then go to ret_bad_code;
 764                fnp_info.lcte_ptr = addr (tty_buf$lct_ptr -> lct.lcte_array (devx));
 765           end;
 766 
 767           call lock_fnp;
 768 
 769           if fnp_info.bootloading | fnp_info.running | fnp_info.t_and_d_in_progress
 770           then do;
 771                code = error_table_$invalid_state;
 772                go to tandd_setup_loses_unlock;
 773           end;
 774 
 775           call uncp_multiplexer$assign (fnp_no, code);
 776           if code ^= 0
 777           then do;
 778                call syserr$error_code (ANNOUNCE, code, "uncp_util: channel assignment failed for FNP ^a.",
 779                     fnp_info.fnp_tag);
 780                go to tandd_setup_loses_unlock;
 781           end;
 782 
 783           call ioam_$assign ((fnp_info.io_manager_chx), fnp_tandd_release_handler, code);
 784           if code ^= 0
 785           then do;
 786                call syserr$error_code (ANNOUNCE, code, "uncp_util: ioam_$assign failed for FNP ^a.", fnp_info.fnp_tag);
 787                go to tandd_setup_loses_unlock;
 788           end;
 789           fnp_info.boot_process_id = pds$processid;
 790           fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 791           call syserr (ANNOUNCE, "uncp_util: assigned FNP ^a to ^a for T & D.", temp_fnp_name, pds$process_group_id);
 792           fnp_info.t_and_d_in_progress = "1"b;
 793 
 794 tandd_setup_loses_unlock:
 795           if code = 0
 796           then fnp_info.boot_ev_chan = a_ev_chan;
 797           call unlock_fnp;
 798           a_code = code;
 799           return;
 800 
 801 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 802    fnp_util$fnp_tandd_release_handler. */
 803 
 804 fnp_tandd_release_handler:
 805      entry (a_devx, a_code);
 806 
 807           devx = a_devx;
 808           infop = addr (dn355_data$);
 809           fnp_dump_ptr = addr (fnp_dump_seg$);
 810           on cleanup
 811                begin;
 812                if fnp_dump_seg.lock = pds$processid
 813                then call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
 814           end;
 815           do fnp_no = 1 to datanet_info.no_of_355s;
 816                fnpp = addr (datanet_info.per_datanet (fnp_no));
 817                if devx = fnp_info.io_manager_chx
 818                then if fnp_info.t_and_d_in_progress
 819                     then call release_t_and_d;
 820           end;
 821           return;
 822 
 823 /**** T and D does not have to worry about force deconfiguration,
 824       since it is completely released at deconfigure time.
 825       Validate_fnp_tandd_ret will generate an error code if
 826       deconfiguration has stolen the FNP. */
 827 
 828 
 829 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 830    fnp_util$fnp_tandd_detach. */
 831 
 832 fnp_tandd_detach:
 833      entry (a_fnp_no, a_code);
 834           fnp_no = a_fnp_no;
 835 
 836           call validate_fnp_tandd_ret ("fnp_tandd_detach");
 837           call lock_fnp;
 838           call validate_assigned_ret ("fnp_tandd_detach");
 839 
 840           call mask_dia;
 841 
 842           fnp_info.boot_process_id = "000000000000"b3;
 843           fnp_info.t_and_d_in_progress = "0"b;
 844           fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 845           call ioam_$unassign ((fnp_info.io_manager_chx), (0));
 846           call uncp_multiplexer$unassign (fnp_no, code);
 847           if code ^= 0
 848           then call syserr$error_code (ANNOUNCE, code, "uncp_util: io channel unassignment failed for FNP ^a.",
 849                     fnp_info.fnp_tag);
 850           call syserr (ANNOUNCE, "uncp_util: releasing FNP ^a from ^a", fnp_info.fnp_id.fnp_tag, pds$process_group_id);
 851           call unlock_fnp;
 852           a_code = 0;
 853           return;
 854 
 855 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 856    fnp_util$fnp_tandd_mask. */
 857 
 858 fnp_tandd_mask:
 859      entry (a_fnp_no, a_code);
 860           fnp_no = a_fnp_no;
 861           call validate_fnp_tandd_ret ("fnp_tandd_mask");
 862           call lock_fnp;
 863           call validate_assigned_ret ("fnp_tandd_mask");
 864 
 865           call mask_dia;
 866           call unlock_fnp;
 867           a_code = 0;
 868           return;
 869 
 870 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 871    fnp_util$fnp_tandd_send_int. */
 872 
 873 fnp_tandd_send_int:
 874      entry (a_fnp_no, a_level, a_code);
 875           fnp_no = a_fnp_no;
 876           call validate_fnp_tandd_ret ("fnp_tandd_send_int");
 877           call lock_fnp;
 878           call validate_assigned_ret ("fnp_tandd_send_int");
 879 
 880           fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 881           call connect_to_dia ("71"b3);
 882           call unlock_fnp;
 883 
 884           a_code = 0;
 885           return;
 886 
 887 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 888    fnp_util$fnp_tandd_get_ints. */
 889 
 890 fnp_tandd_get_ints:
 891      entry (a_fnp_no, a_ints, a_code);
 892           fnp_no = a_fnp_no;
 893           call validate_fnp_tandd_ret ("fnp_tandd_get_ints");
 894           call lock_fnp;
 895           call validate_assigned_ret ("fnp_tandd_get_ints");
 896           a_ints = fnp_info.t_and_d_lev_3_occurred || fnp_info.t_and_d_lev_7_occurred;
 897           fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 898           call unlock_fnp;
 899           a_code = 0;
 900           return;
 901 
 902 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 903    fnp_util$fnp_tandd_read. */
 904 
 905 fnp_tandd_read:
 906      entry (a_fnp_no, a_ptr, a_count, a_fnp_addr, a_fnp_type, a_code);
 907           opcode = BIT_75;
 908           go to fnp_t_and_d_rw_merge;
 909 
 910 /* This procedure is NOT REFERENCED by uncp software, but rather calls
 911    fnp_util$fnp_tandd_write. */
 912 
 913 fnp_tandd_write:
 914      entry (a_fnp_no, a_ptr, a_count, a_fnp_addr, a_fnp_type, a_code);
 915           opcode = BIT_76;
 916 fnp_t_and_d_rw_merge:
 917 /**** To avoid LONG delays in deconfiguration, this does not lock
 918       the LCTE lock except around the connects themselves. */
 919           fnp_no = a_fnp_no;
 920           segptr = a_ptr;
 921           nwords = a_count;
 922           fnp_type = a_fnp_type;
 923           fnp_addr = a_fnp_addr;
 924           fnp_dump_ptr = addr (fnp_dump_seg$);
 925           call validate_fnp_tandd_ret ("fnp_tandd_rw");
 926 
 927           on cleanup
 928                begin;
 929                if fnp_dump_seg.lock = pds$processid
 930                then call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
 931           end;
 932 
 933           data_ptr = addr (fnp_dump_seg.data);
 934 
 935           call lock$wait (addr (fnp_dump_seg.lock), fdump_seg_event, code);
 936           if code ^= 0
 937           then go to ret_bad_code;
 938           if fnp_type = DN6670
 939           then dump_6670_control.unpaged = "1"b;
 940           else dump_355_control.address_mode = "1"b3;
 941           offset = 0;
 942           do while (nwords > 0);
 943                fnp_tally = min (MIN_TALLY, nwords);
 944                nwords = nwords - fnp_tally;
 945                call setup_dump_ctl_word;
 946                if opcode = BIT_76                           /* WRITE */
 947                then addr (fnp_dump_seg.data (2)) -> tally_words = addrel (segptr, offset) -> tally_words;
 948                call wire_dump_seg;
 949                if code ^= 0
 950                then go to unlock_dump_seg;
 951                fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 952                fnp_info.t_and_d_notify_requested = "1"b;
 953 
 954                call fdump_seg_io (opcode);
 955 
 956                fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
 957                call unwire_dump_seg;
 958                if code ^= 0
 959                then go to unlock_dump_seg;
 960                if opcode = BIT_75                           /* READ */
 961                then addrel (segptr, offset) -> tally_words = addr (fnp_dump_seg.data (2)) -> tally_words;
 962 
 963                offset = offset + fnp_tally;
 964           end;
 965           code = 0;
 966           go to unlock_dump_seg;
 967 ^L
 968 
 969 validate_assigned_ret:
 970      procedure (caller);
 971 
 972 declare  caller char (32);
 973 
 974           if ^fnp_info.io_manager_assigned
 975           then do;
 976                code = error_table_$io_not_assigned;
 977                if datanet_info.trace | datanet_info.debug_stop
 978                then call syserr$error_code (ANNOUNCE, code,
 979                          "uncp_util$validate_assigned_ret (^a): IO manager assignment lacking.", caller);
 980                call STOP_CHECK ("validate_assigned_ret");
 981                call unlock_fnp;
 982                go to ret_bad_code;
 983           end;
 984           return;
 985      end validate_assigned_ret;
 986 
 987 
 988 validate_fnp_ret:
 989      procedure (caller);
 990 
 991 declare  caller char (32);
 992 
 993 /* internal procedure to ensure that FNP number is reasonable */
 994 
 995           infop = addr (dn355_data$);
 996 
 997           if fnp_no <= 0 | fnp_no > max_no_355s
 998           then do;
 999                code = error_table_$io_not_defined;
1000 ERROR:
1001                if datanet_info.trace | datanet_info.debug_stop
1002                then call syserr$error_code (ANNOUNCE, code, "uncp_util$^a: Invalid call for FNP ^d.", caller, fnp_no);
1003                call STOP_CHECK (caller);
1004                go to ret_bad_code;
1005           end;
1006 
1007           if ^tty_buf$fnp_config_flags (fnp_no)
1008           then do;
1009                fnpp = null;
1010                code = error_table_$io_not_defined;
1011                go to ERROR;
1012           end;
1013 
1014           code = 0;
1015           fnpp = addr (datanet_info.per_datanet (fnp_no));
1016           mbxp = fnp_info.mbx_pt;
1017           if datanet_info.trace
1018           then call syserr (ANNOUNCE, "uncp_util$^a: Tracing call for fnp ^a.", caller, fnp_info.fnp_tag);
1019 
1020           return;
1021 
1022      end validate_fnp_ret;
1023 ^L
1024 
1025 
1026 validate_fnp_tandd_ret:
1027      proc (caller);
1028 
1029 declare  caller char (32);
1030 
1031           call validate_fnp_ret (caller);
1032           if ^fnp_info.t_and_d_in_progress
1033           then code = error_table_$invalid_state;
1034           else if fnp_info.boot_process_id ^= pds$processid
1035           then code = error_table_$io_no_permission;
1036           if code ^= 0
1037           then do;
1038                if (datanet_info.trace | datanet_info.debug_stop)
1039                then call syserr$error_code (ANNOUNCE, code, "uncp_util$^a: Invalid call.", caller);
1040                go to ret_bad_code;
1041           end;
1042           return;                                           /* validate_fnp_ret did trace */
1043      end validate_fnp_tandd_ret;
1044 ^L
1045 setup_dump_ctl_word:
1046      proc;
1047 
1048           d7100.pcw.fnp_address = divide (2 * offset, SIZE_256, 14, 0);
1049                                                             /* The DN7100 address is modulo 256 */
1050           d7100.pcw.tally = fixed (fnp_tally, 11);          /* Tally in L68 words */
1051 
1052      end;
1053 
1054 wire_dump_seg:
1055      proc;
1056 
1057           astep = get_ptrs_$given_segno (fixed (baseno (fnp_dump_ptr), 17));
1058           call pc_abs$wire_abs_contig (astep, 0, 1, code);  /* wire a page */
1059           if code = 0
1060           then abs_address = absadr (fnp_dump_ptr, code);
1061           if code = 0
1062           then abs_addr_string = bit (fixed (abs_address + 2, 24), 24);
1063                                                             /* fdump_seg_io needs this */
1064      end;
1065 
1066 unwire_dump_seg:
1067      proc;
1068 
1069           astep = get_ptrs_$given_segno (fixed (baseno (fnp_dump_ptr), 17));
1070           call pc_abs$unwire_abs (astep, 0, 1);
1071           return;
1072      end unwire_dump_seg;
1073 
1074 
1075 assign_interrupt:
1076      proc (handler, code);
1077 
1078 /* internal procedure to set handler for IOM interrupt to our proc. */
1079 
1080 dcl  handler entry;
1081 
1082 dcl  iom_code fixed bin (35);
1083 dcl  code fixed bin (35);
1084 
1085           call lock_fnp;                                    /* discourage reconfiguration */
1086           if ^fnp_info.io_manager_assigned                  /* already deconfigured?  */
1087           then if ^fnp_info.available                       /* already deconfigured! */
1088                then do;
1089                     code = error_table_$io_not_configured;
1090                     return;
1091                end;
1092 
1093 /**** It may already be unassigned, as in dump of down MPX */
1094 
1095           if fnp_info.io_manager_assigned
1096           then do;
1097                call io_manager$unassign (fnp_info.io_manager_chx, code);
1098                if code ^= 0
1099                then call syserr$error_code (CRASH, code, "uncp_util: Could not unassign FNP ^a at reassign_interrupt.",
1100                          fnp_info.fnp_tag);
1101                fnp_info.io_manager_assigned = "0"b;
1102           end;                                              /* now make new assignment */
1103 
1104           call io_manager$assign (fnp_info.io_manager_chx, fnp_info.io_chanid, handler, (fnp_no), (null ()), iom_code);
1105           call unlock_fnp;
1106           if code = 0                                       /* if there wasn't anything more interesting to report */
1107           then do;
1108                code = iom_code;                             /* then report this */
1109                fnp_info.io_manager_assigned = "1"b;
1110           end;
1111 
1112           return;
1113 
1114      end assign_interrupt;
1115 
1116 /*  unassign_interrupt:
1117    procedure;
1118 
1119    call io_manager$unassign (fnp_info.io_manager_chx, (0));
1120    fnp_info.io_manager_assigned = "0"b;
1121    return;
1122    end unassign_interrupt;      */
1123 connect_to_dia:
1124      proc (cmd);
1125 
1126 /* internal procedure to do DIA i/o */
1127 
1128 dcl  cmd bit (6) aligned;
1129 dcl  1 ima aligned like io_manager_arg;
1130 
1131           datanet_mbx.dia_pcw.zero = substr (abs_addr_string, 7, 18);
1132                                                             /* lower 18 bits of 6180 address */
1133           datanet_mbx.dia_pcw.mbx_no = substr (abs_addr_string, 1, 6);
1134                                                             /* rest of it goes here */
1135           datanet_mbx.dia_pcw.command = cmd;
1136 
1137 /* parity on pcw (probably not necessary) */
1138 
1139           string (datanet_mbx.dia_pcw) = dn355_util$compute_parity (string (datanet_mbx.dia_pcw));
1140 
1141           ima.chx = fnp_info.io_manager_chx;
1142           ima.ptp = null ();
1143           call io_manager$connect_direct (ima);
1144 
1145           return;
1146      end /* connect_to_dia */;                              /*^L                                                        */
1147 mask_dia:
1148      procedure;
1149           call io_manager$mask (fnp_info.io_manager_chx);   /* mask the channel to initialize it */
1150      end mask_dia;
1151 
1152 /*   internal_unwire:
1153    procedure;
1154 
1155    declare  px fixed bin;
1156 
1157    /* internal procedure to undo work of wire entry */
1158 /*
1159    if fnpp = null
1160    then return;
1161    if ^fnp_info.wired
1162    then return;
1163 
1164    ioptp = fnp_info.ptp;
1165    if ioptp ^= null ()
1166    then do px = FIRST_BOOTLOAD_PAGEX to FIRST_BOOTLOAD_PAGEX + fnp_info.n_pages_wired;
1167    unspec (page_table.ptw (px)) = ""b;  /* as of next connect, no more references */
1168 /*        end;
1169 
1170    astep = fnp_info.astep;
1171    call pc_abs$unwire_abs (astep, 0, fnp_info.n_pages_wired);
1172    call grab_aste$release_io (astep);
1173    fnp_info.wired = "0"b;
1174    return;
1175 
1176    end internal_unwire;    */
1177 
1178 release_t_and_d:
1179      procedure;
1180 
1181 declare  unlock_dump_seg bit (1) aligned;
1182 
1183           call lock$wait (addr (fnp_dump_seg.lock), fdump_seg_event, code);
1184                                                             /* wait for finish */
1185           unlock_dump_seg = (code = 0);                     /* if user held lock for other reason, leave it locked ? */
1186           call syserr (0, "uncp_util: force detaching FNP ^a from process ^w.", fnp_info.fnp_id.fnp_tag,
1187                fnp_info.boot_process_id);
1188           call lock_fnp;                                    /* hold the LCTE lock (or the config lock) */
1189           fnp_info.boot_process_id = "000000000000"b3;
1190           fnp_info.boot_ev_chan = 0;
1191           fnp_info.t_and_d_in_progress = "0"b;
1192           fnp_info.t_and_d_lev_3_occurred, fnp_info.t_and_d_lev_7_occurred = "0"b;
1193           call uncp_multiplexer$unassign (fnp_no, code);
1194           if code ^= 0
1195           then call syserr$error_code (ANNOUNCE, code, "uncp_util: io channel unassignment failed for FNP ^a.",
1196                     fnp_info.fnp_tag);
1197           call unlock_fnp;
1198           if unlock_dump_seg
1199           then call lock$unlock (addr (fnp_dump_seg.lock), fdump_seg_event);
1200           return;
1201      end release_t_and_d;
1202 
1203 
1204 lock_fnp:
1205      procedure;
1206 
1207 declare  code fixed bin (35);
1208 
1209           if locked | config_locked
1210           then call syserr (CRASH, "uncp_util: lock_fnp called with lock locked.");
1211           locked, config_locked = "0"b;
1212 
1213           call lock$lock_fast (addr (datanet_info.configuration_lock));
1214           config_locked = "1"b;                             /* LCTE cannot get initialized after this point */
1215           if fnp_info.lcte_ptr = null ()
1216           then return;                                      /* that is the whole story */
1217           else if ^fnp_info.lcte_ptr -> lcte.initialized    /* no mpx in the house */
1218           then return;                                      /* and the config lock locks out T&D I/O */
1219 
1220           /*** here, there is a multiplexer, so we have to lock against it */
1221 
1222           call uncp_multiplexer$fnp_lock (fnpp, code);
1223           if code = 0
1224           then do;
1225                locked = "1"b;                               /* lcte was initialized, and we now own it */
1226                call lock$unlock_fast (addr (datanet_info.configuration_lock));
1227                                                             /* if init_multiplexer finds the LCTE initialized, it aborts */
1228                                                             /* so all we are protecting against is ourselves */
1229                config_locked = "0"b;
1230           end;
1231           return;
1232 
1233 unlock_fnp:
1234      entry;
1235 
1236           if locked
1237           then call uncp_multiplexer$fnp_unlock (fnpp);
1238           locked = "0"b;
1239           if config_locked
1240           then call lock$unlock_fast (addr (datanet_info.configuration_lock));
1241           config_locked = "0"b;
1242           return;
1243      end lock_fnp;
1244 
1245 
1246 STOP_CHECK:
1247      procedure (Tracer);
1248 declare  Tracer char (*);
1249 
1250           if datanet_info.debug_stop
1251           then call syserr (CRASH, "uncp_util$^a: Debugging stop (type go to continue).", Tracer);
1252           return;
1253      end STOP_CHECK;
1254 ^L
1255 
1256 get_page_table:
1257      procedure (code);
1258 
1259 declare  pagex fixed bin;
1260 declare  px fixed bin;
1261 declare  1 seg_pt (0:255) aligned like l68_core_ptw based (ptp);
1262 declare  ptp pointer;
1263 declare  code fixed bin (35);
1264 
1265           io_page_table_size = SIZE_256;                    /* always, for datanet */
1266           call ioi_page_table$get (io_page_table_size * sys_info$page_size, fnp_info.ptx, code);
1267                                                             /* Direct channel has no bounds check so we need all 256 */
1268           if code ^= 0
1269           then return;
1270           fnp_info.ptp, ioptp = ioi_page_table$ptx_to_ptp (fnp_info.ptx);
1271 
1272           unspec (page_table) = ""b;
1273 
1274 /**** leave page zero invalid */
1275 
1276 /**** First, dn355_mailbox */
1277 
1278           do px = LOW_MBX_PTW to HIGH_MBX_PTW;
1279                io_ptwp = addr (page_table.ptw (px));
1280                io_ptw.address = px;                         /* absolute page number */
1281                io_ptw.write = "1"b;
1282                io_ptw.valid = "1"b;
1283           end;
1284 
1285 /**** Now, tty_buf */
1286 
1287           astep = get_ptrs_$given_segno (segno (addr (tty_buf$)));
1288           pagex = FIRST_TTY_BUF_PAGEX;
1289           ptp = addwordno (astep, sst$astsize);
1290           do px = 0 to bin (aste.csl, 9) - 1;               /* no null pages here */
1291                io_ptwp = addr (page_table.ptw (pagex));
1292                io_ptw.address = seg_pt (px).frame;
1293                io_ptw.write = "1"b;
1294                io_ptw.valid = "1"b;
1295                pagex = pagex + 1;
1296           end;                                              /* tty_buf is now described to the channel */
1297           return;
1298 
1299 fill_bootload_page_table:
1300      entry;                                                 /* fill in io ptws for bootload segment */
1301 
1302 /**** astep is already set to the bootload image aste */
1303 
1304           pagex = FIRST_BOOTLOAD_PAGEX;
1305           ptp = addwordno (astep, sst$astsize);
1306           auto_absadr = pagex * sys_info$page_size;
1307           ioptp = fnp_info.ptp;
1308 
1309           do px = 0 to fnp_info.n_pages_wired - 1;
1310                io_ptwp = addr (page_table.ptw (pagex));
1311                io_ptw.address = seg_pt (px).frame;
1312                io_ptw.write = "0"b;
1313                io_ptw.valid = "1"b;
1314                pagex = pagex + 1;
1315           end;
1316 
1317           if datanet_info.trace
1318           then do px = 0 to 255;
1319                if unspec (page_table.ptw (px)) ^= ""b
1320                then call syserr (ANNOUNCE, "uncp_util: ptw at ^4o = ^w", px, unspec (page_table.ptw (px)));
1321           end;
1322 
1323           return;
1324 
1325      end get_page_table;
1326 
1327 
1328 /* format: off */
1329 
1330 /* INCLUDE FILES */
1331 %page; %include aste;
1332 %page; %include config_prph_fnp_card;
1333 %page; %include dn355_mailbox;
1334 %page; %include mailbox_ops;
1335 %page; %include lct;
1336 %page; %include dn355_data;
1337 %page; %include pcb;
1338 %page; %include fnp_dump_seg;
1339 %page; %include fnp_types;
1340 %page; %include io_manager_dcls;
1341 %page; %include io_page_tables;
1342 %page; %include io_chnl_util_dcls;
1343 %page; %include "ptw.l68";
1344        declare ptp pointer;
1345 %page; %include syserr_constants;
1346 %page; %include tty_buf;
1347 %include fnp_mpx_msg_;
1348 
1349 ^L
1350 
1351 
1352 /* Begin message documentation invisible
1353 
1354    This message documentation is designated "invisible" and not in the normal
1355    format so it will not be assigned to the released set of message
1356    documentation.  This software is not to be released for customer use.
1357 
1358    Message:
1359    Loading FNP X, CORE_IMAGE VERSION
1360 
1361    S:  $info
1362 
1363    T:  Answering service initialization and each subsequent FNP
1364    bootload.
1365 
1366    M:  Loading of FNP X has begun with a core image named CORE_IMAGE
1367    (normally "mcs") of version number VERSION.
1368 
1369    A:  $ignore
1370 
1371 
1372    Message:
1373    uncp_util$wire: FNP T already wired (trace)
1374 
1375 
1376    Message:
1377    uncp_util$wire: failed. REASON (trace)
1378 
1379 
1380    Message:
1381    uncp_util$load: FNP load already in progress for FNP T.
1382 
1383 
1384    Message:
1385    uncp_util$load: FNP T not wired.
1386 
1387 
1388    Message:
1389    uncp_util$load: FNP T is running. (trace)
1390 
1391 
1392    Message:
1393    uncp_util$load: FNP T is running T&D.
1394 
1395 
1396    Message:
1397    uncp_util$load: Error loading FNP T. REASON (trace)
1398 
1399 
1400    Message:
1401    uncp_util$unwire: Unwire failed for FNP T. REASON
1402 
1403 
1404    Message:
1405    uncp_util$configure: FNP T already configured.
1406 
1407 
1408    Message:
1409    uncp_util: FNP T added to configuration^[ by NAME^].
1410 
1411 
1412    Message:
1413    FNP T deleted from configuration^[ by ^a^].
1414 
1415 
1416    Message:
1417    uncp_util$fdump_seg_io: IO_OP for CALLER (trace)
1418 
1419 
1420    Message:
1421    uncp_util: channel assignment failed for FNP ^T REASON. (tandd)
1422 
1423 
1424    Message:
1425    uncp_util: ioam_$assign failed for FNP T. REASON (tandd)
1426 
1427 
1428    Message:
1429    uncp_util: assigned FNP T to NAME for T & D.
1430 
1431 
1432 
1433    Message:
1434    uncp_util: io channel unassignment failed for FNP T. (tandd)
1435 
1436 
1437    Message:
1438    uncp_util: releasing FNP T from NAME (tandd)
1439 
1440 
1441    Message:
1442    uncp_util$validate_assigned_ret (CALLER): IO manager assignment lacking. (trace)
1443 
1444 
1445    Message:
1446    uncp_util$ENTRY: Invalid call for FNP INDEX. (not in cdeck)
1447 
1448 
1449    Message:
1450    uncp_util$ENTRY: Tracing call for fnp T.
1451 
1452 
1453    Message:
1454    uncp_util$ENTRY: Invalid call. (trace)
1455 
1456 
1457    Message:
1458    uncp_util: Could not unassign FNP T at reassign_interrupt.
1459 
1460 
1461    Message:
1462    uncp_util: force detaching FNP T from process PID.
1463 
1464 
1465    Message:
1466    uncp_util: io channel unassignment failed for FNP T. (tandd)
1467 
1468 
1469    Message:
1470    uncp_util: lock_fnp called with lock locked.
1471 
1472 
1473    Message:
1474    uncp_util$ENTRY: Debugging stop (type go to continue).
1475 
1476    End message documentation invisible */
1477 
1478 
1479      end uncp_util;