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 /****^  HISTORY COMMENTS:
 14   1) change(86-01-16,Fawcett), approve(86-04-11,MCR7383),
 15      audit(86-05-28,Beattie), install(86-07-17,MR12.0-1097):
 16      Add support for 512_WORD_IO devices, 3380 and 3390.
 17                                                    END HISTORY COMMENTS */
 18 
 19 
 20 vm_vio: proc;
 21 
 22 /* original coding 9/75 by Bensoussan. Use of linear 256k seg for access changed
 23    5/76 by Kobziar to be a table of abs segs used round robin fashion  and initialized to 64k size.
 24    Modified 03/21/81, W. Olin Sibert, for ADP PTW formats
 25    Modified 03/08/82, J. Bongiovanni, for new PVTE
 26    */
 27 
 28 /* The first abs seg (first 64k) is not releasable, and its ptr is always valid.
 29    Handling of reused addresses fits in as there is no dependence on any other abs seg  (ptr) */
 30 
 31 /* Optimized for  linearly increasing vtocx index. Only case this not true is in processing
 32    a reused address, an event which is too infrequent (and happens only if unlucky hardware
 33    failure during crash) to code for. Thus read ahead and write behind will cause extra work
 34    due to possible reinitializing already written pages only in this case. */
 35 
 36 /* Note that cleanup entry now releases printer */
 37 
 38 dcl (pvtx, a_pvtx) fixed bin,
 39     (vtocx, a_vtocx, devx) fixed bin,
 40     (code, a_code) fixed bin (35);
 41 
 42 dcl  rec_size fixed bin internal static options (constant) init (1024);
 43 dcl  n_rec_per_seg fixed bin internal static options (constant) init (64);
 44 
 45 dcl  segnos_initialized bit (1) internal static init ("0"b);
 46 
 47 dcl  s (0 : 4) fixed bin internal static;                   /* use 5 abs segs for addressibility */
 48 
 49 dcl 1 seg_list (0 : 4) internal static,
 50     2 basep ptr,                                            /* seg ptr to be used for this abs seg */
 51     2 recno fixed bin,                                      /* starting addr of this seg w.r.t. disk 0 */
 52     2 perm bit (1) aligned,                                 /* slot frozen for this disk - header ptrs remain valid */
 53     2 used bit (1) aligned;                                 /* indicates slot initialized */
 54 
 55 dcl  i fixed bin;
 56 dcl  ptp pointer;
 57 
 58 dcl  dseg$ (0 : 1023) fixed bin (71) external static;
 59 dcl  pds$processid ext bit (36) aligned;
 60 dcl  pvt$n_entries fixed bin external;
 61 dcl  salv_abs_seg_00$ external;
 62 dcl  salv_data$vol_read_ahead fixed bin external;
 63 dcl  sst$astl bit (36) aligned external;
 64 dcl  sst$astsize fixed bin external;
 65 dcl  1 sst$level (0 : 3) aligned external,
 66      2 ausedp bit (18) unaligned,
 67      2 no_aste bit (18) unaligned;
 68 dcl  sst$pts (0 : 3) fixed bin external;
 69 
 70 dcl  get_aste entry (fixed bin) returns (ptr);
 71 dcl  get_ptrs_$given_astep entry (ptr) returns (fixed bin (71) aligned);
 72 dcl  get_ptrs_$given_segno entry (fixed bin) returns (ptr);
 73 dcl  lock$lock_ast entry;
 74 dcl  lock$unlock_ast entry;
 75 dcl  page$cam entry;
 76 dcl  pc$cleanup entry (ptr);
 77 dcl  pc_wired$read entry (ptr, fixed bin, fixed bin);
 78 dcl  pc_wired$write entry (ptr, fixed bin, fixed bin);
 79 dcl  ptw_util_$make_disk entry (pointer, fixed bin (20));
 80 dcl  ptw_util_$make_null entry (pointer, bit (22) aligned);
 81 dcl  put_aste entry (pointer);
 82 dcl  syserr entry options (variable);
 83 dcl  thread$out entry (pointer, bit (18) unaligned);
 84 
 85 dcl (addr, addrel, baseno, baseptr, bit, divide, hbound, mod, null, ptr, fixed) builtin;
 86 
 87 dcl  cleanup condition;
 88 
 89 /* ^L */
 90 
 91 get_vtocep : entry (a_pvtx, a_vtocx) returns (ptr);
 92 
 93           pvtx = a_pvtx;
 94           vtocx = a_vtocx;
 95           pvt_arrayp = addr (pvt$array);
 96           devx = pvt_array (pvtx).device_type;
 97           vtocep = GET_VTOCEP (pvtx, vtocx);
 98 
 99           return (vtocep);
100 
101 
102 
103 
104 
105 
106 init :    entry (a_pvtx, a_code) returns (ptr);
107 
108           pvtx = a_pvtx;
109           code = 0;
110           pvt_arrayp = addr (pvt$array);
111           devx = pvt_array (pvtx).device_type;
112           on cleanup call CLEAN_UP;
113 
114           call INIT (pvtx, code);
115 
116           a_code = code;
117 
118           if code ^= 0 then do; call CLEAN_UP; return (null); end;
119 
120           return (seg_list (0).basep);
121 
122 
123 
124 
125 
126 clean_up : entry (a_pvtx);
127 
128           pvtx = a_pvtx;
129           pvt_arrayp = addr (pvt$array);
130           devx = pvt_array (pvtx).device_type;
131           call CLEAN_UP;
132 
133           return;
134 ^L
135 GET_VTOCEP : procedure (pvtx, vtocx) returns (ptr);
136 
137 
138 /* FUNCTION - This procedure returns a pointer to the vtoc entry whose  vtoc  index
139    is (vtocx) in the physical volume that has been assigned the entry number (pvtx) in
140    the physical volume table. */
141 
142 
143 dcl  pvtx fixed bin,
144      vtocx fixed bin;
145 
146 dcl  recno fixed bin;
147 dcl  compno fixed bin;
148 dcl  segno fixed bin;
149 dcl  word_number fixed bin;
150 
151 dcl  vtoce_size fixed bin;
152 dcl  n_vtoce_per_rec fixed bin;
153 
154 dcl  vtoce_ptr ptr;
155 
156 dcl  k fixed bin;
157 
158 
159                if pvtx <= 0 | pvtx > pvt$n_entries then
160                     do;
161                     call syserr (ANNOUNCE, "vm_vio: get_vtocep: invalid pvtx: ^oo", pvtx);
162                     return (null);
163                end;
164             devx = pvt_array (pvtx).device_type;
165 
166 
167 /* The vtoce_size calculation is done this way so that for disk devices that
168    only do 512 word io will appear to have a vtoce size of 512 instead of 192
169    because there is only one vtoce per sector and the remaining 320 are not
170    used. Therefore the calculation of word_number will always point to the
171    begining of the vtoce. */
172 
173                vtoce_size = sect_per_vtoc (devx) * words_per_sect (devx);
174                n_vtoce_per_rec = divide (rec_size, vtoce_size, 17, 0);
175                recno = divide (vtocx, n_vtoce_per_rec, 17, 0) + VTOC_ORIGIN;
176                compno = get_segno (recno);
177                segno = s (compno);
178 
179                if vtocx < 0 | recno >= pvt_array (pvtx).vtoc_size then
180                     do;
181                     call syserr (ANNOUNCE, "vm_vio: get_vtocep: invalid vtocx ^oo on pvtx ^oo", vtocx, pvtx);
182                     return (null);
183                end;
184 
185                word_number = mod (recno, n_rec_per_seg) * rec_size
186                     + mod (vtocx, n_vtoce_per_rec) * vtoce_size;
187 
188                vtoce_ptr = ptr (baseptr (segno), word_number);
189 
190                k = salv_data$vol_read_ahead;
191                if k > 0 then if mod (vtocx, n_vtoce_per_rec * k) = 0 then call READ_AHEAD ;
192 
193                return (vtoce_ptr);
194 
195 ^L
196 READ_AHEAD :   proc ;                                       /* INTERNAL TO GET_VTOCEP */
197 
198 
199 
200 dcl (r, r1, r2) fixed bin;
201 dcl (j, n (0:1)) fixed bin;
202 dcl  first (0:1) fixed bin;
203 dcl  astep (0:1) ptr;
204 dcl  index fixed bin;
205 
206 
207                     r1 = recno + k;
208                     r2 = r1 + k - 1;
209 
210                     n (0), n (1), j = 0;
211 
212                     do r = recno + 1 to r2 while (r < pvt_array (pvtx).vtoc_size);
213                          if mod (r, n_rec_per_seg) = 0 then j = 1;
214                          if r >= r1 then n (j) = n (j) + 1;
215                     end;
216 
217                     do j = 0, 1;
218                          if n (j) > 0 then
219                               do;
220                               if j = 0 then astep (0) = get_ptrs_$given_segno (s (compno));
221                               else do;
222                                    index = get_segno (recno + n_rec_per_seg);
223                                    astep (j) = get_ptrs_$given_segno (s (index));
224                               end;
225                               if j = 0 then
226                               first (j) = mod (r1, n_rec_per_seg); else first (j) = mod (r1 + n (0), n_rec_per_seg);
227                               if astep (j) ^= null then call pc_wired$read (astep (j), first (j), n (j));
228                               else  call syserr  (CRASH, "vm_vio: no AST pointer at readahead.");
229                          end;
230                     end;
231 
232 
233                     index = mod (recno, n_rec_per_seg);
234                     if index >= k then
235                          do;
236                          if n (0) = 0 then astep (0) = get_ptrs_$given_segno (s (compno));
237                          if astep (0) ^= null then call pc_wired$write (astep (0), index - k, k);
238                     end;
239 
240                     return;
241 
242                end READ_AHEAD;
243 ^L
244 
245 get_segno:     proc (pageno) returns (fixed bin);
246 
247 dcl  pageno fixed bin;
248 dcl  fbtemp fixed bin;
249 
250                     do i = 0 to hbound (s, 1);
251                          if seg_list (i).used then if seg_list (i).recno <= pageno
252                               then if pageno <= seg_list (i).recno +n_rec_per_seg -1 then return (i);
253                     end;
254                                                             /* must update slot */
255                     fbtemp = 1;
256                                                             /* used to be only one loop with test for perm bit */
257                     do i = 1 to hbound (s, 1);
258                          if seg_list (i).recno < seg_list (fbtemp).recno then fbtemp = i;
259                     end;
260 
261                     call init_seg_list (fbtemp, pageno);
262                     return (fbtemp);
263                end get_segno;
264 
265 init_seg_list: proc (index, pageno);
266 
267 dcl (index, pageno) fixed bin;
268 dcl  start fixed bin;
269 
270                     astep = get_ptrs_$given_segno (s (index));
271                     call pc_wired$write (astep, 0, -1);
272                     call pc$cleanup (astep);
273 
274                     start = divide (pageno, n_rec_per_seg, 17, 0) * n_rec_per_seg;
275 
276                     ptp = addrel (astep, sst$astsize);
277                     do i = 0 to n_rec_per_seg - 1;
278                          call ptw_util_$make_disk (addrel (ptp, i), start + i); /* Appropriate record, out on disk */
279                     end;
280 
281                     seg_list (index).recno = start;
282 
283                end init_seg_list;
284           end GET_VTOCEP;
285 ^L
286 INIT :    proc (pvtx, code);
287 
288 dcl  pvtx fixed bin;
289 dcl  code fixed bin (35);
290 
291 dcl  vtoc_size fixed bin;
292 dcl  start_recno fixed bin;
293 
294 
295                code = 0;
296 
297                if ^ segnos_initialized then
298                     do;
299                     seg_list (0).basep = addr (salv_abs_seg_00$);
300                     s (0) = fixed (baseno (seg_list (0).basep));
301                     seg_list (0).used = "0"b;
302                     seg_list (0).perm = "0"b;
303 
304                     do i = 1 to hbound (s, 1);
305                          s (i) = s (0) + i;
306                          seg_list (i).basep = baseptr (s (i));
307                          seg_list (i).used = "0"b;
308                          seg_list (i).perm = "0"b;
309                     end;
310 
311                     segnos_initialized = "1"b;
312                end;
313 
314                start_recno = 0;
315                call INIT_VTOC_SEG (s (0), pvtx, start_recno, n_rec_per_seg, code);
316                if code ^= 0 then return;
317 
318                seg_list (0).used = "1"b;
319                seg_list (0).perm = "1"b;
320                seg_list (0).recno = 0;
321 
322                labelp = ptr (baseptr (s (0)), LABEL_ADDR * rec_size);
323 
324                vtoc_size = label.vtoc_size;
325 
326                do i = 1 to hbound (s, 1);
327                     start_recno = start_recno + n_rec_per_seg;
328                     call INIT_VTOC_SEG (s (i), pvtx, start_recno, n_rec_per_seg, code);
329                     if code ^= 0 then return;
330                     seg_list (i).used = "1"b;
331                     seg_list (i).perm = "0"b;
332                     seg_list (i).recno = start_recno;
333                end;
334 
335                pvt_array (pvtx).vtoc_size = vtoc_size; /* Needed by vm_vio$get_vtocep */
336                return;
337 
338           end INIT;
339 ^L
340 INIT_VTOC_SEG : proc (segno, pvtx, first_recno, n_records, code) ;
341 
342 
343 dcl  segno fixed bin,                                       /* segno assigned to this vtoc segment - input */
344      pvtx fixed bin,                                        /* PVT index for this vtoc segment - input */
345      first_recno fixed bin,                                 /* device add for page 0 of this vtoc segment - input */
346      n_records fixed bin,                                   /* number of pages for this vtoc segment - input */
347      code fixed bin (35);
348 
349 dcl (i, pts, ptsi) fixed bin;
350 
351 dcl  tsdw fixed bin (71);
352 
353 
354 /* ALLOCATE AN ASTE OF THE APPROPRIATE SIZE */
355 
356                code = 0;
357 
358                call lock$lock_ast;
359 
360                astep = get_aste (n_records);                /* Get an ASTE with the appropriate size PT */
361 
362                ptsi = fixed (aste.ptsi);
363                pts = sst$pts (ptsi);
364 
365 
366 /* ZERO THE ASTE */
367 
368                astep -> aste_part.two = "0"b;               /* Zero the rest of the ASTE except ptsi and marker */
369 
370 /* INITIALIZE THE PAGE TABLE WITH DISK ADDRESSES AND PAGE FAULT BITS */
371 
372                ptp = addrel (astep, sst$astsize); /* get a pointer to the page table */
373 
374                do i = 0 to n_records - 1;                   /* initialize the page table array for the entry */
375                     call ptw_util_$make_disk (addrel (ptp, i), first_recno + i); /* Appropriate record, out on disk */
376                end;
377 
378                do i = n_records to pts - 1;
379                     call ptw_util_$make_null (addrel (ptp, i), fill_page_table_null_addr); /* Make up remaining PTWS */
380                end;
381 
382 
383 
384 /* INITIALIZE THE ASTE */
385 
386                astep -> aste.vtocx = -1;                    /* show there is no VTOCE for the segment */
387                astep -> aste.dnzp = "1"b;
388                astep -> aste.gtpd = "1"b;                   /* do not put pages in the paging device */
389                astep -> aste.nqsw = "1"b;                   /* turn on no quota switch */
390                astep -> aste.strp = bit (fixed (segno, 18), 18); /* store segment number in AST */
391                astep -> aste.csl = bit (fixed (n_records, 9), 9); /* set the current length */
392                astep -> aste.msl = bit (fixed (n_records, 9), 9); /* set the max length */
393                astep -> aste.records = bit (fixed (n_records, 9), 9); /* set the number of records used */
394                astep -> aste.pvtx = pvtx;                   /* store the physical volume table index */
395 
396 
397 
398 /* THE CLEAN_UP OPERATION WILL DEPEND ON THE ORDER IN WHICH THE NEXT ACTIONS ARE PERFORMED */
399 
400                tsdw = get_ptrs_$given_astep (astep);        /* Get initial  SDW. */
401                dseg$ (segno) = tsdw;                        /* store temp SDW in the descriptor segment */
402                call page$cam;
403 
404                astep -> aste.usedf = "1"b;                  /* mark it as being used - as late as possible */
405 
406                call thread$out (astep, sst$level (ptsi).ausedp); /* thread the entry out of the used list */
407 
408                call lock$unlock_ast;
409 
410                return;
411 
412           end INIT_VTOC_SEG;
413 ^L
414 CLEAN_UP : proc;
415 
416 dcl  k fixed bin;
417 
418 
419                if ^ segnos_initialized then return;
420 
421                if sst$astl ^= pds$processid then call lock$lock_ast;
422 
423                do k = 0 to hbound (s, 1);;
424                     if seg_list (k).used then do;
425                          astep = get_ptrs_$given_segno (s (k));
426 
427                          if astep ^= null then
428                               if fixed (aste.strp, 18) = s (k) then
429                                    do;
430                                    dseg$ (s (k)) = 0;
431                                    call page$cam;
432                                    call pc$cleanup (astep);
433                                    call put_aste (astep);
434                               end;
435                          seg_list (k).used = "0"b;
436                          seg_list (k).perm = "0"b;
437                     end;
438                end;
439 
440                call lock$unlock_ast;
441 
442                addr (pvt$array) -> pvt_array (pvtx).vtoc_size = 0;
443 
444                return;
445 
446           end CLEAN_UP;
447 
448 %page; %include aste;
449 %page; %include disk_pack;
450 %page; %include fs_vol_label;
451 %page; %include null_addresses;
452 %page; %include pvte;
453 %page; %include vtoce;
454 %page; %include syserr_constants;
455 %page; %include fs_dev_types_sector;
456 /* ^L */
457 
458 /* BEGIN MESSAGE DOCUMENTATION
459 
460    Message:
461    vm_vio: get_vtocep: invalid pvtx: PPPo
462 
463    S: $info
464 
465    T: Volume salvaging or disk rebuilding.
466 
467    M: The Volume Salvager virtual access package has been given a bad
468    PVT index parameter, PPP (shown in octal).
469    $err
470 
471    A: Salvaging will not proceed.
472    $boot_tape
473 
474    Message:
475    vm_vio: get_vtocep: invalid vtocx VVVo on pvtx PPPo
476 
477    S: $info
478 
479    T: Volume salvaging or disk rebuilding.
480 
481    M: An out-of-range VTOC index (VVV) has been given to the Volume Salvager
482    virtual access package while processing PV at pvtx PPP. The vtocx and pvtx
483    are shown in octal.
484    $err
485 
486    A: Salvaging may fail.
487    $note
488 
489    Message:
490    vm_vio: no AST pointer at readahead.
491 
492    S: $crash
493 
494    T: Volume salvaging or disk rebuilding.
495 
496    M: No AST entry pointer was found for a VTOC-addressing
497    segment used by the Volume Salvager virtual access package.
498    $err
499 
500    A: $recover
501    $note
502 
503    END MESSAGE DOCUMENTATION */
504 
505      end vm_vio;