1 /****^  ***********************************************************
   2         *                                                         *
   3         * Copyright, (C) Honeywell Bull Inc., 1987                *
   4         *                                                         *
   5         * Copyright, (C) Honeywell Information Systems Inc., 1984 *
   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(86-06-05,GJohnson), approve(86-06-05,MCR7387),
  15      audit(86-06-10,Martinson), install(86-07-17,MR12.0-1091):
  16      Correct error message documentation.
  17   2) change(86-06-30,Fawcett), approve(86-06-30,MCR7383),
  18      audit(86-06-30,LJAdams), install(86-07-17,MR12.0-1097):
  19      Add support for subvolumes, 3380 and 3390.
  20                                                    END HISTORY COMMENTS */
  21 
  22 /* format: indattr,inddcls,dclind5,idind30,struclvlind5,ifthenstmt,ifthendo,^inditerdo,^indnoniterend,case,^tree,^indproc,^indend,^delnl,^insnl,comcol81,indcom,linecom,^indcomtxt */
  23 mdx:
  24      proc;
  25 
  26           /* Guts of volume management.
  27 
  28    This program is the brains behind disk_table_.
  29    We run in ring 1 here and can mess with the disk table - but we don't print any messages.
  30 
  31    system_startup_ and sc_command_ call disk_table_ which can run in any ring and print.
  32    disk_table_ calls us through initializer_mdc_.
  33 
  34    THVV
  35    4/2/76 by Greenberg for demount and auto lv/pv vanishing
  36    12/4/76 by Greenberg for new lv vanish including demounted bits
  37    03/8/77 by Greenberg for static ac/dc disks and random refcount bugs
  38    July 1977 by T. Casey to add set_lv_pdir_bit entry
  39    Jan 1978 by B. Greenberg for prev_bootload bit, making lvs "mounting" at startup.
  40    July 1978 by B. Greenberg for hardcore RLV acceptance.
  41    July 1981 by J. Bongiovanni to validate lv indices
  42    March 1982 by J. Bongiovanni for new PVTE
  43    '82 for english disk error codes
  44    831122 by E. A. Ranzenbach for set_vacate_pdirs_bit entry.
  45    August 1984 by Chris Jones to tell IOI when we add or delete a drive.
  46    84-09-04 by EJ Sharpe to change hdx refs to volume_registration_mgr_
  47           also changed check_hv entry to check_lv
  48    85-01-31 by EJ Sharpe to force-init DT entries for: 1) root PVs not on the
  49           ROOT config card (i.e. not in PVT at init time); and 2) root PVs
  50           have moved to a different drive (these used to be done incorrectly
  51           by "forgetter").  Also, clear all lve.pdirs_ok bits at initialization.
  52    1985-04-02, BIM: Indicate to caller of "take" when this call has completed
  53                the rlv, so that the last add_vol of an root PV's crows
  54                with success.
  55    05/07/85 by Chris Jones to let IOI decide when a drive can or cannot be reconfigured.
  56    08/28/85 by Rich Fawcett to support sub-volumes.
  57 */
  58 
  59           dcl  found                         bit (1);
  60           dcl  must_term                     bit (1) init ("0"b);
  61           dcl  (sdtp, stat_pvtp)             ptr static init (null);
  62           dcl  ROOT                          char (168) static init (">");
  63           dcl  SL1                           char (168) static init (">system_library_1");
  64           dcl  i                             fixed bin;
  65           dcl  dvn                           char (8);
  66           dcl  (tpvtx, a_tpvtx)              fixed bin;
  67           dcl  lvx                           fixed bin;
  68           dcl  prev_state                    bit (1);
  69           dcl  oldlev                        fixed bin;
  70           dcl  num_pic                       pic "99";
  71           dcl  pvt_n_entries                 fixed bin;
  72           dcl  xec                           fixed bin (35);
  73           dcl  reasonable_time               fixed bin (71) int static init (2276881905645328);
  74 
  75           dcl  (addr, fixed, null, max, rel, rtrim, substr, unspec) builtin;
  76 
  77           dcl  admin_gate_$ioi_add_device    entry (char (*), fixed bin (35));
  78           dcl  admin_gate_$ioi_delete_device entry (char (*), fixed bin (35));
  79           dcl  (cu_$level_set, cu_$level_get) entry (fixed bin);
  80           dcl  initializer_gate_$add_pv_to_lv entry (bit (36) aligned, bit (36) aligned, fixed bin (35));
  81           dcl  initializer_gate_$read_disk   entry (fixed bin, fixed bin, ptr, fixed bin (35));
  82           dcl  initializer_gate_$define_lv   entry (ptr, fixed bin (35));
  83           dcl  initializer_gate_$delete_lv   entry (bit (36) aligned, fixed bin (35));
  84           dcl  initializer_gate_$set_disk_table_loc entry (ptr, fixed bin (35));
  85           dcl  initializer_gate_$accept_fs_disk entry (fixed bin, fixed bin (35));
  86           dcl  initializer_gate_$demount_pv  entry (fixed bin, fixed bin (35));
  87           dcl  initializer_gate_$vol_salv    entry (fixed bin, bit (36) aligned, fixed bin (35));
  88           dcl  initializer_gate_$ss_io_reconfigure entry (fixed bin, bit (1) aligned, fixed bin (35));
  89           dcl  verify_label_                 entry (ptr, ptr, fixed bin, fixed bin (35));
  90           dcl  volume_registration_mgr_$init entry (ptr);
  91           dcl  volume_registration_mgr_$test entry (char (*));
  92           dcl  volume_registration_mgr_$check_volume_registration entry (ptr, fixed bin (35));
  93           dcl  volume_registration_mgr_$get_lv_pvinfo entry (char (*), ptr, fixed bin, fixed bin, fixed bin (35));
  94           dcl  volume_registration_mgr_$find entry (ptr, fixed bin (35));
  95           dcl  hcs_$initiate                 entry (char (*), char (*), char (*), fixed bin (1), fixed bin (2), ptr, fixed bin (35));
  96           dcl  hcs_$terminate_noname         entry (ptr, fixed bin (35));
  97           dcl  hcs_$make_seg                 entry (char (*), char (*), char (*), fixed bin (5), ptr, fixed bin (35));
  98           dcl  hcs_$truncate_seg             entry (ptr, fixed bin, fixed bin (35));
  99           dcl  hcs_$add_acl_entries          entry (char (*), char (*), ptr, fixed bin, fixed bin (35));
 100           dcl  rcp_control_$ss_io_interchange entry (char (*), bit (1) aligned, bit (1) aligned, fixed bin (35));
 101           dcl  admin_gate_$syserr            ext entry options (variable);
 102 
 103           dcl  1 label_buffer                like label;
 104 
 105           dcl  1 adte                        like dte aligned based (aux_dtep);
 106           dcl  1 alve                        like lve aligned based (aux_lvep);
 107           dcl  (aux_dtep, aux_lvep)          ptr;
 108 
 109           dcl  1 aa                          aligned int static,
 110                     2 name                   char (32) init ("*.*.*"),
 111                     2 mode                   bit (36) init ("111"b),
 112                     2 mbz                    bit (36) init ((36)"0"b),
 113                     2 code                   fixed bin (35);
 114 
 115           dcl  sys_info$access_class_ceiling bit (72) ext;
 116           dcl  error_table_$fsdisk_not_salv  fixed bin (35) ext;
 117           dcl  error_table_$no_label         fixed bin (35) ext;
 118           dcl  error_table_$invalid_state    fixed bin (35) ext;
 119           dcl  error_table_$bad_label        fixed bin (35) ext;
 120           dcl  error_table_$argerr           fixed bin (35) ext;
 121           dcl  error_table_$action_not_performed fixed bin (35) ext;
 122           dcl  error_table_$io_still_assnd   fixed bin (35) ext;
 123           dcl  error_table_$logical_volume_not_defined fixed bin (35) ext;
 124           dcl  error_table_$mount_not_ready  fixed bin (35) ext;
 125           dcl  error_table_$private_volume   fixed bin (35) ext;
 126 
 127           /* -------------------------------------------------------- */
 128 
 129           /* This entry is the guts of disk_table_$init. Actually we could call ioa_ here but don't. */
 130 
 131 init: entry (a_dtp, new, ec);
 132 
 133           dcl  a_dtp                         ptr, new bit (1), ec fixed bin (35);
 134 
 135           ec = 0;
 136           new = "0"b;
 137           call hcs_$make_seg (ROOT, "disk_table", "", 1010b, dtp, xec);
 138           if dtp = null then do;                                                /* Must have one */
 139                     ec = xec;                                                   /* quelle horreur */
 140                     return;
 141                end;
 142           call hcs_$add_acl_entries (ROOT, "disk_table", addr (aa), 1, xec);
 143 
 144           call initializer_gate_$set_disk_table_loc (dtp, xec);                 /* Tell BOS where it is (fsout too) */
 145 
 146           call hcs_$initiate (SL1, "pvt", "", 0, 1, pvtp, xec);
 147           if pvtp = null then do;
 148                     ec = xec;                                                   /* system is broken */
 149                     return;
 150                end;
 151           stat_pvtp = pvtp;                                                     /* save value for use in copying pvt.salv bit */
 152           sdtp = dtp;                                                           /* Save static copy for other ep's */
 153           call volume_registration_mgr_$init (dtp);
 154           a_dtp = dtp;
 155 
 156           /* Does the PVT match the Disk Table? */
 157 
 158           pvt_n_entries = pvt.n_entries;
 159           pvt_arrayp = addr (pvt.array);
 160 
 161           if dt.version ^= 1 then ec = 3;
 162           else if pvt_n_entries = dt.n_entries then do;                         /* Must be same size */
 163 
 164                     do i = 1 to dt.n_lv_entries;                                /* Cause lv table to be garbage-collected */
 165                          lvep = addr (dt.lv_array (i));
 166                          lve.mounting = "0"b;                                   /* As to not induce mhv's */
 167                          lve.demounted_only = "0"b;                             /* develop this later */
 168                          lve.demounting = "0"b;                                 /* As to not induce dhv's */
 169                          lve.used = "0"b;                                       /* So that gc will work */
 170                          lve.hv_mounted = "0"b;                                 /* not until we know better */
 171                          lve.pdirs_ok = "0"b;                                   /* site should set these each bootload */
 172                     end;
 173 
 174                     do i = 1 to pvt_n_entries;                                  /* Find hardcore-accepted volumes, scratch old DT entries. */
 175                          pvtep = addr (pvt_array (i));
 176                          dtep = addr (dt.array (i));
 177                          dte.rpv = "0"b;                                        /* Will be set by make_root_pve if true */
 178                          if pvte.used then call make_root_pve;
 179                          else dte.hc_accepted = "0"b;
 180                     end;
 181 
 182                     do i = 1 to pvt_n_entries;                                  /* check all entries xcept PD */
 183                          pvtep = addr (pvt_array (i));
 184                          dtep = addr (dt.array (i));
 185                          dte.need_salvage = "0"b;
 186                          if pvte.storage_system ^= dte.storage_system then do;
 187                                    dte.known, dte.used, dte.demounted, dte.pre_accepted = "0"b;
 188                                    dte.storage_system = pvte.storage_system;
 189                               end;
 190                          if dte.deleted | ^dte.storage_system
 191                          then dte.used, dte.known, dte.pre_accepted, dte.demounted = "0"b;
 192                          num_pic = pvte.logical_area_number;
 193                          dvn = pvte.devname || "_" || num_pic;
 194                          if pvte.is_sv then dvn = rtrim (dvn) || rtrim (pvte.sv_name);
 195                          lvx = dte.lvx;                                         /* Can't be TOO bad. */
 196                          lvep = addr (dt.lv_array (lvx));
 197                          if dvn ^= dte.drive_name then ec = 4;
 198                          else if pvte.device_type ^= dte.device_type then ec = 5;
 199                          else if dte.deleted then dte.deleted = "0"b;           /* Cancel previous "deld" */
 200                          else if lvx <= 0 then goto skip_lv;                    /* invalid index -- don't diddle lve              */
 201                          else if dte.used then do;                              /* good thing last time? */
 202                                    if dte.hc_accepted
 203                                    then call volume_registration_mgr_$check_volume_registration (dtep, xec); /* re-register root pack */
 204                                    else if dte.lvx = 1 then do;
 205                                                                                 /* root PV that is not on ROOT card */
 206                                              call admin_gate_$syserr (BEEP, "disk_table_: Deleted root PV ""^a"" on ^a.", dte.pvname, dte.drive_name);
 207                                              call force_init_dte (i);
 208                                         end;
 209                                    else do;                                     /* Other volumes are "pre-accepted" (ie assumed) */
 210 estab_lv:                                    call make_assumed;
 211                                              lve.demounted_only = "0"b;
 212                                              if dte.lvx ^= 1 then lve.mounting = "1"b;
 213                                              lve.prev_bootload = "1"b;
 214 suggest_lv:                                  lve.used = "1"b;
 215                                              dt.n_lv_entries = max (dt.n_lv_entries, dte.lvx);
 216                                         end;
 217                               end;
 218                          else if dte.known | dte.pre_accepted then go to estab_lv;
 219                          else if dte.demounted then do;
 220                                    if ^lve.used then lve.demounted_only = "1"b;
 221                                    go to suggest_lv;                            /* good vol will turn off, */
 222                                                                                 /* bad vols wont turn on */
 223                               end;
 224                          else ;                                                 /* Idle last time */
 225 skip_lv:
 226                     end;
 227                     if ec = 0 then return;                                      /* If disk config didn't change we exit normally */
 228                end;
 229 
 230           else if dt.n_entries = 0 then do;                                     /* Did we create a new disk table */
 231                     ec = 1;                                                     /*  Yes */
 232                end;
 233 
 234           else do;                                                              /* Some other mismatch */
 235                     ec = 2;                                                     /* disk config changed. rebuild whole thing */
 236                end;
 237 
 238           call hcs_$truncate_seg (dtp, 0, xec);                                 /* Throw away all old stuff */
 239           dt.version = 1;                                                       /* .. and make new */
 240           new = "1"b;
 241           dt.n_entries = pvt_n_entries;                                         /*  Discount the paging device */
 242           dt.max_n_entries = pvt.max_n_entries;
 243           dt.n_lv_entries = 0;
 244           do i = 1 to dt.n_entries;                                             /* Make new table */
 245                pvtep = addr (pvt_array (i));
 246                dtep = addr (dt.array (i));
 247                call force_init_dte (i);
 248                if pvte.used then do;
 249                          call make_root_pve;                                    /* Kosher by definition */
 250                          call volume_registration_mgr_$check_volume_registration (dtep, xec);
 251                                                                                 /* Make sure the rpv is registered */
 252                     end;
 253           end;
 254 
 255           return;
 256 
 257           /* --------------------------------------------------------- */
 258 
 259 take: entry (a_pvname, a_indx, took, ec);
 260 
 261           dcl  a_pvname                      char (*);
 262           dcl  a_indx                        fixed bin;
 263           dcl  took                          bit (1);
 264 
 265           ec = 0;
 266           dtp = sdtp;
 267           i = a_indx;
 268           dtep = addr (dt.array (i));
 269           took = "0"b;
 270           if ^dte.storage_system | dte.deleted | dte.used then do;
 271 fail:               ec = error_table_$argerr;
 272                     return;
 273                end;
 274 
 275           call verify_drive_vanish_pve (dtep, a_pvname, ec);
 276           if ec ^= 0 then return;                                               /* Consistentize disk table */
 277 
 278           dte.pvname = a_pvname;
 279           if ^dte.known then do;
 280                     call volume_registration_mgr_$find (dtep, ec);
 281                     if ec ^= 0 then do;
 282                               call make_demounted;
 283                               return;
 284                          end;
 285                     if ^get_it_known (i, ec) then do;
 286                               call make_demounted;
 287                               return;
 288                          end;
 289                end;
 290           lvep = addr (dt.lv_array (dte.lvx));
 291           if lve.hv_mounted then do;                                            /* Adding vol to live lv (eg root) */
 292                     call initializer_gate_$accept_fs_disk (i, ec);
 293                     if ec = error_table_$fsdisk_not_salv then do;               /* salvage if needed */
 294                               call initializer_gate_$vol_salv (i, ""b, ec);
 295                               call initializer_gate_$accept_fs_disk (i, ec);
 296                          end;
 297                     if ec = 0 then do;
 298                               call make_used;
 299                               call initializer_gate_$add_pv_to_lv (lve.lvid, dte.pvid, ec);
 300                          end;
 301                     call check_lv_complete (xec);                               /* Always try to announce success in completing the RLV */
 302                     if xec = 0 then do;
 303                               call verify_whole_lv (1, xec);
 304                               took = (xec = 0);
 305                          end;
 306                end;
 307           else do;
 308                     i = dte.lvx;
 309                     call check_lv_complete (xec);
 310                     if xec = 0 & lve.mounting then do;                          /* If vol complete AND mhv was called */
 311                               call verify_whole_lv (i, ec);
 312                               if ec = 0 then took = "1"b;
 313                          end;
 314                end;
 315           return;
 316 
 317           /* ------------------------------------------------------ */
 318 
 319 assert: entry (a_pvname, a_indx, ec);
 320 
 321           ec = 0;
 322           dtp = sdtp;
 323           i = a_indx;
 324           dtep = addr (dt.array (i));
 325           if ^dte.storage_system | dte.deleted | dte.used then go to fail;
 326           call verify_drive_vanish_pve (dtep, a_pvname, ec);
 327           if ec ^= 0 then return;
 328 
 329           dte.pvname = a_pvname;
 330           call volume_registration_mgr_$find (dtep, ec);
 331           if ec = 0 then call make_assumed;
 332           else call make_blank;
 333           return;
 334 
 335           /* --------------------------------------------------------- */
 336 
 337 forget: entry (a_indx, ec);
 338 
 339           ec = 0;
 340           dtp = sdtp;
 341           i = a_indx;
 342           dtep = addr (dt.array (i));
 343           if ^dte.storage_system | dte.deleted | dte.used then go to fail;
 344           call make_blank;
 345           return;
 346 
 347           /* -------------------------------------------------------- */
 348 
 349 volsalv: entry (a_pvname, a_indx, opt, ec);
 350 
 351           dcl  opt                           bit (36) aligned;
 352 
 353           ec = 0;
 354           dtp = sdtp;
 355           i = a_indx;
 356           dtep = addr (dt.array (i));
 357           if ^dte.storage_system | dte.deleted | dte.used then go to fail;
 358 
 359           call verify_drive_vanish_pve (dtep, a_pvname, ec);
 360           if ec ^= 0 then return;
 361 
 362           dte.pvname = a_pvname;
 363           call volume_registration_mgr_$find (dtep, ec);
 364           if ec ^= 0 then return;
 365           call verify_label_ (dtp, dtep, i, ec);
 366           if ec ^= 0 then return;
 367           call make_known;
 368 
 369           call initializer_gate_$vol_salv (i, opt, ec);
 370           return;
 371 
 372           /* ---------------------------------------------------------- */
 373 
 374 rlvolcheck: entry (a_indx, a_pvtx, opt, ec);                                    /* allow connection volsalv of copies of rlv members */
 375                                                                                 /* a_pvtx is copy, a_indx is real one */
 376 
 377           dcl  a_pvtx                        fixed bin,
 378                rdtep                         ptr;
 379 
 380           i = a_pvtx;
 381           dtp = sdtp;
 382           dtep = addr (dt.array (i));                                           /* dtep -> copy being salved */
 383           rdtep = addr (dt.array (a_indx));                                     /* rdtep is place where live one lives */
 384 
 385           if dte.deleted | ^dte.storage_system | dte.used then go to fail;
 386           if ^(rdtep -> dte.used | rdtep -> dte.known) then go to fail;
 387 
 388 
 389           call verify_label_ (dtp, rdtep, i, ec);                               /* LIE to verify_label_: info for live, read phony */
 390           if ec ^= 0 then return;
 391 
 392           call make_blank;                                                      /* Bash away stuff, can't be right */
 393 
 394 
 395           call initializer_gate_$vol_salv (i, opt, ec);
 396 
 397           return;
 398 
 399           /* --------------------------------------------------------- */
 400 
 401 mhv: entry (a_indx, a_tpvtx, ec);
 402 
 403           ec = 0;
 404           tpvtx, a_tpvtx = 0;
 405           dtp = sdtp;
 406           lvep = addr (dt.lv_array (a_indx));
 407 
 408           if (lve.hv_mounted & ^(a_indx = 1))                                   /* ok doublemount rlv */
 409                | (lve.mounting & ^lve.prev_bootload)                            /* autograb last-time's */
 410                | lve.demounting | ^lve.used then go to fail;
 411 
 412           if a_indx ^= 1 then lve.mounting = "1"b;
 413           call check_lv_complete (ec);
 414           if ec = 0 | ec = -1 then do;                                          /* Complete or completeable? */
 415                     call verify_whole_lv (a_indx, ec);
 416                end;
 417           a_tpvtx = tpvtx;
 418           return;
 419 
 420           /* --------------------------------------------------------- */
 421 
 422 reregister: entry (a_pvname, a_indx, ec);                                       /* Called when opr asserts disk is ok */
 423 
 424           ec = 0;
 425           dtp = sdtp;
 426           dtep = addr (dt.array (a_indx));
 427 
 428           if ^dte.storage_system | dte.used | dte.deleted then go to fail;
 429 
 430           call verify_drive_vanish_pve (dtep, a_pvname, ec);
 431           if ec ^= 0 then return;
 432 
 433           labelp = addr (label_buffer);
 434           call initializer_gate_$read_disk (a_indx, LABEL_ADDR, labelp, ec);
 435           if ec ^= 0 then return;
 436 
 437           ec = error_table_$no_label;
 438           if label.Multics ^= Multics_ID_String then return;
 439           if label.version ^= 1 then return;
 440           if label.time_registered < reasonable_time then return;
 441           ec = error_table_$bad_label;
 442           if label.pv_name ^= a_pvname then return;
 443           dte.pvname = label.pv_name;
 444           dte.pvid = label.pvid;
 445           do i = 1 to dt.n_lv_entries while (^dt.lv_array (i).used | dt.lv_array (i).lvname ^= label.lv_name); end;
 446           dte.lvx = i;
 447           lvep = addr (dt.lv_array (dte.lvx));
 448           if dte.lvx > dt.n_lv_entries then do;
 449                     dt.n_lv_entries = dt.n_lv_entries + 1;
 450                     unspec (lve) = ""b;
 451                     lve.lvname = label.lv_name;
 452                     lve.lvid = label.lvid;
 453                     lve.max_access_class = label.max_access_class;
 454                     lve.min_access_class = label.min_access_class;
 455                     lve.public = ^label.private;
 456                     lve.used = "1"b;
 457                end;
 458           call volume_registration_mgr_$check_volume_registration (dtep, ec);
 459           if ec ^= 0 then return;
 460           call make_known;
 461           return;
 462 
 463 
 464           /* --------------------------------------------------------- */
 465 
 466 read_disk_table: entry (spacep, ec);
 467 
 468           dcl  spacep                        ptr;
 469           dcl  move_len                      fixed bin (18);
 470           dcl  move_table                    (move_len) fixed bin (35) aligned based;
 471 
 472           if ^get_local_dtp () then return;
 473           ec = 0;
 474           move_len = fixed (rel (addr (dt.lv_array (dt.n_lv_entries + 1))), 18);
 475           spacep -> move_table = dtp -> move_table;
 476           go to term_exit;
 477 
 478 
 479           /* --------------------------------------------------------- */
 480 
 481 check_pv: entry (a_pvname, ec);
 482 
 483           if ^get_local_dtp () then return;
 484 
 485           found = "0"b;
 486           do i = 1 to dt.n_entries while (^found);
 487                dtep = addr (dt.array (i));
 488                if a_pvname = dte.pvname & (dte.used | dte.known) then found = "1"b;
 489                                                                                 /* oughtta take out of tbl here */
 490           end;
 491           go to found_exit;
 492 
 493           /* ------------------------------------------------------- */
 494 
 495 
 496 check_lv: entry (a_hvname, ec);
 497 
 498           dcl  a_hvname                      char (*);
 499 
 500           if ^get_local_dtp () then return;
 501 
 502           found = "0"b;
 503           do i = 1 to dt.n_lv_entries while (^found);
 504                if dt.lv_array (i).lvname = a_hvname & dt.lv_array (i).used & dt.lv_array (i).hv_mounted then found = "1"b;
 505           end;
 506 found_exit:
 507           if ^found then ec = error_table_$mount_not_ready;
 508           else ec = 0;
 509 term_exit:
 510           if must_term then do;
 511                     call cu_$level_set (oldlev);
 512                     call hcs_$terminate_noname (dtp, (0));
 513                end;
 514           return;
 515 
 516           /* --------------------------------------------------------- */
 517 
 518 
 519 set_lv_pdir_bit: entry (a_hvname, a_bit, ec);
 520 
 521           dcl  a_bit                         bit (1) aligned;
 522 
 523           ec = 0;                                                               /* until something goes wrong */
 524           if ^get_local_dtp () then return;
 525           found = ""b;
 526           do i = 1 to dt.n_lv_entries while (^found);
 527                if dt.lv_array (i).lvname = a_hvname & dt.lv_array (i).used then do;
 528                          found = "1"b;
 529                          if dt.lv_array (i).public then
 530                               dt.lv_array (i).pdirs_ok = a_bit;
 531                          else ec = error_table_$private_volume;
 532                     end;
 533           end;
 534           if ^found then
 535                ec = error_table_$mount_not_ready;
 536           return;
 537 
 538 
 539           /* --------------------------------------------------------- */
 540 
 541 
 542 set_vacate_pdirs_bit: entry (a_hvname, a_bit, ec);
 543 
 544           ec = 0;                                                               /* until something goes wrong */
 545           if ^get_local_dtp () then return;
 546           found = ""b;
 547           do i = 1 to dt.n_lv_entries while (^found);
 548                if dt.lv_array (i).lvname = a_hvname & dt.lv_array (i).used then do;
 549                          found = "1"b;
 550                          if dt.lv_array (i).public then do;
 551                                    dt.lv_array (i).vacate_pdirs = a_bit;
 552                                    if dt.lv_array (i).pdirs_ok & a_bit then dt.lv_array (i).pdirs_ok = "0"b;
 553                               end;
 554                          else ec = error_table_$private_volume;
 555                     end;
 556           end;
 557           if ^found then
 558                ec = error_table_$mount_not_ready;
 559           return;
 560 
 561 
 562           /* --------------------------------------------------------- */
 563 
 564 add_del: entry (a_device_name, a_adding_drive, true_if_found, ec);
 565 
 566           dcl  a_device_name                 char (*),
 567                a_adding_drive                bit (1) aligned,
 568                true_if_found                 bit (1) aligned;
 569           dcl  adding_drive                  bit (1);                           /* "0"b if deleting device "1"b if adding device */
 570 
 571           adding_drive = a_adding_drive;
 572           dtp = sdtp;
 573           ec = 0;
 574           true_if_found = "0"b;
 575           do i = 1 to dt.n_entries;
 576                dtep = addr (dt.array (i));
 577                if dte.drive_name = a_device_name then do;
 578                          true_if_found = dte.storage_system;
 579                          if dte.used | dte.known then ec = error_table_$io_still_assnd;
 580                          else if dte.deleted ^= adding_drive then ec = error_table_$action_not_performed;
 581                          else do;
 582                                    if adding_drive then
 583                                         call admin_gate_$ioi_add_device ((dte.drive_name), ec);
 584                                    else call admin_gate_$ioi_delete_device ((dte.drive_name), ec);
 585                                    if ec = 0 then do;
 586                                              dte.deleted = ^adding_drive;
 587                                              if dte.storage_system then do;
 588                                                        call make_blank;
 589                                                        call admin_gate_$syserr
 590                                                             (ANNOUNCE, "disk_table_: ^[Added^;Deleted^] drive ^a.", (adding_drive), (a_device_name));
 591                                                   end;
 592                                       end;
 593                               end;
 594                     end;
 595           end;
 596           return;
 597 
 598           /* -------------------------------------------------------- */
 599 
 600 ss_io_reconfig: entry (a_pvtx, a_from_ss, ec);
 601 
 602           dcl  a_from_ss                     bit (1);
 603           dcl  from_ss                       bit (1) aligned;
 604 
 605           from_ss = a_from_ss;
 606           i = a_pvtx;
 607           dtp = sdtp;
 608           dtep = addr (dt.array (i));
 609           xec = 0;
 610           if from_ss ^= dte.storage_system then do;
 611                     ec = error_table_$invalid_state;
 612                     return;
 613                end;
 614           if from_ss then if dte.known | dte.used then do;
 615                          ec = error_table_$io_still_assnd;
 616                          return;
 617                     end;
 618           call make_blank;
 619           call cu_$level_get (oldlev);
 620           call cu_$level_set (1);
 621           if dte.is_sub_vol then do;
 622                                                                                 /* if this is a drive that contains subvolumes only tell rcp about the last one */
 623                     if dte.sv_num = (dte.num_of_sv - 1) then
 624                                                                                 /* This should be the last one */
 625                          call rcp_control_$ss_io_interchange ((substr (dte.drive_name, 1, 7)), from_ss, (dte.deleted), xec);
 626                end;
 627           else call rcp_control_$ss_io_interchange ((dte.drive_name), from_ss, (dte.deleted), xec);
 628           call cu_$level_set (oldlev);
 629           if xec = 0 then call initializer_gate_$ss_io_reconfigure (i, from_ss, xec);
 630           if xec = 0 then dte.storage_system = ^from_ss;
 631           ec = xec;
 632           return;
 633 
 634           /* --------------------------------------------------------- */
 635 
 636 demount_pv: entry (a_pvtx, ec);
 637 
 638           dtp = sdtp;
 639           dtep = addr (dt.array (a_pvtx));
 640 
 641           if ^dte.storage_system | ^dte.used then do;
 642                     ec = error_table_$action_not_performed;
 643                     return;
 644                end;
 645 
 646           lvx = dte.lvx;
 647           if lvx < 0 | lvx > dt.n_lv_entries then do;
 648                     ec = error_table_$action_not_performed;
 649                     return;
 650                end;
 651           lvep = addr (dt.lv_array (lvx));
 652 
 653           if ^lve.demounting then do;
 654                     ec = error_table_$io_still_assnd;
 655                     return;
 656                end;
 657 
 658           call initializer_gate_$demount_pv (a_pvtx, ec);
 659 
 660           if ec = 0 then call make_demounted;
 661 
 662           return;
 663 
 664           /* --------------------------------------------------------- */
 665 
 666 demount_lv: entry (a_lvx, a_dhv_act, ec);
 667 
 668           dcl  a_lvx                         fixed bin, a_dhv_act fixed bin;
 669 
 670           dtp = sdtp;
 671           lvx = a_lvx;
 672           lvep = addr (dt.lv_array (lvx));
 673           if ^lve.used then do;
 674                     lve.hv_mounted, lve.demounting, lve.mounting = "0"b;        /* for robustness */
 675                     ec = error_table_$action_not_performed;
 676                     return;
 677                end;
 678 
 679           if lvx = dt.array (dt.rpvx).lvx
 680                | (lve.pdirs_ok & lve.hv_mounted) then do;
 681                     ec = error_table_$action_not_performed;
 682                     return;
 683                end;
 684 
 685           ec = 0;                                                               /* Unless otherwise */
 686 
 687           if a_dhv_act = 1 then do;                                             /* Stop a mhv */
 688                     if ^lve.mounting then go to fail;                           /* argerr */
 689                     lve.mounting = "0"b;
 690                     do i = 1 to dt.n_entries while (^(dt.array (i).used & dt.array (i).lvx = lvx)); end;
 691                     if i <= dt.n_entries then lve.demounting = "1"b;
 692                end;
 693           else if a_dhv_act = 2 then do;                                        /* Demount start, take out of r0 */
 694                     if lve.mounting then go to fail;
 695                     if ^lve.hv_mounted then go to fail;
 696                     call initializer_gate_$delete_lv (lve.lvid, ec);
 697                     if ec = error_table_$logical_volume_not_defined then ec = 0;/* Ignore not-there */
 698                     lve.demounting = "1"b;
 699                     lve.hv_mounted = "0"b;
 700                end;
 701           else if a_dhv_act = 3 then do;                                        /* Turn off demounting */
 702                     if ^lve.demounting then go to fail;
 703                     lve.demounting = "0"b;
 704                end;
 705 
 706           if ec ^= 0 then return;
 707 
 708           do i = 1 to dt.n_entries;                                             /* Make Ops happy, erase the thing. */
 709                dtep = addr (dt.array (i));
 710                if dte.pre_accepted & (dte.lvx = lvx) then call make_demounted;
 711           end;
 712           if ^lve.used then return;
 713 
 714           lve.mounting = "0"b;                                                  /* General principles, minimize screwups */
 715           call develop_lve_status_anon;                                         /* Check for weird case */
 716 
 717           return;
 718 %page;
 719           /*        SUBROUTINES AND OTHER UTILE CONSTRUCTIONS         */
 720 
 721 
 722 get_it_known: proc (b_dtx, b_ec) returns (bit (1));
 723 
 724           /* Call verify_label, leave drive hungry or known */
 725 
 726           dcl  b_dtx                         fixed bin;                         /* passed for convenience */
 727           dcl  b_ec                          fixed bin (35);
 728 
 729           call verify_label_ (dtp, dtep, b_dtx, b_ec);
 730           if b_ec = 0 then do;
 731                     call make_known;
 732                     return ("1"b);
 733                end;
 734           return ("0"b);
 735 
 736      end get_it_known;
 737 
 738 
 739 verify_drive_vanish_pve: proc (b_dtep, b_pvname, ec);
 740           dcl  ec                            fixed bin (35);
 741           dcl  b_dtep                        ptr;
 742           dcl  b_pvname                      char (*);
 743           dcl  bpk                           fixed bin;
 744           dcl  save_dtep                     ptr;
 745           dcl  k                             fixed bin;
 746 
 747           do k = 1 to dt.n_entries;
 748                aux_dtep = addr (dt.array (k));
 749                if aux_dtep = b_dtep then bpk = k;
 750                else do;
 751                          if (adte.used | adte.known) & adte.pvname = b_pvname
 752                          then do;
 753                                    ec = error_table_$io_still_assnd;
 754                                    return;
 755                               end;
 756                          if (adte.pre_accepted | adte.demounted) & adte.pvname = b_pvname then call forgetter (k);
 757                     end;
 758           end;
 759           aux_dtep = b_dtep;
 760           if adte.used | adte.known then if adte.pvname = b_pvname then ec = 0;
 761                else ec = error_table_$io_still_assnd;
 762           else if adte.pre_accepted | adte.demounted then call forgetter (bpk);
 763           if ec = 0 then do;
 764                     save_dtep = dtep;
 765                     dtep = b_dtep;                                              /* This is what lambda was invented for */
 766                     call make_blank;
 767                     dtep = save_dtep;
 768                end;
 769      end;
 770 
 771 
 772 forgetter: entry (a_indx);                                                      /* recursive only */
 773           dtp = sdtp;
 774           dtep = addr (dt.array (a_indx));
 775           call make_blank;
 776           return;
 777 %page;
 778 
 779 make_root_pve:
 780      proc;
 781 
 782           dcl  mrpve_pvtx                    fixed bin;
 783 
 784           /* This procedure is called to construct DT PV entries for volumes
 785    accepted by the hardcore during initialization.  PVT and DT pointers
 786    are valid. */
 787 
 788           dte.storage_system = "1"b;                                            /* Get good params going */
 789           dte.deleted = "0"b;
 790           dte.rpv = pvte.rpv;                                                   /* Get rpv bit */
 791           dte.pvid = pvte.pvid;
 792           if dte.rpv then dt.rpvx = i;
 793           dte.lvx = 1;
 794           dte.permanent = "1"b;
 795           call make_root_lve;
 796           call verify_label_ (dtp, dtep, i, ec);
 797 
 798           /* Special kludge in verify_label_ will cause name fillin into DT instead of check.  lvname = root triggers this. */
 799 
 800           dte.hc_accepted = "1"b;                                               /* Cause comparator to ignore. */
 801           call make_used;
 802 
 803           do mrpve_pvtx = 1 to dt.n_entries;
 804 
 805                /* Since this is the first pass of mdx init, flush all other claims to this volume, regardless of
 806    how strong they are. */
 807 
 808                aux_dtep = addr (dt.array (mrpve_pvtx));
 809                if aux_dtep ^= dtep then do;                                     /* Don't consider self */
 810                          if adte.pvname = dte.pvname | adte.pvid = dte.pvid
 811                          then do;
 812                                    call admin_gate_$syserr (ANNOUNCE, "disk_table_: Root PV ""^a"" moved from ^a to ^a.",
 813                                         dte.pvname, adte.drive_name, dte.drive_name);
 814                                    call force_init_dte (mrpve_pvtx);
 815                               end;
 816                     end;
 817           end;
 818      end;
 819 
 820 
 821 make_root_lve: proc;
 822 
 823           lvep = addr (dt.lv_array (1));
 824           if lve.lvname ^= "root" | ^lve.used then do;
 825                     dt.n_lv_entries = 1;
 826                     unspec (lve) = ""b;
 827                     lve.public = "1"b;
 828                     lve.lvid = pvte.lvid;
 829                     lve.lvname = "root";
 830                     lve.min_access_class = ""b;
 831                     lve.max_access_class = sys_info$access_class_ceiling;
 832                end;
 833           lve.used = "1"b;                                                      /* gc turned off */
 834           lve.hv_mounted = "1"b;
 835 
 836      end make_root_lve;
 837 
 838 
 839 force_init_dte:                                                                 /* procedure used during disk_table initialzation to clear a particular entry */
 840      proc (dte_index);
 841 
 842           dcl  dte_index                     fixed bin parameter;
 843           dcl  l_dtep                        ptr;
 844           dcl  1 l_dte                       aligned like dte based (l_dtep);
 845           dcl  l_pvtep                       ptr;
 846           dcl  1 l_pvte                      aligned like pvte based (l_pvtep);
 847 
 848           l_dtep = addr (dt.array (dte_index));
 849           l_pvtep = addr (pvt_array (dte_index));
 850           unspec (l_dte) = ""b;
 851           num_pic = l_pvte.logical_area_number;
 852           l_dte.is_sub_vol = l_pvte.is_sv;
 853           l_dte.sv_num = l_pvte.sv_num;
 854           l_dte.drive_name = l_pvte.devname || "_" || num_pic;
 855           if l_dte.is_sub_vol then l_dte.drive_name = rtrim (l_dte.drive_name) || rtrim (l_pvte.sv_name);
 856           l_dte.device_type = l_pvte.device_type;
 857           l_dte.storage_system = l_pvte.storage_system;
 858           l_dte.permanent = l_pvte.permanent;
 859           l_dte.num_of_sv = l_pvte.num_of_svs;
 860           l_dte.sv_name = l_pvte.sv_name;
 861           return;
 862 
 863      end force_init_dte;
 864 %page;
 865 
 866 verify_whole_lv: proc (desired_lvx, ec);
 867 
 868           /* This procedure is called when it is desired to mount an entire hierarchy volume,
 869    and all constituent pv's are either pre_accepted, known, or
 870    in use (from a previous failing attempt).  It tries to accept them all, promoting
 871    all drives up through the states.  As is the convention in mdx, any time
 872    a label is read which contradicts a pre_accepted, the latter is turned off. No volumes
 873    are promoted to used (ring 0 called) unless all labels check. */
 874 
 875 
 876           dcl  desired_lvx                   fixed bin, ec fixed bin (35);
 877 
 878           dcl  i                             fixed bin;
 879           dcl  1 local_lvte                  aligned like lvte;
 880 
 881           lvep = addr (dt.lv_array (desired_lvx));
 882           do i = 1 to dt.n_entries;
 883                dtep = addr (dt.array (i));
 884                if dte.lvx = desired_lvx & dte.pre_accepted then do;
 885                          if ^get_it_known (i, ec) then do;
 886                                    tpvtx = i;
 887                                    call make_assumed;
 888                                    return;
 889                               end;
 890                     end;
 891           end;
 892           do i = 1 to dt.n_entries;
 893                dtep = addr (dt.array (i));
 894                if dte.lvx = desired_lvx & dte.known then do;
 895                          call initializer_gate_$accept_fs_disk (i, ec);
 896                          if ec = error_table_$fsdisk_not_salv then do;          /* salvage if needed */
 897                                    call initializer_gate_$vol_salv (i, ""b, ec);
 898                                    call initializer_gate_$accept_fs_disk (i, ec);
 899                               end;
 900 
 901                          if ec ^= 0 then do;
 902                                    tpvtx = i;
 903                                    return;
 904                               end;
 905                          call make_used;
 906                          if lve.hv_mounted then call initializer_gate_$add_pv_to_lv (lve.lvid, dte.pvid, ec);
 907                     end;
 908           end;
 909           if ^lve.hv_mounted then do;                                           /* Want to mount new vol? */
 910                     unspec (local_lvte) = "0"b;
 911                     local_lvte.lvid = lve.lvid;
 912                     local_lvte.access_class.min = lve.min_access_class;
 913                     local_lvte.access_class.max = lve.max_access_class;
 914                     local_lvte.public = lve.public;
 915                     call initializer_gate_$define_lv (addr (local_lvte), ec);
 916                     if ec = 0 then do;
 917                               lve.hv_mounted = "1"b;
 918                               lve.mounting = "0"b;
 919                          end;
 920                end;
 921 
 922      end verify_whole_lv;
 923 %page;
 924 
 925 check_lv_complete: proc (ec);
 926 
 927           /* This procedure checks the registration for a given LV, and determines if they are all in the
 928    disk table. */
 929 
 930           dcl  ec                            fixed bin (35);
 931 
 932           dcl  pvap                          ptr;
 933           dcl  npv                           fixed bin;
 934           dcl  (i, j)                        fixed bin;
 935           dcl  (found, ready)                bit (1);
 936           dcl  1 pva                         (100) based (pvap) aligned,
 937                     2 pvname                 char (32),
 938                     2 device_type            fixed bin,
 939                     2 pad                    fixed bin;
 940 
 941           pvap = addr (dt.lv_array (dt.max_n_entries + 1));
 942           call volume_registration_mgr_$get_lv_pvinfo ((lve.lvname), pvap, npv, (0), ec);
 943           if ec ^= 0 then return;
 944 
 945           ec = 0;
 946           ready = "1"b;
 947           do i = 1 to npv while (ec = 0);                                       /* Look for any unmounted vol */
 948                found = "0"b;
 949                do j = 1 to dt.n_entries while (^found);
 950                     dtep = addr (dt.array (j));
 951                     if dte.pvname = pva (i).pvname
 952                     then if dte.used | dte.known then found = "1"b;
 953                          else if dte.pre_accepted then do;
 954                                    found = "1"b;
 955                                    ready = "0"b;
 956                               end;
 957                end;
 958                if ^found then ec = 1;
 959           end;
 960           if ec = 0 & ^ready then ec = -1;
 961 
 962      end check_lv_complete;
 963 %page;
 964 
 965           /*        SUBROUTINES TO PERFORM STATE TRANSIT              */
 966 
 967           /* All assume dtep is set */
 968 
 969 make_blank: proc;
 970 
 971           call hold_status;
 972           dte.pre_accepted, dte.used, dte.known, dte.demounted = "0"b;
 973           call develop_lve_status;
 974      end;
 975 
 976 make_assumed: proc;
 977 
 978           dte.used, dte.known, dte.demounted, dte.used = "0"b;
 979           dte.pre_accepted = "1"b;
 980           if dte.lvx > 0 & dte.lvx <= dt.n_lv_entries then
 981                dt.lv_array (dte.lvx).demounted_only = "0"b;
 982      end;
 983 
 984 make_demounted: proc;
 985 
 986           prev_state = "1"b;                                                    /* lvx must be good */
 987           dte.pre_accepted, dte.used, dte.known = "0"b;
 988           dte.demounted = "1"b;
 989           call develop_lve_status;
 990      end;
 991 
 992 make_known: proc;
 993 
 994           dte.pre_accepted, dte.used, dte.demounted = "0"b;
 995           dte.known = "1"b;
 996           if dte.lvx > 0 & dte.lvx <= dt.n_lv_entries then
 997                dt.lv_array (dte.lvx).demounted_only = "0"b;
 998      end;
 999 
1000 make_used: proc;
1001 
1002           dte.pre_accepted, dte.demounted, dte.known = "0"b;
1003           if ^dte.used then call admin_gate_$syserr
1004                     (LOG, "disk_table_: accepted PV ^a on ^a.", dte.pvname, dte.drive_name);
1005           dte.used = "1"b;
1006           if dte.lvx > 0 & dte.lvx <= dt.n_lv_entries then
1007                dt.lv_array (dte.lvx).demounted_only = "0"b;
1008      end;
1009 
1010 hold_status: proc;
1011           prev_state = dte.used | dte.pre_accepted | dte.known | dte.demounted;
1012      end;
1013 
1014 develop_lve_status: proc;
1015 
1016           dcl  ii                            fixed bin;
1017           dcl  l_lvx                         fixed bin;
1018           dcl  hold                          bit (1) init ("0"b);
1019 
1020           if ^prev_state then do;
1021                     dte.lvx = -2;                                               /* sure asdmp */
1022                     return;                                                     /* dont check garbage */
1023                end;
1024           l_lvx = dte.lvx;
1025           go to join;
1026 
1027 develop_lve_status_anon: entry;
1028           l_lvx = lvx;                                                          /* global */
1029 join:     if l_lvx < 0 | l_lvx > dt.n_lv_entries then return;
1030           aux_lvep = addr (dt.lv_array (l_lvx));
1031           do ii = 1 to dt.n_entries;
1032                aux_dtep = addr (dt.array (ii));
1033                if adte.lvx = l_lvx then do;
1034                          if adte.demounted then hold = "1"b;
1035                          else if adte.used | adte.known | adte.pre_accepted then do;
1036                                    alve.demounted_only = "0"b;
1037                                    return;
1038                               end;
1039                     end;
1040           end;
1041 
1042           if hold then do;                                                      /* He thinks its vanished */
1043                     alve.demounted_only = "1"b;
1044                     alve.prev_bootload = "0"b;                                  /* No more special privileges */
1045                end;
1046           if alve.mounting then return;
1047           if ^hold then do;
1048                     alve.used = "0"b;
1049                     alve.lvid = "0"b;
1050                end;
1051 
1052      end develop_lve_status;
1053 %page;
1054 
1055 get_local_dtp: proc returns (bit (1));
1056 
1057           dtp = sdtp;
1058           must_term = "0"b;
1059           if dtp = null () then do;                                             /* we're not Inz */
1060                     call cu_$level_get (oldlev);
1061                     call cu_$level_set (1);
1062                     call hcs_$initiate (ROOT, "disk_table", "", 0, 1, dtp, ec);
1063                     if dtp = null () then do;
1064                               call cu_$level_set (oldlev);
1065                               return ("0"b);
1066                          end;
1067                     must_term = "1"b;
1068                end;
1069           return ("1"b);
1070 
1071      end;
1072 test: entry (aroot);
1073 
1074           dcl  aroot                         char (*);
1075 
1076           SL1, ROOT = aroot;
1077           call volume_registration_mgr_$test (aroot);
1078           return;
1079                                                                                 /* format: off */
1080 %page; %include disk_table;
1081 %page; %include lvt;
1082 %page; %include pvt;
1083 %page; %include pvte;
1084 %page; %include fs_vol_label;
1085 %page; %include disk_pack;
1086 %page; %include syserr_constants;
1087 %page;
1088           /* BEGIN MESSAGE DOCUMENTATION
1089 
1090    Message:
1091    disk_table_: Added drive DSKX_NN
1092 
1093    S:     $info
1094 
1095    T:     $response
1096 
1097    M:     The operator has added a storage system disk drive with adddev.
1098 
1099    A:     $ignore
1100 
1101    Message:
1102    disk_table_: Deleted drive DSKX_NN
1103 
1104    S:     $info
1105 
1106    T:     $response
1107 
1108    M:     The operator has deleted a storage system disk drive with deldev.
1109 
1110    A:     $ignore
1111 
1112    Message:
1113    disk_table_: accepted PV PVNAME on DSKX_NN
1114 
1115    S:     $log
1116 
1117    T:     $response
1118    $init
1119 
1120    M:     A storage system physical volume has been placed in use.
1121    The volume and drive name are identified.
1122 
1123    A:     $ignore
1124    This message is provided for the benefit of
1125    automatic error analysis and logging.
1126 
1127 
1128    Message:
1129    disk_table_: Deleted root PV "PV_NAME" on DSKX_NN.
1130 
1131    S:     $beep
1132 
1133    T:     $init
1134 
1135    M:     The specified drive did not appear in the ROOT config card.  Thus,
1136    it was removed from the disk_table_.  This will also occur when the
1137    volume is intentionally deleted.
1138 
1139    A:     $notify
1140 
1141 
1142    Message:
1143    disk_table_: Root PV "PV_NAME" moved from DSKX_NN to DSKX_NN.
1144 
1145    S:     $info
1146 
1147    T:     $init
1148 
1149    M:     The specified root volume has been moved to a different drive
1150    since the last shutdown.
1151 
1152    A:     $ignore
1153 
1154 
1155    END MESSAGE DOCUMENTATION */
1156 
1157      end mdx;