1 /****^  ***********************************************************
   2         *                                                         *
   3         * Copyright, (C) Honeywell Bull Inc., 1987                *
   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 /*
  14                                 vtoc_man$get_vtoce
  15                                         $read_ahead_vtoce
  16                                         $put_vtoce
  17                                         $alloc_and_put_vtoce
  18                                         $free_vtoce
  19                                         $free_vtoce_for_scavenge
  20                                         $cleanup_pv
  21                                         $stabilize
  22                                         $crawlout
  23 
  24           The specification of each function is given with the entry point declaration.
  25 
  26           Modified by :
  27           08/14/75  Andre Bensoussan - Written for the new storage system.
  28           06/02/76 by Bernard Greenberg for non-fatal write errors (hot buffers).
  29           06/07/76 by Bernard Greenberg for vtoc_man$stabilize.
  30           09/17/76 by R. Bratt to add per-process meters.
  31           03/12/80 by J. A. Bush to fix "out of buffers" bug
  32           04/16/81 by J. Bongiovanni to recover on crawlout with vtoc buffer lock ,
  33                    bug in cleanup_pv (vtoce 4 trashing), validate vtoc index
  34           03/08/82 by J. Bongiovanni for new PVTE and stocks
  35           07/07/82 by J. Bongiovanni - rewritten for new buffer strategy
  36                    (almost always read entire VTOCE, do write in 1 I/O).
  37           07/26/82 by J. Bongiovanni to add free_vtoce_for_scavenge and
  38                    read_ahead_vtoce
  39           11/06/82 by J. Bongiovanni to add pseudo-clock for scavenger race
  40           09/20/83 by E. N. Kittlitz to implement the former's last request: clear pad when writing
  41           01/17/84 by Jeffrey I. Schiller to requeue I/O for "hot" buffers.
  42           */
  43 
  44 
  45 /****^  HISTORY COMMENTS:
  46   1) change(86-01-16,Fawcett), approve(86-04-11,MCR7383),
  47      audit(86-06-02,GDixon), install(86-07-17,MR12.0-1097):
  48      Add support for 512_WORD_IO devices, (one vtoce per sector), and add
  49      software RAR.
  50                                                    END HISTORY COMMENTS */
  51 
  52 
  53 /* format: style3 */
  54 vtoc_man$get_vtoce:
  55      proc (Pvid, Pvtx, Vtocx, Parts, Copy_Vtocep, Code);
  56 
  57 /*  Parameter  */
  58 
  59 dcl       Copy_Vtocep         ptr;                          /* Pointer to copy of VTOCE to be written or read into */
  60 dcl       Code                fixed bin (35);               /* Status code */
  61 dcl       Parts               bit (3);                      /* Mask of parts of interest */
  62 dcl       Pvid                bit (36) aligned;             /* Physical Volume ID */
  63 dcl       Pvtx                fixed bin;                    /* PVTE index */
  64 dcl       Vtocx               fixed bin;                    /* VTOCE index on volume */
  65 
  66 /*  Automatic  */
  67 
  68 dcl       bufx                fixed bin;
  69 dcl       code                fixed bin (35);
  70 dcl       dev_type            fixed bin;
  71 dcl       hot_buffer_tried    bit (1);
  72 dcl       1 local_vtoce_buffer
  73                               aligned like vtoce_buffer;
  74 dcl       old_pseudo_clock    fixed bin (35);
  75 dcl       p99                 pic "99";
  76 dcl       parts               bit (3) aligned;
  77 dcl       parts_to_write      bit (3) aligned;
  78 dcl       pvid                bit (36) aligned;
  79 dcl       pvtx                fixed bin;
  80 dcl       return_vtocx        fixed bin;
  81 dcl       sector_read_required
  82                               bit (1) aligned;
  83 dcl       vtocx               fixed bin;
  84 dcl       wait_event          bit (36) aligned;
  85 
  86 /*  Static  */
  87 
  88 dcl       ALL_PARTS           bit (3) aligned int static options (constant) init ("111"b);
  89 dcl       CORE_OFFSET         (0:7) fixed bin int static options (constant) init (0, 128, 64, 64, 0, 0, 0, 0);
  90 dcl       MAX_PSEUDO_CLOCK    fixed bin (35) int static options (constant) init (1000000);
  91 dcl       MAX_STEPS           fixed bin int static options (constant) init (10000);
  92 dcl       SECTOR_OFFSET       (0:7) fixed bin int static options (constant) init (0, 2, 1, 1, 0, 0, 0, 0);
  93 dcl       SECTORS_TO_WRITE    (0:7) fixed bin int static options (constant) init (0, 1, 1, 2, 1, 0, 2, 3);
  94 dcl       VALID_WRITE         (0:7) bit (1) aligned int static options (constant)
  95                               init ("0"b, "1"b, "1"b, "1"b, "1"b, "0"b, "1"b, "1"b);
  96 
  97 /*  Based  */
  98 
  99 dcl       1 Copy_Vtoce        aligned like vtoce_buffer based (Copy_Vtocep);
 100 
 101 /*  External  */
 102 
 103 dcl       error_table_$invalid_pvtx
 104                               fixed bin (35) external;
 105 dcl       error_table_$invalid_vtocx
 106                               fixed bin (35) external;
 107 dcl       error_table_$pvid_not_found
 108                               fixed bin (35) external;
 109 dcl       error_table_$vtoc_io_err
 110                               fixed bin (35) external;
 111 dcl       error_table_$vtoce_free
 112                               fixed bin (35) external;
 113 dcl       pds$processid       bit (36) aligned external;
 114 dcl       pds$process_group_id
 115                               char (32) aligned external;
 116 dcl       pds$vtoc_reads      fixed bin (35) external;
 117 dcl       pds$vtoc_writes     fixed bin (35) external;
 118 dcl       pvt$n_entries       fixed bin external;
 119 
 120 /*  Entry  */
 121 
 122 dcl       dctl$read_sectors   entry (fixed bin, fixed bin (24), bit (18) aligned, fixed bin, fixed bin);
 123 dcl       dctl$write_sectors  entry (fixed bin, fixed bin (24), bit (18) aligned, fixed bin, fixed bin);
 124 dcl       disk_run            entry;
 125 dcl       lock$lock_fast      entry (ptr);
 126 dcl       lock$unlock_fast    entry (ptr);
 127 dcl       pxss$addevent       entry (bit (36) aligned);
 128 dcl       pxss$delevent       entry (bit (36) aligned);
 129 dcl       pxss$wait           entry;
 130 dcl       syserr              entry options (variable);
 131 dcl       vtoc_search$hash_in entry (ptr);
 132 dcl       vtoc_search$hash_out
 133                               entry (ptr);
 134 dcl       vtoc_search$search  entry (fixed bin, fixed bin, ptr);
 135 dcl       vtoce_stock_man$check_in_use
 136                               entry (ptr, fixed bin, fixed bin (35));
 137 dcl       vtoce_stock_man$get_free_vtoce
 138                               entry (ptr, fixed bin);
 139 dcl       vtoce_stock_man$return_if_not_free
 140                               entry (ptr, fixed bin, fixed bin (35));
 141 dcl       vtoce_stock_man$return_free_vtoce
 142                               entry (ptr, fixed bin);
 143 
 144 /*  Builtin  */
 145 
 146 dcl       addr                builtin;
 147 dcl       bin                 builtin;
 148 dcl       bit                 builtin;
 149 dcl       convert             builtin;
 150 dcl       divide              builtin;
 151 dcl       mod                 builtin;
 152 dcl       null                builtin;
 153 dcl       ptr                 builtin;
 154 dcl       rel                 builtin;
 155 dcl       size                builtin;
 156 dcl       substr              builtin;
 157 dcl       unspec              builtin;
 158 %page;
 159 /*        GET_VTOCE
 160 
 161           FUNCTION - This procedure copies the  vtoc  entry  defined  by  the
 162           input  arguments  (pvtx,vtocx)  into  the  caller's area pointed to by
 163           (copy_vtocep). The argument (parts) specifies  what  portions  of  the
 164           vtoc  entry is to be copied. The 64-word portion number i of the vtoce
 165           is copied into the user area only  if  bit  number  i  is  ON  in  the
 166           argument  parts.  Three  error  code may be returned: pvid_not_found,
 167           vtoc_io_err, or invalid_vtocx. */
 168 
 169           pvid = Pvid;
 170           pvtx = Pvtx;
 171           vtocx = Vtocx;
 172           parts = Parts;
 173           Code = 0;
 174 
 175           call SETUP_LOCK (pvtx, code);
 176           if code ^= 0
 177           then goto GET_VTOCE_RETURNS;
 178 
 179           call VALIDATE_VTOCX (vtocx, code);
 180           if code ^= 0
 181           then goto GET_VTOCE_RETURNS;
 182 
 183 
 184           call READ (pvtx, vtocx, parts, vtoc_buf_descp, vtoc_bufp, sector_read_required, code);
 185           if code ^= 0
 186           then goto GET_VTOCE_RETURNS;
 187 
 188           unspec (local_vtoce_buffer) = unspec (vtoce_buffer);
 189 
 190 GET_VTOCE_RETURNS:
 191           call UNLOCK;
 192           vtoc_buffer.meters.call_get = vtoc_buffer.meters.call_get + 1;
 193 
 194           if code = 0
 195           then call COPY_PARTS (parts, addr (local_vtoce_buffer), Copy_Vtocep);
 196 
 197           Code = code;
 198 
 199           return;
 200 %page;
 201 /*        READ_AHEAD_VTOCE -
 202 
 203           FUNCTION - This procedure initiates a read to a specified VTOC entry,
 204           unless the VTOC entry is already in a VTOC buffer. It is similar to
 205           get_vtoce, except that it does not wait, and it returns no data
 206           to the caller. It is intended for routines which scan the VTOC
 207           sequentially (or in any predetermined order), to overlap VTOC I/O
 208           with processing. Three error codes may be returned: pvid_not_found,
 209           vtoc_io_err, or invalid_vtocx. */
 210 
 211 read_ahead_vtoce:
 212      entry (Pvid, Pvtx, Vtocx, Parts, Code);
 213 
 214           pvid = Pvid;
 215           pvtx = Pvtx;
 216           vtocx = Vtocx;
 217           parts = Parts;
 218           Code = 0;
 219 
 220           call SETUP_LOCK (pvtx, code);
 221           if code ^= 0
 222           then goto READ_AHEAD_VTOCE_RETURNS;
 223 
 224           call VALIDATE_VTOCX (vtocx, code);
 225           if code ^= 0
 226           then goto READ_AHEAD_VTOCE_RETURNS;
 227 
 228           call READ_AHEAD (pvtx, vtocx, parts, vtoc_buf_descp, vtoc_bufp, sector_read_required, code);
 229 
 230 READ_AHEAD_VTOCE_RETURNS:
 231           call UNLOCK;
 232 
 233 
 234           Code = code;
 235 
 236           return;
 237 
 238 
 239 %page;
 240 /*        PUT_VTOCE -
 241 
 242           FUNCTION - This procedure copies the vtoc  entry  from  the  user's
 243           area  located at (copy_vtocep) into the real vtoc entry defined by the
 244           (pvtx,vtocx) pair. The argument (parts) specifies what portions of the
 245           user's area is to be copied into the  real  vtoc  entry.  The  64-word
 246           portion  number  i  of  the user's vtoce is copied into the real vtoce
 247           only if bit number i is ON in the input argument parts. Three error
 248           codes may be returned: pvid_not_found, vtoc_io_err, or invalid_vtocx. */
 249 
 250 put_vtoce:
 251      entry (Pvid, Pvtx, Vtocx, Parts, Copy_Vtocep, Code);
 252 
 253           pvid = Pvid;
 254           pvtx = Pvtx;
 255           vtocx = Vtocx;
 256           parts = Parts;
 257           Code = 0;
 258           sector_read_required = "0"b;
 259           parts_to_write = parts;
 260           call COPY_PARTS (parts, Copy_Vtocep, addr (local_vtoce_buffer));
 261                                                             /* Avoid segfault with buffers locked */
 262 
 263           call SETUP_LOCK (pvtx, code);
 264           if code ^= 0
 265           then goto PUT_VTOCE_RETURNS;
 266 
 267           call VALIDATE_VTOCX (vtocx, code);
 268           if code ^= 0
 269           then goto PUT_VTOCE_RETURNS;
 270 
 271           vtoc_buffer.unsafe_pvtx = pvtx;                   /* Update in progress */
 272           if (SECTORS_PER_VTOCE (pvte.device_type) = 1) & (parts ^= ALL_PARTS)
 273           then do;                                          /* 512_word sector device and not all parts */
 274                     call READ (pvtx, vtocx, ALL_PARTS, vtoc_buf_descp, vtoc_bufp, sector_read_required, code);
 275                     if code ^= 0
 276                     then goto PUT_VTOCE_RETURNS;
 277                     parts_to_write = ALL_PARTS;
 278                end;
 279 
 280           else call GET_BUFFER (pvtx, vtocx, vtoc_buf_descp, vtoc_bufp, code);
 281                                                             /* Get a buffer, wait until not out-of-service */
 282           if code ^= 0
 283           then goto PUT_VTOCE_RETURNS;
 284           call CLEAR_PAD (addr (local_vtoce_buffer), parts);/* No dirty bits */
 285           call COPY_PARTS (parts, addr (local_vtoce_buffer), vtoc_bufp);
 286                                                             /* Update the buffer */
 287 
 288           call WRITE (parts_to_write, vtoc_buf_descp);      /* Write it out */
 289           if sector_read_required
 290           then vtoc_buffer.meters.soft_rar = vtoc_buffer.meters.soft_rar + 1;
 291 PUT_VTOCE_RETURNS:
 292           vtoc_buffer.unsafe_pvtx = 0;
 293           call UNLOCK;
 294           vtoc_buffer.meters.call_put = vtoc_buffer.meters.call_put + 1;
 295           Code = code;
 296           return;
 297 %page;
 298 /*        ALLOC_AND_PUT_VTOCE -
 299 
 300           FUNCTION - This procedure removes a vtoc entry from the  free  pool
 301           for  the  physical volume defined by (pvtx), initializes the allocated
 302           VTOC entry with the data for the segment being created and returns the
 303           VTOC index of that entry. If there is no more free VTOC entry  in  the
 304           specified  physical  volume, it returns the value (-1). Three error code
 305           may be returned: pvid_not_found, vtoc_io_err, or invalid_vtocx. Whenever
 306           a  non  zero code is returned, the returned vtoc index is (-1). */
 307 
 308 alloc_and_put_vtoce:
 309      entry (Pvid, Pvtx, Copy_Vtocep, Code) returns (fixed bin (17));
 310 
 311           pvid = Pvid;
 312           pvtx = Pvtx;
 313           Code = 0;
 314           return_vtocx = -1;
 315 
 316           unspec (local_vtoce_buffer) = unspec (Copy_Vtoce);/* Avoid segfaults with buffers locked */
 317 
 318           call SETUP_LOCK (pvtx, code);
 319           if code ^= 0
 320           then goto ALLOC_PUT_RETURNS;
 321 
 322 RETRY_ALLOC:
 323           old_pseudo_clock = vtoc_buffer.scavenger_free_p_clock;
 324 
 325           call vtoce_stock_man$get_free_vtoce (pvtep, vtocx);
 326           if vtocx = -1
 327           then goto ALLOC_PUT_RETURNS;                      /* None left */
 328 
 329           call VALIDATE_VTOCX (vtocx, code);                /* Make sure a valid index */
 330           if code ^= 0
 331           then do;
 332                     call SET_VOL_TROUBLE (pvtep, vtocx, "Invalid free");
 333                     goto RETRY_ALLOC;                       /* Might win */
 334                end;
 335 
 336           call READ (pvtx, vtocx, ALL_PARTS, vtoc_buf_descp, vtoc_bufp, sector_read_required, code);
 337           if code ^= 0
 338           then goto ALLOC_PUT_RETURNS;
 339           vtocep = vtoc_bufp;
 340           if vtoce.uid ^= ""b
 341           then do;
 342                     call SET_VOL_TROUBLE (pvtep, vtocx, "UID ^= 0 in free VTOCE");
 343                     goto RETRY_ALLOC;
 344                end;
 345 
 346           if vtoc_buffer.scavenger_free_p_clock ^= old_pseudo_clock
 347           then do;                                          /* Scavenger has freed a VTOCE - better make sure it isn't this one */
 348                     vtoc_buffer.meters.scavenger_free_checks = vtoc_buffer.meters.scavenger_free_checks + 1;
 349                     call vtoce_stock_man$check_in_use (pvtep, vtocx, code);
 350                     if code ^= 0
 351                     then do;                                /* Lost race */
 352                               vtoc_buffer.meters.scavenger_free_losses = vtoc_buffer.meters.scavenger_free_losses + 1;
 353                               goto RETRY_ALLOC;
 354                          end;
 355                end;
 356 
 357           vtoc_buffer.unsafe_pvtx = pvtx;                   /* Update in progress */
 358 
 359           call CLEAR_PAD (addr (local_vtoce_buffer), ALL_PARTS);
 360                                                             /* wash the naughty bits */
 361           unspec (vtoce_buffer) = unspec (local_vtoce_buffer);
 362           call WRITE (ALL_PARTS, vtoc_buf_descp);
 363 
 364           return_vtocx = vtocx;
 365 
 366 ALLOC_PUT_RETURNS:
 367           vtoc_buffer.unsafe_pvtx = 0;
 368           call UNLOCK;
 369           vtoc_buffer.meters.call_alloc = vtoc_buffer.meters.call_alloc + 1;
 370 
 371           Code = code;
 372           return (return_vtocx);
 373 %page;
 374 /*        FREE_VTOCE -
 375 
 376           FUNCTION - This procedure zeros the vtoc entry defined by the input
 377           arguments (pvtx,vtocx). Then it adds that vtoc entry in the free  pool
 378           for  the  physical  volume  defined  by  (pvtx). Three error codes may be
 379           returned: pvid_not_found, vtoc_io_err, or invalid_vtocx. */
 380 
 381 free_vtoce:
 382      entry (Pvid, Pvtx, Vtocx, Code);
 383 
 384           pvid = Pvid;
 385           pvtx = Pvtx;
 386           vtocx = Vtocx;
 387           Code = 0;
 388 
 389           call SETUP_LOCK (pvtx, code);
 390           if code ^= 0
 391           then goto FREE_VTOCE_RETURNS;
 392 
 393           call VALIDATE_VTOCX (vtocx, code);
 394           if code ^= 0
 395           then goto FREE_VTOCE_RETURNS;
 396 
 397           call GET_BUFFER (pvtx, vtocx, vtoc_buf_descp, vtoc_bufp, code);
 398                                                             /* Get a buffer, wait for not out-of-service */
 399           if code ^= 0
 400           then goto FREE_VTOCE_RETURNS;
 401 
 402           unspec (vtoce_buffer.parts) = ""b;                /* Mark it free - the whole thing */
 403           call WRITE (ALL_PARTS, vtoc_buf_descp);
 404 
 405           call vtoce_stock_man$return_free_vtoce (pvtep, vtocx);
 406                                                             /* Return it to the stock */
 407 
 408 FREE_VTOCE_RETURNS:
 409           call UNLOCK;
 410           vtoc_buffer.meters.call_free = vtoc_buffer.meters.call_free + 1;
 411 
 412           Code = code;
 413           return;
 414 %page;
 415 /*        FREE_VTOCE_FOR_SCAVENGE -
 416 
 417           FUNCTION - frees a VTOCE that the volume scavenger thinks is lost
 418           (free but not in map). Under appropriate locks, it checks that the
 419           VTOCE is still free. It calls a special entry in vtoce_stock_man
 420           that frees it only if it is not already free. Four error codes may
 421           be returned: pvid_not_found, vtoc_io_err, invalid_vtocx, or
 422           vtoce_free.
 423 
 424           There is a race here, but it is safe. The VTOCE being freed could
 425           be in allocation, with the allocating process waiting for the
 426           read to complete. If we see the read completing before the
 427           allocating process, we will think that the VTOCE is free and
 428           mark it as such in the map. This is safe, since the VTOCE will
 429           never be allocated with a non-zero UID.
 430 
 431           On the other hand, it is annoying, since it causes spurious volume
 432           inconsistencies. The race is avoided by using a pseudo-clock, which
 433           is incremented under the VTOC Buffer Lock each time we free a
 434           VTOCE for the scavenger. VTOCE allocation checks the value of this
 435           pseudo-clock when it is given a vtocx and after the VTOCE read
 436           completes. If it has changed, it makes sure that the vtocx is
 437           in-use.
 438 */
 439 
 440 free_vtoce_for_scavenge:
 441      entry (Pvid, Pvtx, Vtocx, Code);
 442 
 443 
 444           pvid = Pvid;
 445           pvtx = Pvtx;
 446           vtocx = Vtocx;
 447           Code = 0;
 448 
 449           call SETUP_LOCK (pvtx, code);
 450           if code ^= 0
 451           then goto FREE_FOR_SCAVENGE_RETURNS;
 452 
 453           call VALIDATE_VTOCX (vtocx, code);
 454           if code ^= 0
 455           then goto FREE_FOR_SCAVENGE_RETURNS;
 456 
 457           call READ (pvtx, vtocx, ALL_PARTS, vtoc_buf_descp, vtoc_bufp, sector_read_required, code);
 458           if code ^= 0
 459           then goto FREE_FOR_SCAVENGE_RETURNS;
 460 
 461           vtocep = vtoc_bufp;
 462           if vtoce.uid ^= ""b
 463           then do;
 464                     code = error_table_$vtoce_free;         /* Someone else did it */
 465                     goto FREE_FOR_SCAVENGE_RETURNS;
 466                end;
 467 
 468           unspec (vtoce) = ""b;
 469           call WRITE (ALL_PARTS, vtoc_buf_descp);
 470 
 471           call vtoce_stock_man$return_if_not_free (pvtep, vtocx, code);
 472 
 473           vtoc_buffer.scavenger_free_p_clock = vtoc_buffer.scavenger_free_p_clock + 1;
 474           if vtoc_buffer.scavenger_free_p_clock > MAX_PSEUDO_CLOCK
 475           then vtoc_buffer.scavenger_free_p_clock = 0;
 476 
 477 FREE_FOR_SCAVENGE_RETURNS:
 478           call UNLOCK;
 479 
 480           Code = code;
 481           return;
 482 
 483 
 484 %page;
 485 /*        AWAIT_VTOCE -
 486 
 487           FUNCTION - This procedure is called by  programs which  update vtoces
 488           and subsequently deposit addresses. It awaits all  pendant I/O on a sel-
 489           ected vtoce, so that the addresses  to  be  deposited will not be avail-
 490           able for  reassignment until it is  known that  they no longer appear in
 491           the old vtoce. This is solely for unrecoverable disk failures. The error
 492           codes which may be returned are pvid_not_found, vtoc_io_err, and invalid_vtocx. */
 493 
 494 await_vtoce:
 495      entry (Pvid, Pvtx, Vtocx, Code);
 496 
 497           pvid = Pvid;
 498           pvtx = Pvtx;
 499           vtocx = Vtocx;
 500           Code = 0;
 501 
 502           call SETUP_LOCK (pvtx, code);
 503           if code ^= 0
 504           then goto AWAIT_RETURNS;
 505 
 506           call VALIDATE_VTOCX (vtocx, code);
 507           if code ^= 0
 508           then goto AWAIT_RETURNS;
 509 
 510 RETRY_AWAIT:
 511           call vtoc_search$search (pvtx, vtocx, vtoc_buf_descp);
 512                                                             /* See if the VTOCE still has a buffer */
 513           if vtoc_buf_descp = null ()
 514           then goto AWAIT_RETURNS;                          /* No - easy case */
 515 
 516           if vtoc_buf_desc.os
 517           then do;
 518                     call WAIT (vtoc_buf_descp, code);       /* Wait until not out-of-service */
 519                     if code ^= 0
 520                     then goto AWAIT_RETURNS;                /* Might have disappeared */
 521                     goto RETRY_AWAIT;
 522                end;
 523 
 524           if vtoc_buf_desc.write_sw & vtoc_buf_desc.err     /* Hot buffer */
 525           then code = error_table_$vtoc_io_err;
 526 
 527 AWAIT_RETURNS:
 528           call UNLOCK;
 529           vtoc_buffer.meters.call_await = vtoc_buffer.meters.call_await + 1;
 530 
 531           Code = code;
 532           return;
 533 %page;
 534 /*        CLEANUP_PV -
 535 
 536           FUNCTION - Guarantees that the physical volume supplied does not have
 537           any portion of its VTOC in the vtoc_buffers. If it does, and nothing can be
 538           done about it (hot buffer, hard I/O error), the volume inconsistency
 539           count is increased. */
 540 
 541 cleanup_pv:
 542      entry (Pvtx, Code);
 543 
 544           pvid = ""b;
 545           pvtx = Pvtx;
 546           vtocx = -1;
 547           Code = 0;
 548 
 549           call SETUP_LOCK (pvtx, code);                     /* Will get non-zero code during demount */
 550 
 551           do bufx = 1 to vtoc_buffer.n_bufs;                /* Requeue writes on hot buffers */
 552                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 553                if vtoc_buf_desc.pvtx = pvtx & vtoc_buf_desc.used = "1"b /* This volume, Buffer in use */
 554                     & vtoc_buf_desc.err & vtoc_buf_desc.write_sw & ^vtoc_buf_desc.os
 555                                                             /* Hot buffer */
 556                then call WRITE ((vtoc_buf_desc.parts_used), vtoc_buf_descp);
 557           end;
 558 
 559           do bufx = 1 to vtoc_buffer.n_bufs;                /* Wait for all out-of-service */
 560                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 561                do while (vtoc_buf_desc.pvtx = pvtx & vtoc_buf_desc.used /* This volume, Buffer in use */
 562                     & vtoc_buf_desc.os);                    /* Out-of-service */
 563                     call WAIT (vtoc_buf_descp, code);
 564                end;
 565           end;
 566 
 567           code = 0;
 568           do bufx = 1 to vtoc_buffer.n_bufs;                /* Flush buffers, abandon hot buffers */
 569                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 570                if vtoc_buf_desc.pvtx = pvtx & vtoc_buf_desc.used
 571                                                             /* This volume, Buffer in use */
 572                then do;
 573                          if vtoc_buf_desc.os
 574                          then call syserr (CRASH, "vtoc_man: Buffer out-of-service during cleanup");
 575                          if vtoc_buf_desc.write_sw & vtoc_buf_desc.err
 576                                                             /* Hot buffer */
 577                          then do;
 578                                    call SET_VOL_TROUBLE (pvtep, (vtoc_buf_desc.vtocx),
 579                                         "Hot buffer abandoned during cleanup");
 580                                    code = error_table_$vtoc_io_err;
 581                               end;
 582                          call FLUSH_BUFFER (vtoc_buf_descp);
 583                     end;
 584           end;
 585 
 586           call UNLOCK;
 587 
 588           Code = code;
 589           return;
 590 %page;
 591 /*        STABILIZE -
 592 
 593           FUNCTION - This entry is called only during emergency shutdown. It
 594           makes the vtoc_buffer consistent so that shutdown can succeed. This
 595           process includes busting the lock, rethreading all buffers into
 596           the hash table, abandoning in-progress reads, and setting in-progress
 597           writes to "hot". */
 598 
 599 stabilize:
 600      entry;
 601 
 602           pvid = ""b;
 603           pvtx = -1;
 604           vtocx = -1;
 605 
 606           vtoc_buffer_segp = addr (vtoc_buffer_seg$);
 607           vtoc_buffer.lock.processid = ""b;                 /* Bust the lock */
 608 
 609           call SETUP_LOCK (pvtx, code);
 610 
 611           call RETHREAD;
 612 
 613           do bufx = 1 to vtoc_buffer.n_bufs;
 614                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 615                if vtoc_buf_desc.used & vtoc_buf_desc.os     /* Buffer in use, I/O in progress */
 616                then if vtoc_buf_desc.write_sw
 617                     then do;                                /* Write */
 618                               vtoc_buf_desc.err = "1"b;     /* Make hot */
 619                               vtoc_buf_desc.os = "0"b;
 620                          end;
 621                     else call FLUSH_BUFFER (vtoc_buf_descp);
 622           end;
 623 
 624           call UNLOCK;
 625 
 626           return;
 627 %page;
 628 /*        CRAWLOUT -
 629 
 630           FUNCTION - This entry is called only by verify_lock when it has
 631           found the vtoc buffer lock held by the process.  It checks for
 632           inconsistent buffer states and corrects them (specifically,
 633           out-of-service but no I/O queued).  Before doing this, it waits
 634           for the associated event, to cover the case where the I/O
 635           was queued successfully, but the crawlout occurred afterwards.
 636           If the I/O was not queued successfully, the wait will end
 637           via notify-time-out.  If a physical volume is
 638           potentially inconsistent ("unsafe"), the volume inconsistency
 639           count is increased. Note that the vtoc buffer lock is left locked
 640           on exit - verify_lock busts it for us. */
 641 
 642 crawlout:
 643      entry;
 644 
 645 
 646           vtoc_buffer_segp = addr (vtoc_buffer_seg$);
 647           vtoc_buf_desc_arrayp = ptr (vtoc_buffer_segp, vtoc_buffer.buf_desc_offset);
 648           vtoc_buf_arrayp = ptr (vtoc_buffer_segp, vtoc_buffer.buf_offset);
 649           pvt_arrayp = addr (pvt$array);
 650 
 651           if vtoc_buffer.lock.processid ^= pds$processid
 652           then return;                                      /* Invalid call */
 653 
 654           call RETHREAD;                                    /* May be inconsistent */
 655 
 656           if vtoc_buffer.unsafe_pvtx ^= 0
 657           then do;                                          /* Update in progress */
 658                     pvtep = addr (pvt_array (vtoc_buffer.unsafe_pvtx));
 659                     call SET_VOL_TROUBLE (pvtep, -1, "Update in progress on crawlout by " || pds$process_group_id);
 660                end;
 661 
 662           do bufx = 1 to vtoc_buffer.n_bufs;                /* Look for inconsistent buffers */
 663                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 664                if vtoc_buf_desc.used & vtoc_buf_desc.os & ^vtoc_buf_desc.ioq
 665                                                             /* buffer in use, out-of-service, not queued */
 666                then do;
 667                          pvtx = vtoc_buf_desc.pvtx;
 668                          vtocx = vtoc_buf_desc.vtocx;
 669                          wait_event = bit (bin (vtoc_buffer.wait_event_constant + vtoc_buf_desc.wait_index, 36), 36);
 670                          call pxss$addevent (wait_event);
 671                          call lock$unlock_fast (addr (vtoc_buffer.lock));
 672                          call pxss$wait;                    /* Wait 1 NTO interval */
 673                          call lock$lock_fast (addr (vtoc_buffer.lock));
 674                          if vtoc_buf_desc.used & vtoc_buf_desc.os
 675                               & ^vtoc_buf_desc.ioq /* Buffer in use, out-of-service, not queued */
 676                               & vtoc_buf_desc.pvtx = pvtx & vtoc_buf_desc.vtocx = vtocx
 677                                                             /* Still the same one */
 678                          then do;
 679                                    pvtep = addr (pvt_array (pvtx));
 680                                    if vtoc_buf_desc.write_sw
 681                                    then do;                 /* Write */
 682                                              call syserr (LOG,
 683                                                   "vtoc_man: write I/O recovered on crawlout by ^a for ^a_^a^a vtocx ^o",
 684                                                   pds$process_group_id, pvte.devname,
 685                                                   convert (p99, pvte.logical_area_number), pvte.sv_name, vtocx);
 686                                              vtoc_buf_desc.os = "0"b;
 687                                              call WRITE ((vtoc_buf_desc.parts_used), vtoc_buf_descp);
 688                                         end;
 689                                    else do;                 /* Read */
 690                                              call syserr (LOG,
 691                                                   "vtoc_man: read reset on crawlout by ^a for ^a_^a^a vtocx ^o",
 692                                                   pds$process_group_id, pvte.devname,
 693                                                   convert (p99, pvte.logical_area_number), pvte.sv_name, vtocx);
 694                                              call FLUSH_BUFFER (vtoc_buf_descp);
 695                                         end;
 696                               end;
 697                     end;
 698           end;
 699 
 700 
 701           return;
 702 %page;
 703 /*        CLEAR_PAD - clears pad fields in the vtoce prior to copying to buffer for write. */
 704 
 705 CLEAR_PAD:
 706      proc (Clear_ptr, Parts);
 707 
 708 dcl       Clear_ptr           ptr;
 709 dcl       Parts               bit (3) aligned;
 710 
 711 dcl       1 Clear_vtoce       aligned like vtoce based (Clear_ptr);
 712 
 713           if (Parts & "100"b)
 714           then do;
 715                     Clear_vtoce.pad_free_vtoce_chain = ""b;
 716                     Clear_vtoce.pad2 = ""b;
 717                     Clear_vtoce.pad3 = ""b;
 718                     Clear_vtoce.pad4 = ""b;
 719                end;
 720           if (Parts & "001"b)
 721           then do;
 722                     unspec (Clear_vtoce.pad6) = ""b;
 723                     Clear_vtoce.pad7 = ""b;
 724                     Clear_vtoce.pad8 = ""b;
 725                     Clear_vtoce.pad9 = ""b;
 726                end;
 727 
 728      end CLEAR_PAD;
 729 %page;
 730 /*        COPY_PARTS - copies VTOCE parts between two buffers as specified
 731           by a mask.
 732 */
 733 
 734 COPY_PARTS:
 735      proc (Parts, From_ptr, To_ptr);
 736 
 737 dcl       Parts               bit (3) aligned;
 738 dcl       From_ptr            ptr;
 739 dcl       To_ptr              ptr;
 740 
 741 dcl       partsx              fixed bin;
 742 
 743 dcl       1 From_Vtoce_Buffer aligned like vtoce_buffer based (From_ptr);
 744 dcl       1 To_Vtoce_Buffer   aligned like vtoce_buffer based (To_ptr);
 745 
 746           do partsx = 1 to N_PARTS_PER_VTOCE;
 747                if substr (Parts, partsx, 1) = "1"b
 748                then unspec (To_Vtoce_Buffer.parts (partsx)) = unspec (From_Vtoce_Buffer.parts (partsx));
 749           end;
 750 
 751      end COPY_PARTS;
 752 %page;
 753 /*        Routines to compute parameters needed by disk control
 754 
 755           CORE   - computes the absolute memory address
 756 
 757           RECORD - computes the Multics record number
 758 
 759           SECTOR - computes the sector within record
 760 */
 761 
 762 CORE:
 763      proc (Vtoc_buf_descp) returns (fixed bin (24));
 764 
 765 dcl       Vtoc_buf_descp      ptr;
 766 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 767 
 768           return (vtoc_buffer.abs_addr + bin (Vtoc_buf_desc.buf_rel));
 769 
 770      end CORE;
 771 
 772 
 773 
 774 RECORD:
 775      proc (Vtoc_buf_descp) returns (bit (18) aligned);
 776 
 777 dcl       Vtoc_buf_descp      ptr;
 778 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 779 
 780           return (bit (bin (VTOC_ORIGIN + divide (Vtoc_buf_desc.vtocx, VTOCES_PER_RECORD (dev_type), 17), 18), 18));
 781 
 782      end RECORD;
 783 
 784 
 785 SECTOR:
 786      proc (Vtoc_buf_descp) returns (fixed bin (17));
 787 
 788 dcl       Vtoc_buf_descp      ptr;
 789 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 790 
 791 
 792           return (mod (Vtoc_buf_desc.vtocx, VTOCES_PER_RECORD (dev_type)) * SECTORS_PER_VTOCE (dev_type));
 793 
 794      end SECTOR;
 795 
 796 
 797 %page;
 798 /*        SET_VOL_TROUBLE - increments the count of volume inconsistencies
 799           and logs a message into syserr.
 800 */
 801 
 802 SET_VOL_TROUBLE:
 803      proc (Pvtep, Vtocx, Msg);
 804 
 805 dcl       Pvtep               ptr;
 806 dcl       Vtocx               fixed bin;
 807 dcl       Msg                 char (*);
 808 
 809 dcl       1 Pvte              aligned like pvte based (Pvtep);
 810 
 811           Pvte.vol_trouble_count = Pvte.vol_trouble_count + 1;
 812 
 813           call syserr (LOG, "vtoc_man: ^a ^[vtocx ^o ^;^1s^]on ^a_^a^a", Msg, (Vtocx ^= -1), Vtocx, Pvte.devname,
 814                convert (p99, Pvte.logical_area_number), Pvte.sv_name);
 815 
 816      end SET_VOL_TROUBLE;
 817 %page;
 818 /*        RETHREAD - procedure to walk the vtoc_buffer linearly and
 819           thread all in-use buffers into the hash table. This is called
 820           if damage is suspected.
 821 */
 822 
 823 RETHREAD:
 824      proc;
 825 
 826           unspec (vtoc_buffer.hash_table) = ""b;            /* Clear out the old hash table */
 827 
 828           do bufx = 1 to vtoc_buffer.n_bufs;
 829                vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 830                if vtoc_buf_desc.used
 831                then call vtoc_search$hash_in (vtoc_buf_descp);
 832           end;
 833 
 834      end RETHREAD;
 835 %page;
 836 /*        FLUSH_BUFFER - procedure to clear a buffer descriptor and thread
 837           it out of the hash table.
 838 */
 839 
 840 FLUSH_BUFFER:
 841      proc (Vtoc_buf_descp);
 842 
 843 dcl       Vtoc_buf_descp      ptr;
 844 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 845 
 846           call vtoc_search$hash_out (Vtoc_buf_descp);
 847 
 848           vtoc_buffer.search_index =
 849                divide (bin (rel (Vtoc_buf_descp)) - bin (rel (vtoc_buf_desc_arrayp)), size (vtoc_buf_desc), 17) + 1;
 850                                                             /* Set to look at this one first */
 851 
 852           unspec (Vtoc_buf_desc) = ""b;
 853 
 854 
 855      end FLUSH_BUFFER;
 856 %page;
 857 /*        GET_BUFFER - procedure to find a buffer given a pvtx and vtocx.
 858           If the VTOCE so defined already has a buffer, it is returned.
 859           Otherwise, one is allocated. This routine does not return until
 860           the buffer is not out-of-service.
 861 
 862           GET_BUFFER_NOWAIT - identical to GET_BUFFER, except that it does
 863           not wait for the buffer to be not out-of-service.
 864 */
 865 
 866 GET_BUFFER:
 867      proc (Pvtx, Vtocx, Vtoc_buf_descp, Vtoc_bufp, Code);
 868 
 869 dcl       Pvtx                fixed bin;
 870 dcl       Vtocx               fixed bin;
 871 dcl       Vtoc_buf_descp      ptr;
 872 dcl       Vtoc_bufp           ptr;
 873 dcl       Code                fixed bin (35);
 874 
 875 dcl       first_time          bit (1) aligned;
 876 dcl       skip_waiting        bit (1) aligned;
 877 dcl       steps               fixed bin;
 878 dcl       wait_sw             bit (1) aligned;
 879 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 880 
 881 
 882           wait_sw = "1"b;
 883           goto GET_BUFFER_JOIN;
 884 
 885 
 886 GET_BUFFER_NOWAIT:
 887      entry (Pvtx, Vtocx, Vtoc_buf_descp, Vtoc_bufp, Code);
 888 
 889           wait_sw = "0"b;
 890 
 891 GET_BUFFER_JOIN:
 892           Code = 0;
 893           vtoc_buffer.meters.get_buffer_calls = vtoc_buffer.meters.get_buffer_calls + 1;
 894           first_time = "1"b;
 895 
 896 
 897 GET_BUFFER_RETRY:
 898           call vtoc_search$search (Pvtx, Vtocx, Vtoc_buf_descp);
 899                                                             /* Look for existing buffer with this VTOCE */
 900           if Vtoc_buf_descp ^= null () & first_time
 901           then vtoc_buffer.meters.get_buffer_hits = vtoc_buffer.meters.get_buffer_hits + 1;
 902           first_time = "0"b;
 903 
 904           if Vtoc_buf_descp = null ()
 905           then do;                                          /* Not there */
 906                     steps = 0;
 907                     skip_waiting = "1"b;                    /* Skip those with notify_sw the first pass */
 908                     bufx = vtoc_buffer.search_index;        /* Roving pointer */
 909                     do while ("1"b);
 910                          vtoc_buffer.meters.steps = vtoc_buffer.meters.steps + 1;
 911                          steps = steps + 1;
 912                          Vtoc_buf_descp = addr (vtoc_buf_desc_array (bufx));
 913 
 914                          if ^Vtoc_buf_desc.used
 915                          then goto FOUND;
 916 
 917                          if Vtoc_buf_desc.os
 918                          then vtoc_buffer.meters.skip_os = vtoc_buffer.meters.skip_os + 1;
 919                          else if Vtoc_buf_desc.write_sw & Vtoc_buf_desc.err
 920                          then vtoc_buffer.meters.skip_hot = vtoc_buffer.meters.skip_hot + 1;
 921                          else if Vtoc_buf_desc.notify_sw & skip_waiting
 922                          then vtoc_buffer.meters.skip_wait = vtoc_buffer.meters.skip_wait + 1;
 923                          else goto FOUND;                   /* Nemine contradiscente */
 924 
 925                          if steps > MAX_STEPS
 926                          then call syserr (CRASH, "vtoc_man: Out of buffers");
 927                          bufx = bufx + 1;
 928                          if bufx > vtoc_buffer.n_bufs
 929                          then bufx = 1;
 930                          if bufx = vtoc_buffer.search_index
 931                          then do;                           /* Went around once more */
 932                                    skip_waiting = "0"b;     /* Only skip these on first pass */
 933                                    call disk_run;           /* Poll for lost interrupts */
 934                               end;
 935                     end;
 936 
 937 FOUND:
 938                     if bufx >= vtoc_buffer.n_bufs
 939                     then vtoc_buffer.search_index = 1;
 940                     else vtoc_buffer.search_index = bufx + 1;
 941                                                             /* Set to look at next first */
 942 
 943                     if Vtoc_buf_desc.used
 944                     then call FLUSH_BUFFER (Vtoc_buf_descp);
 945 
 946                     Vtoc_buf_desc.pvtx = Pvtx;
 947                     Vtoc_buf_desc.vtocx = Vtocx;
 948                     Vtoc_buf_desc.used = "1"b;
 949                     Vtoc_buf_desc.wait_index = bufx;
 950                     Vtoc_buf_desc.buf_rel = rel (addr (vtoce_buffer_array (bufx)));
 951 
 952                     call vtoc_search$hash_in (Vtoc_buf_descp);
 953 
 954                end;
 955 
 956           if Vtoc_buf_desc.os & wait_sw
 957           then do;
 958                     call WAIT (Vtoc_buf_descp, Code);
 959                     if Code ^= 0
 960                     then do;
 961                               Vtoc_buf_descp = null ();
 962                               Vtoc_bufp = null ();
 963                               return;
 964                          end;
 965                     goto GET_BUFFER_RETRY;
 966                end;
 967 
 968 
 969           Vtoc_bufp = ptr (vtoc_buffer_segp, Vtoc_buf_desc.buf_rel);
 970 
 971      end GET_BUFFER;
 972 
 973 %page;
 974 /*        READ - Routine to read a VTOCE. It gets a buffer (possibly containing
 975           part of all of the VTOCE in question). If the parts desired are
 976           in the buffer, it returns with the buffer. If not, it reads the
 977           entire VTOCE and waits for the completion of the read. Note that
 978           the buffer can disappear if READ waits for an I/O (since it unlocks
 979           the vtoc buffers, waits, and relocks).
 980 
 981           READ_AHEAD - Similar to READ, except that it does not wait.
 982 */
 983 
 984 READ:
 985      proc (Pvtx, Vtocx, Parts, Vtoc_buf_descp, Vtoc_bufp, Sector_read_required, Code);
 986 
 987 dcl       Pvtx                fixed bin;
 988 dcl       Vtocx               fixed bin;
 989 dcl       Parts               bit (3) aligned;
 990 dcl       Vtoc_buf_descp      ptr;
 991 dcl       Vtoc_bufp           ptr;
 992 dcl       Sector_read_required
 993                               bit (1) aligned;
 994 dcl       Code                fixed bin (35);
 995 
 996 dcl       wait_sw             bit (1) aligned;
 997 
 998 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
 999 
1000 
1001           wait_sw = "1"b;
1002           goto READ_JOIN;
1003 
1004 
1005 READ_AHEAD:
1006      entry (Pvtx, Vtocx, Parts, Vtoc_buf_descp, Vtoc_bufp, Sector_read_required, Code);
1007 
1008           wait_sw = "0"b;
1009 
1010 READ_JOIN:
1011           Sector_read_required = "0"b;
1012           Code = 0;
1013           hot_buffer_tried = "0"b;                          /* first time to retry_read */
1014 RETRY_READ:
1015           if wait_sw
1016           then call GET_BUFFER (Pvtx, Vtocx, Vtoc_buf_descp, Vtoc_bufp, Code);
1017           else call GET_BUFFER_NOWAIT (Pvtx, Vtocx, Vtoc_buf_descp, Vtoc_bufp, Code);
1018           if Code ^= 0
1019           then return;
1020 
1021           if ^wait_sw & Vtoc_buf_desc.os
1022           then return;
1023 
1024           if Vtoc_buf_desc.err                              /* I/O error */
1025           then do;
1026                     if ^Vtoc_buf_desc.write_sw              /* Not hot buffer */
1027                     then call FLUSH_BUFFER (Vtoc_buf_descp);
1028                     else if ^hot_buffer_tried
1029                     then do;                                /* Hot buffer, retry write */
1030                               hot_buffer_tried = "1"b;
1031                               pvt_arrayp = addr (pvt$array);
1032                               pvtep = addr (pvt_array (Pvtx));
1033                               call syserr (LOG, "vtoc_man: Write I/O being retried by ^a for ^a_^a^a vtocx ^o",
1034                                    pds$process_group_id, pvte.devname, convert (p99, pvte.logical_area_number),
1035                                    pvte.sv_name, Vtocx);
1036                               Vtoc_buf_desc.os = "0"b;      /* Should be anyhow... */
1037 
1038                               call WRITE ((Vtoc_buf_desc.parts_used), Vtoc_buf_descp);
1039                               goto RETRY_READ;
1040                          end;
1041 
1042                     Code = error_table_$vtoc_io_err;
1043                     Vtoc_buf_descp = null ();
1044                     Vtoc_bufp = null ();
1045                     return;
1046                end;
1047 
1048           if (Vtoc_buf_desc.parts_used & Parts) = Parts     /* Got what they want */
1049           then return;
1050 
1051           Vtoc_buf_desc.write_sw = "0"b;
1052           Vtoc_buf_desc.err = "0"b;
1053           Vtoc_buf_desc.notify_sw = "0"b;
1054           Vtoc_buf_desc.ioq = "0"b;
1055           Vtoc_buf_desc.os = "1"b;
1056 
1057           dev_type = addr (pvt_array (Pvtx)) -> pvte.device_type;
1058 
1059           call dctl$read_sectors (Pvtx, CORE (Vtoc_buf_descp), RECORD (Vtoc_buf_descp), SECTOR (Vtoc_buf_descp),
1060                SECTORS_PER_VTOCE (dev_type));
1061           Sector_read_required = "1"b;
1062           Vtoc_buf_desc.ioq = "1"b;
1063           Vtoc_buf_desc.parts_used = ALL_PARTS;
1064 
1065           vtoc_buffer.meters.disk_reads = vtoc_buffer.meters.disk_reads + 1;
1066           pds$vtoc_reads = pds$vtoc_reads + 1;
1067 
1068           if wait_sw
1069           then goto RETRY_READ;
1070 
1071           return;
1072 
1073      end READ;
1074 %page;
1075 /*        WRITE - This procedure writes the parts specified for a given
1076           vtoc buffer. It does not await its completion.
1077 */
1078 
1079 WRITE:
1080      proc (Parts, Vtoc_buf_descp);
1081 
1082 dcl       Parts               bit (3) aligned;
1083 dcl       Vtoc_buf_descp      ptr;
1084 
1085 dcl       partsx              fixed bin;
1086 
1087 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
1088 
1089 dcl       n_sectors           fixed bin;
1090           if Vtoc_buf_desc.os
1091           then call syserr (CRASH, "vtoc_man: buffer out-of-service on write.");
1092 
1093           partsx = bin (Parts, 3);
1094           if ^VALID_WRITE (partsx)
1095           then call syserr (CRASH, "vtoc_man: Invalid write");
1096 
1097           Vtoc_buf_desc.err = "0"b;
1098           Vtoc_buf_desc.notify_sw = "0"b;
1099           Vtoc_buf_desc.ioq = "0"b;
1100           Vtoc_buf_desc.write_sw = "1"b;
1101           Vtoc_buf_desc.os = "1"b;
1102 
1103           dev_type = addr (pvt_array (Vtoc_buf_desc.pvtx)) -> pvte.device_type;
1104 
1105           if SECTORS_PER_VTOCE (dev_type) = 1
1106           then do;
1107                     n_sectors = 1;
1108                     if Parts ^= ALL_PARTS
1109                     then do;
1110                               call syserr (CRASH, "vtoc_man: Attempt to write less than entire VTOCE to ^d device.",
1111                                    MODELN (dev_type));
1112                          end;
1113                end;
1114           else n_sectors = SECTORS_TO_WRITE (partsx);
1115           call dctl$write_sectors ((Vtoc_buf_desc.pvtx), CORE (Vtoc_buf_descp) + CORE_OFFSET (partsx),
1116                RECORD (Vtoc_buf_descp), SECTOR (Vtoc_buf_descp) + SECTOR_OFFSET (partsx), n_sectors);
1117 
1118           Vtoc_buf_desc.ioq = "1"b;
1119           if VALID_WRITE (bin ((Parts | Vtoc_buf_desc.parts_used), 3))
1120           then Vtoc_buf_desc.parts_used = Vtoc_buf_desc.parts_used | Parts;
1121           else Vtoc_buf_desc.parts_used = Parts;
1122 
1123           vtoc_buffer.meters.disk_writes = vtoc_buffer.meters.disk_writes + 1;
1124           pds$vtoc_writes = pds$vtoc_writes + 1;
1125 
1126      end WRITE;
1127 %page;
1128 /*        WAIT - Procedure to wait until a specified buffer is no longer
1129           out-of-service.
1130 */
1131 
1132 WAIT:
1133      proc (Vtoc_buf_descp, Code);
1134 
1135 dcl       Vtoc_buf_descp      ptr;
1136 dcl       Code                fixed bin (35);
1137 
1138 dcl       1 Vtoc_buf_desc     aligned like vtoc_buf_desc based (Vtoc_buf_descp);
1139 
1140           Code = 0;
1141           vtoc_buffer.meters.wait_calls = vtoc_buffer.meters.wait_calls + 1;
1142 
1143           do while (Vtoc_buf_desc.os);
1144                wait_event = bit (bin (vtoc_buffer.wait_event_constant + Vtoc_buf_desc.wait_index, 36), 36);
1145                call pxss$addevent (wait_event);
1146                Vtoc_buf_desc.notify_sw = "1"b;
1147                if Vtoc_buf_desc.os
1148                then do;
1149                          vtoc_buffer.meters.wait_os = vtoc_buffer.meters.wait_os + 1;
1150                          call UNLOCK;
1151                          call pxss$wait;
1152                          call LOCK_CHECK (Code);
1153                          if Code ^= 0
1154                          then return;
1155                     end;
1156                else call pxss$delevent (wait_event);
1157                Vtoc_buf_desc.notify_sw = "0"b;
1158           end;
1159 
1160      end WAIT;
1161 
1162 %page;
1163 /*        VALIDATE_VTOCX - Routine to check whether a given VTOCE index
1164           corresponds to a VTOCE on the volume.
1165 */
1166 
1167 VALIDATE_VTOCX:
1168      proc (Vtocx, Code);
1169 
1170 dcl       Vtocx               fixed bin;
1171 dcl       Code                fixed bin (35);
1172 
1173           if Vtocx < 0 | Vtocx >= pvte.n_vtoce
1174           then Code = error_table_$invalid_vtocx;
1175           else Code = 0;
1176 
1177      end VALIDATE_VTOCX;
1178 %page;
1179 /*        Setup, Locking, and Unlocking Routines
1180 
1181           SETUP_LOCK  - sets up global pointers, locks vtoc_buffers,
1182                         checks PVTE for still there, not being demounted
1183 
1184           LOCK_CHECK  - locks vtoc_buffers,
1185                         checks PVTE for still there, not being demounted
1186 
1187           UNLOCK      - unlocks vtoc_buffers
1188 */
1189 
1190 SETUP_LOCK:
1191      proc (Pvtx, Code);
1192 
1193 dcl       Pvtx                fixed bin;
1194 dcl       Code                fixed bin (35);
1195 
1196 
1197 dcl       code                fixed bin (35);
1198 
1199           vtoc_buffer_segp = addr (vtoc_buffer_seg$);
1200           vtoc_buf_desc_arrayp = ptr (vtoc_buffer_segp, vtoc_buffer.buf_desc_offset);
1201           vtoc_buf_arrayp = ptr (vtoc_buffer_segp, vtoc_buffer.buf_offset);
1202           pvt_arrayp = addr (pvt$array);
1203 
1204           Code = 0;
1205           pvtep = null ();
1206 
1207           if Pvtx < 0 | Pvtx > pvt$n_entries
1208           then Code = error_table_$invalid_pvtx;
1209           else pvtep = addr (pvt_array (Pvtx));
1210 
1211           call LOCK_CHECK (code);
1212           if code ^= 0
1213           then Code = code;
1214 
1215      end SETUP_LOCK;
1216 
1217 
1218 
1219 LOCK_CHECK:
1220      proc (Code);
1221 
1222 dcl       Code                fixed bin (35);
1223 
1224           Code = 0;
1225 
1226           if pvtep ^= null ()
1227           then do;
1228                     if (pvid ^= ""b & pvid ^= pvte.pvid)
1229                     then Code = error_table_$pvid_not_found;
1230                     else if pvte.device_inoperative
1231                     then Code = error_table_$vtoc_io_err;
1232                     else if pvte.being_demounted2
1233                     then Code = error_table_$pvid_not_found;
1234                end;
1235 
1236           call lock$lock_fast (addr (vtoc_buffer.lock));
1237 
1238 
1239      end LOCK_CHECK;
1240 
1241 
1242 UNLOCK:
1243      proc;
1244 
1245           call lock$unlock_fast (addr (vtoc_buffer.lock));
1246 
1247 
1248      end UNLOCK;
1249 
1250 %page;
1251 %include disk_pack;
1252 %page;
1253 %include pvte;
1254 %page;
1255 %include syserr_constants;
1256 %page;
1257 %include vtoc_buffer;
1258 %page;
1259 %include vtoce;
1260 %page;
1261 %include fs_dev_types;
1262 %page;
1263 
1264 /* BEGIN MESSAGE DOCUMENTATION
1265 
1266 Message:
1267 vtoc_man: Invalid free vtocx XXXXX on dskX_NN{s}
1268 
1269 S:        $log
1270 
1271 T:        $run
1272 
1273 M:        A free VTOCE was allocated which has an invalid VTOCE index for the
1274 volume. This is indicative of damage to volume control structures. This
1275 damage can be corrected by a volume salvage.
1276 
1277 A:        $ignore
1278 
1279 Message:
1280 vtoc_man: Out of buffers try number N
1281 
1282 S:        $info
1283 
1284 T:        $run
1285 
1286 M:        There may be a disk problem which prevents the vtoc buffers
1287 from being written to disk, or there may be a disk tuning problem.
1288 The system may crash within the next few minutes.
1289 
1290 A:        $contact_sa
1291 
1292 Message:
1293 vtoc_man: UID ^= 0 in free VTOCE vtocx XXXXX dskX_NN{s}
1294 
1295 S:        $log
1296 
1297 T:        $run
1298 
1299 M:        The contents of VTOCE XXXXX on dskX_NN{s} are incorrect, as free
1300 VTOCEs should have a zero UID. The system attempts to find another free
1301 VTOCE. This may indicate damage to volume control structures. This damage
1302 can be corrected by a volume salvage.
1303 
1304 A:        $ignore
1305 
1306 
1307 Message:
1308 vtoc_man: Buffer out-of-service during cleanup
1309 
1310 S:        $crash
1311 
1312 T:        When a volume is being demounted or during system shutdown.
1313 
1314 M:        A likely software error in VTOC buffer management which caused
1315 an inconsistency in the VTOC buffer.
1316 
1317 A:        $recover
1318 
1319 
1320 Message:
1321 vtoc_man: Hot buffer abandoned during cleanup vtocx XXXXX dskX_NN{s}
1322 
1323 S:        $log
1324 
1325 T:        When a volume is being demounted or during system shutdown.
1326 
1327 M:        An update to VTOCE XXXXX on dskX_NN{s} could not be completed
1328 due to I/O errors. The VTOCE may be inconsistent or damaged.
1329 
1330 A:        The VTOCE should be examined by means of dump_vtoce the next time
1331 the volume is online. Any inconsistency can be corrected by a volume salvage.
1332 
1333 
1334 Message:
1335 vtoc_man: Write I/O being retried by PERSON.PROJECT.TAG for dskX_NN{s} vtocx XXXXX
1336 
1337 S:        $log
1338 
1339 T:        $run
1340 
1341 M:        A buffer previously marked as "hot" is being requeued for I/O.
1342 
1343 A:        $ignore
1344 
1345 
1346 Message:
1347 vtoc_man: write I/O recovered on crawlout by PERSON.PROJECT.TAG for dskX_NN{s} vtocx XXXXX
1348 
1349 S:        $log
1350 
1351 T:        $run
1352 
1353 M:        The process of PERSON.PROJECT.TAG crawled out of ring-0 or terminated
1354 with the VTOC buffer lock held. A buffer was marked out-of-service for write
1355 to VTOCE XXXXX on dskX_NN{s} for which no I/O had been queued. The write I/O
1356 was requeued.
1357 
1358 A:        $ignore
1359 
1360 
1361 Message:
1362 vtoc_man: read reset of crawlout by PERSON.PROJECT.TAG for dskX_NN{s} vtocx XXXXXX
1363 
1364 S:        $log
1365 
1366 T:        $run
1367 
1368 M:        The process of PERSON.PROJECT.TAG crawled out of ring-0 or terminated
1369 with the VTOC buffer lock held. A buffer was marked out-of-service for read
1370 to VTOCE XXXXX on dskX_NN{s} for which no I/O had been queued. The read I/O was
1371 abandoned.
1372 
1373 A:        $ignore
1374 
1375 
1376 Message:
1377 vtoc_man: Update in progress on crawlout by PERSON.PROJECT.TAG dskX_NN{s}
1378 
1379 S:        $log
1380 
1381 T:        $run
1382 
1383 M:        The process of PERSON.PROJECT.TAG crawled out of ring-0 or terminated
1384 with the vtoc buffer lock held and an update in progress for a VTOCE on dskX_NN{s}.
1385 The VTOCE may be inconsistent. Any inconsistency can be corrected by a volume salvage.
1386 
1387 A:        $ignore
1388 
1389 Message:
1390 vtoc_man: Invalid write
1391 
1392 S:        $crash
1393 
1394 T:        $run
1395 
1396 M:        A likely software error in the calling sequence for output of a VTOCE.
1397 
1398 A:        $recover
1399 
1400 
1401 Message:
1402 vtoc_man: buffer out-of-service on write
1403 
1404 S:        $crash
1405 
1406 T:        $run
1407 
1408 M:        A likely software problem has caused an inconsistency in
1409 the VTOC buffer.
1410 
1411 A:        $recover
1412 
1413 
1414 Message:
1415 vtoc_man: Attempt to write less than entire VTOCE to MODEL device.
1416 
1417 S:        $crash
1418 
1419 T:        $run
1420 
1421 M:        An attempt has been made to write less than the entire VTOCE to a
1422 device MODEL that only supports a 512_word sector. For these devices the
1423 entire 192 word VTOCE must be written at one time. A likely software error
1424 n VTOC buffer management.
1425 
1426 A:        $recover
1427 
1428 
1429 END MESSAGE DOCUMENTATION */
1430      end vtoc_man$get_vtoce;