



		    accept_fs_disk.pl1              11/11/89  1138.3rew 11/11/89  0838.7       67662



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1983 *
        *                                                         *
        *********************************************************** */

/*
   This procedure is used to accept a storage system disk into the
   mounted hierarchy. It is called by the outer ring when the latter has
   fully checked and verified the label information, as read by
   whatever means. As this program uses read_disk,
   it must obey the necessary constraints on the use of that program.

   Bernard Greenberg, 10/16/75
   Removed PD flush stuff to salvage_pv, BSG 5/13/76
   modified 9/30/76 by Noel I. Morris for flagbox bit
   modified 07/21/78 by Greenberg for RLV acceptance by ring 0.
   removed RPV acceptance August 1980 by C. Hornig.
   modified March 1982 by J. Bongiovanni for new PVTE, record and VTOCE stocks
   modified '82 for english error codes.
*/

/****^  HISTORY COMMENTS:
  1) change(86-05-13,GJohnson), approve(86-05-13,MCR7387),
     audit(86-05-13,Martinson), install(86-05-14,MR12.0-1056):
     Correct error message documentation.
  2) change(86-05-19,Fawcett), approve(86-04-11,MCR7383),
     audit(86-05-20,Coppola), install(86-07-17,MR12.0-1097):
     Add support for printing subvolume name.
  3) change(88-05-26,GWMay), approve(88-05-26,MCR7883),
     audit(88-06-14,Beattie), install(88-07-19,MR12.2-1061):
     Added setting of a bit in the pvt to indicate that the dumper bit maps are
     inconsistent.
                                                   END HISTORY COMMENTS */

accept_fs_disk:
     procedure (a_pvtx, a_code);

/* Initialize the PVT entry */

          a_code = 0;

          pvt_arrayp = addr (pvt$array);

	pvtx = a_pvtx;				/* We are a gate, must copy args */

	if (pvtx < 0) | (pvtx > pvt$n_entries) then do;
	     a_code = error_table_$fsdisk_pvtx_oob;
	     return;
	     end;

	pvtep = addr (pvt_array (pvtx));		/* address the pvte */
	if pvte.used | pvte.being_mounted then do;
	     a_code = error_table_$fsdisk_drive_in_use;
	     return;
	     end;
	if ^pvte.storage_system then do;
	     a_code = error_table_$fsdisk_not_storage;
	     return;
	     end;

	pvte.being_mounted = "1"b;			/* Just to mark the pvte */

/* Read the label */

	labelp = addr (buffer);
	call read_disk (pvtx, LABEL_ADDR, labelp, code);	/* Read it */
	if code ^= 0 then goto eg;			/* couldn't read it */
	if label.version ^= 1 then do;		/* Refuse to deal with old disk. */
	     code = error_table_$fsdisk_old_label;
	     goto eg;
	     end;

	if label.volmap_version ^= 1 & label.volmap_version ^= 2
	     then do;				/* Pre-MR10 pack */
	     call salvager$convert_vtoc (pvtx, ""b, code);
	     if code ^= 0 then goto eg;
	     call read_disk (pvtx, LABEL_ADDR, labelp, code);  /* Changed by convert_vtoc */
	     if code ^= 0 then goto eg;
	     end;
	if label.volmap_version >= 2 then do;		/* MR 10.x */
	     call salvager$volume_salvage (pvtx, ""b, code);
	     if code ^= 0 then goto eg;
	     call read_disk (pvtx, LABEL_ADDR, labelp, code);  /* Changed by salvage_pv */
	     if code ^= 0 then goto eg;
	     end;
	     

	pvte.vol_trouble_count = label.vol_trouble_count;

	if (label.time_map_updated ^= label.time_unmounted)
	   & ((label.time_map_updated ^= label.time_salvaged) | (label.time_unmounted > label.time_salvaged)) then do;
	   pvte.vol_trouble_count = pvte.vol_trouble_count + 1;
	   pvte.inconsistent_dbm = "1"b;
	   end;
	else
	   if label.inconsistent_dbm then
	      pvte.inconsistent_dbm = "1"b;
	else
	   pvte.inconsistent_dbm = "0"b;

/* Copy params into PVT - protected by used and being mounted bits */

	pvte.pvid = label.pvid;
	pvte.lvid = label.lvid;
	pvte.brother_pvtx = 0;

/* Now load the volume map and VTOC map. This routine also determines whether
   a salvage is required for the volume before it can be accepted. */

RETRY_AFTER_SALVAGE:
	
	call init_volmap_seg (pvtx, (label.pv_name), code);
	if code ^= 0
	     then if code = error_table_$fsdisk_not_salv then do;
		call salvager$volume_salvage (pvtx, ""b, code);
		if code ^= 0 then goto eg;
		goto RETRY_AFTER_SALVAGE;
	     end;
	     else goto eg;
	     

/* Check the free storage map against the partitions. */

	do i = 1 to label.nparts;
	     if (label.parts (i).frec < (pvte.baseadd + pvte.totrec))
						/* if part begins low */
		& ((label.parts (i).frec + label.parts (i).nrec) > pvte.baseadd)
						/* .. must end low */
	     then call syserr (ANNOUNCE, "accept_fs_disk: part ^a on ^a (^a_^d^[^a^;^1s^]) from ^d for ^d overlaps pages from ^d",
		     label.parts (i).part, label.pv_name, pvte.devname, pvte.logical_area_number,pvte.is_sv,pvte.sv_name,
		     label.parts (i).frec, label.parts (i).nrec, pvte.baseadd);
	end;

/* Now we are in business */

	pvt$n_in_use = pvt$n_in_use + 1;
	call fsout_vol (pvtx, 0);			/* get the label back out */
	pvte.used = "1"b;
	pvte.being_mounted = "0"b;
	return;

eg:
	pvte.used = "0"b;
	pvte.being_mounted = "0"b;
	pvte.pvid = "0"b;
	a_code = code;
	return;
%page;
ss_io_reconfigure:
     entry (a_pvtx, a_direction, a_code);

	pvtx = a_pvtx;
	direction = a_direction;
	code = 0;

	pvt_arrayp = addr (pvt$array);
	if (pvtx < 0) | (pvtx > pvt$n_entries) then do;
	     a_code = error_table_$fsdisk_pvtx_oob;
	     return;
	     end;

	pvtep = addr (pvt_array (pvtx));

	if pvte.storage_system ^= direction then do;
	     a_code = error_table_$fsdisk_not_storage;
	     return;
	     end;

	if (pvte.permanent | pvte.used) & direction then do;
	     a_code = error_table_$fsdisk_drive_in_use;
	     return;
	     end;

	pvte.storage_system = ^direction;
	return;
%page;
dcl  fsout_vol entry (fixed bin, fixed bin);
dcl  init_volmap_seg entry (fixed bin, char (*), fixed bin (35));
dcl  read_disk entry (fixed bin, fixed bin, ptr, fixed bin (35));
dcl  salvager$convert_vtoc entry (fixed bin, bit (36) aligned, fixed bin (35));
dcl  salvager$volume_salvage entry (fixed bin, bit (36) aligned, fixed bin (35));
dcl  syserr entry options (variable);

dcl  pvt$n_entries fixed bin external;
dcl  pvt$n_in_use fixed bin external;

dcl  (a_pvtx, pvtx) fixed bin;			/* physical volume index */
dcl  (a_code, code) fixed bin (35);

dcl  i fixed bin;
dcl  (direction, a_direction) bit (1) aligned;
dcl  1 buffer aligned like label;			/* I/O Buffer */

dcl  addr builtin;

declare (error_table_$fsdisk_pvtx_oob,
         error_table_$fsdisk_drive_in_use,
         error_table_$fsdisk_old_label,
         error_table_$fsdisk_not_storage,
         error_table_$fsdisk_not_salv) ext static fixed bin (35);
%page;
%include disk_pack;
%include fs_vol_label;
%include pvte;
%include syserr_constants;
%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   accept_fs_disk: part NAME on PVNAME (dskX_NNS) from AAA for BBB overlaps pages from CCC

   S:	$info

   T:	When accepting a disk volume.

   M:      The supervisor checks the partitions defined in the volume label
   against the beginning of the paging partition when it accepts a volume.
   The partition NAME overlaps the paging area.  The volume label may have
   been damaged.

   A:	Be careful not to destroy the contents of part NAME,
   since this will destory the contents of user segments.
   $note

   END MESSAGE DOCUMENTATION */

     end accept_fs_disk;




		    demount_pv.pl1                  11/11/89  1138.3rew 11/11/89  0838.7      104157



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1988                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */




/****^  HISTORY COMMENTS:
  1) change(86-04-07,Fawcett), approve(86-04-11,MCR7383),
     audit(86-05-13,Coppola), install(86-07-17,MR12.0-1097):
     Add support for printing subvolume name.
  2) change(88-05-11,Parisek), approve(88-05-27,MCR7907),
     audit(88-06-02,Fawcett), install(88-09-27,MR12.2-1122):
     Changed to make sure the pack is removable before trying to unload it.
     Declare builtins in the main (outer) block as some are referenced there.
     To conform to configuration management. (phx20612)
                                                   END HISTORY COMMENTS */


demount_pv:
     procedure (a_pvtx, a_code);

/*    This procedure implements the hardcore portion of the physical
   volume demounter.  It is called from the hardcore logical  volume
   manager  when  the  latter  is asked to demount a logical volume.
   The current implementation assumes that  no  salvaging  involving
   the   volume   to   be   demounted   is  going  on.  The  current
   implementation also does not attempt to overlap deactivation  I/O
   with outer ring events.

   This  procedure  is also called at system shutdown time
   to demount the entire storage hierarchy. At this time, it  avoids
   calling  deactivate,  in order to avoid dealing with possibly bad
   threads or trailers.

   Although this procedure turns on  pvte.being_demounted,
   this bit may turned on by the caller.  demount_pv will deactivate
   all segments residing on physical volumes with this bit on.  When
   parallelism  with  outer-ring  events  is  implemented, this will
   allow total parallelism during multi-volume demounts.

   Initial coding March 26, 1976 by Bernard Greenberg
   Modified 2/27/77 for drive-down ESD, BSG.
   Modified December 1981 by C. Hornig to remove Page Multilevel.
   Modified March 1982 by J. Bongiovanni for new PVTE
   Modified September 1982 by J. Bongiovanni for scavenger
*/

dcl  sst$astap ptr external;
dcl  sst$astsize fixed bin external;
dcl  1 sst$level (0:3) aligned external,
     2 ausedp bit (18) unal,
     2 no_aste bit (18) unal;
dcl  sst$pts (0:3) fixed bin external;
dcl  tc_data$system_shutdown ext fixed bin;
dcl  pvt$n_in_use fixed bin external;

dcl  error_table_$dev_nt_assnd ext fixed bin (35);
dcl  error_table_$scavenge_in_progress ext fixed bin (35);
dcl  error_table_$unable_to_do_io ext fixed bin (35);
dcl  error_table_$vtoc_io_err ext fixed bin (35);

dcl  get_pvtx$drain_pvtx entry (fixed bin);
dcl  vtoc_man$cleanup_pv entry (fixed bin, fixed bin (35));
dcl  fsout_vol entry (fixed bin, fixed bin);
dcl  (
     syserr,
     syserr$error_code
     ) entry options (variable);

dcl  (addr, addrel, fixed) builtin;

dcl  pvtx fixed bin;				/* pvtx being demounted */
dcl  sys_shut bit (1) aligned;			/* ON if system shutdown */
dcl  pic99 pic "99";
dcl  devname char (9);				/* Device name */
dcl  code fixed bin (35);


dcl  a_code fixed bin (35);
dcl  a_pvtx fixed bin;


%page;
	pvt_arrayp = addr (pvt$array);
	pvtx = a_pvtx;
	pvtep = addr (pvt_array (pvtx));		/* Develop pointers */

	if ^(pvte.used & pvte.storage_system) then do;
	     a_code = error_table_$dev_nt_assnd;	/* Dont work on bad drives */
	     return;
	     end;

	if pvte.device_inoperative then do;
	     a_code = error_table_$unable_to_do_io;
	     return;
	     end;

	if pvte.scavenger_block_rel ^= ""b then do;
	     a_code = error_table_$scavenge_in_progress;
	     return;
	end;

	pvte.being_demounted = "1"b;			/* Cause all future get_pvtx's
						   and get_pvtx$hold_pvtx's to fail. */

	pic99 = pvte.logical_area_number;		/* Cons up devname */
	devname = pvte.devname || "_" || pic99 || pvte.sv_name;

	call get_pvtx$drain_pvtx (pvtx);		/* Wait out all current protectors of this pvtx.
						   When this is finished, no process is in the middle
						   of an indivisible vtoc operation (delete, truncate),
						   and by virtue of previous line,
						   no process can start one */

	sys_shut = (tc_data$system_shutdown ^= 0);	/* Determine if shutting down system */
						/* */
						/* */
						/* DEACTIVATE_ALL_SEGS will lock the AST.
						   If any process is activating on  this
						   PV, he must either not have yet locked
						   the AST, or has it locked. If he has it locked,
						   DEACTIVATE_ALL_SEGS cannot commence until
						   he releases it. If not, he will find
						   being_demounted on when he gets it, and will fail */

	call DEACTIVATE_ALL_SEGS;			/*  We have already asserted that no one can
						   activate, so we deactivate all */

	pvte.being_demounted2 = "1"b;			/* Allow no further vtoc I/O to start */
						/* Vtoc I/O in progress will be allowed to complete.
						   From this point on, divisible calls to
						   vtoc_man (vtoc_attributes, reclassify, etc.),
						   will fail. */

	call vtoc_man$cleanup_pv (pvtx, code);		/* Await all vtoc I/O which had been started
						   to finish. No new I/O will start. */

	if code ^= 0 then call syserr$error_code (ANNOUNCE, code, "demount_pv: vtoc cleanup of ^a:", devname);

	call fsout_vol (pvtx, 1);			/* Write out label, vol map. */

	if ^sys_shut then do;
	     if ^pvte.permanent then call REWIND_UNLOAD;	/* unload non-perm's, only at non-shut time */
	     call syserr (ANNOUNCE, "demounted ^a", devname);
	     end;

	call CLEANUP_PVTE;				/* Tuck the bits into bed. */

	a_code = 0;
	return;

DEMOUNT_FAILS:					/* Arrive here if cannot demount */
	call UNDO_FOR_LOSSAGE;			/* undo what we have done */
	a_code = code;				/* Reflect error */
	return;
%page;
DEACTIVATE_ALL_SEGS:
     procedure;

/* This procedure deactivates all segments on the physical volume being
   demounted. At the time it has begun by locking the AST lock, it has
   been insured thatno further activations on this instance of this pvte
   can take place.

   If a system shutdown is taking place, an "in-line deactivate" is
   performed, to avoid dealing with possibly bad data in the ESD case.

*/

dcl  (px, astx) fixed bin;				/* AST indices */
dcl  tpvtx fixed bin;				/* PVTX of seg under consideration */
dcl  (
     lock$lock_ast,
     lock$unlock_ast
     ) ext entry;
dcl  deactivate entry (ptr, fixed bin (35));
dcl  pc$cleanup entry (ptr);
dcl  update_vtoce$deact entry (ptr, fixed bin (35));
dcl  tpvtep ptr;					/* Corresponding pointer */

	     astep = sst$astap;			/* WALK the AST, don't "list-hack" it */
	     call lock$lock_ast;

	     do px = 0 to 3;			/* pool index */
		do astx = 1 to fixed (sst$level.no_aste (px), 18); /* Scan all of this size */
		     if aste.uid ^= "0"b & aste.pvtx ^= 0 /* Elect only fs entries */
		     & (aste.uid = (36)"1"b | aste.par_astep ^= "0"b) /* root or par must be */
						/* These are superfluous gullibility checks
						   to avoid tragedy */
		     & ^aste.hc_sdw			/* Don't update segments in hardcore partition */
		     then if fixed (aste.ptsi, 2) = px then do; /* All ok */
			     tpvtx = aste.pvtx;	/* Get pvtx. */
			     tpvtep = addr (pvt_array (tpvtx));
			     if tpvtep -> pvte.being_demounted then do; /* Get 'em all. */
				aste.fmchanged = aste.fmchanged | aste.fmchanged1; /* Fix window. */
				aste.ddnp = "0"b;		/* Let pc return the addresses. */
				if sys_shut then do;	/* Avoid AST threads. */
				     if ^aste.ehs then call pc$cleanup (astep);
				     call update_vtoce$deact (astep, code); /* Update the vtoce */
				     if code ^= 0 then if code ^= error_table_$vtoc_io_err
				     then if tpvtx = pvtx then go to DEMOUNT_FAILS;
				     aste.uid = "000000000000"b3;	/* Last update here. */
				end;
				else do;
				     call deactivate (astep, code);
				     if code ^= 0 then if tpvtx = pvtx then go to DEMOUNT_FAILS;
				end;
			     end;
			end;
		     else call syserr (CRASH, "demount_pv: ast out of sync");
		     astep = addrel (astep, fixed (sst$pts (px) + sst$astsize, 18));
	     end;
	end;

	call lock$unlock_ast;


     end DEACTIVATE_ALL_SEGS;
%page;
CLEANUP_PVTE:
     procedure;

/* This procedure puts the pvt entry of the disk being demounted
   in a credible state for reuse. An fsout_vol has already been done. */

	     pvte.nleft = 0;			/* Dont let fsdct be used */
	     pvte.n_free_vtoce = 0;			/* or vtoc allocates */
	     pvte.lvid = "0"b;
	     pvte.pvid = "0"b;
	     pvte.being_demounted2 = "0"b;
	     pvte.being_demounted = "0"b;
	     pvte.vacating = "0"b;			/* In case this was going on */
	     pvte.used = "0"b;			/* Drive not used */
	     pvt$n_in_use = pvt$n_in_use - 1;		/* ? */

	end CLEANUP_PVTE;

%page;
UNDO_FOR_LOSSAGE: procedure;

/* This procedure undoes what has been done by the demounter, because
   the volume cannot be demounted due to an entry hold scgment */

dcl  lock$unlock_ast entry;

	call lock$unlock_ast;


	pvte.being_demounted = "0"b;

     end UNDO_FOR_LOSSAGE;
%page;
REWIND_UNLOAD:
     procedure;

/* This procedure tries to unload the disk pack. */

dcl  disk_control$unload_drive entry (fixed bin);
dcl  disk_run entry;

          if ^pvte.removable_pack then return;             /* Pack can not be unloaded */
	pvte.testing = "1"b;
	call disk_control$unload_drive (pvtx);
	do while (pvte.testing);			/* Noel has sworn that something will come back */
	     call disk_run;
	end;

	if pvte.device_inoperative then do;
	     call syserr (BEEP, "demount_pv: Unload ^a for storage system.", devname);
	     pvte.device_inoperative = "0"b;
	     end;

	return;

     end REWIND_UNLOAD;
%page; %include aste;
%page; %include iom_pcw;
%page; %include pvte;
%page; %include syserr_constants;
%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   demount_pv: vtoc cleanup of DRIVENAME: ERRORMESSAGE

   S: $info

   T: Volume demounting or shutdown.

   M: An unexpected error was encountered in flushing VTOC information
   out to a volume being shut down or demounted.  The volume will not be demounted.
   message.

   A: $notify
   Attempt to repeat the demount of the logical volume, if this is not during shutdown.
   The physical volume involved may have to be salvaged.

   Message:
   demounted DRIVENAME

   S: $info

   T: Volume demounting, in response to delete_lv command or user action.

   M: The disk pack on drive DRIVENAME was successfully demounted.

   A: $ignore

   Message:
   demount_pv: ast out of sync

   S: $crash

   T: Volume demounting or system shutdown.

   M: The volume demounter has detected irreparable damage to the
   system segment table (SST).

   A: Emergency shutdown will fail, and need not be attempted.
   Follow normal recovery procedures for ESD failure.

   Message:
   demount_pv: ioi_PROGNAME for DRIVENAME: ERRORMESSAGE

   S: $info

   T: Volume demounting.

   M: In attempting to cycle down drive DRIVENAME, an unexpected
   error was received from the I/O Interfacer. The drive may not
   be cycled down.

   A: Notify the system programming staff. Cycle down the drive if it was not cycled down.

   END MESSAGE DOCUMENTATION */
     end demount_pv;




		    fsout_vol.pl1                   11/11/89  1138.3rew 11/11/89  0838.7      116712



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1983 *
        *                                                         *
        *********************************************************** */

/* format: style4 */

fsout_vol: proc (tx, SHUT);

/* FSOUT_VOL - Update the volume map, VTOC header, and label
   for one physical volume.

   This program is called at volume demount time, which includes shutdown, and
   at the time that a volume  is accepted.  All calls except SHUT calls cause
   the label to indicate that volume inconsistencies exist.

   WARNING: This program uses read_disk.

   First coding by Tom VanVleck.

   Modified by Greenberg for dynamic demount, large volume maps, cross-bootload
   paging device management, and disk table location, at various times.
   Modified by D. Vinograd 6/76 to write out volume dumper bit map into volume header
   Modified by R. Holmstedt 10/80 to use fsdisk_error_message in syserr message.
   Modified by J. Bongiovanni, March 1982, for record stocks and VTOCE stocks
   Modified by J. Bongiovanni, August 1982, to update vol_trouble_count in label
   always (for scavenger)
   Modified '82 for english error codes
   Modified by E. N. Kittlitz, September 1983, clear label pad fields.
*/


/****^  HISTORY COMMENTS:
  1) change(88-05-27,GWMay), approve(88-05-27,MCR7883),
     audit(88-06-14,Beattie), install(88-07-19,MR12.2-1061):
     Added assignment of the inconsistent volume dumper bit map flag.
  2) change(88-09-07,Beattie), approve(88-09-19,MCR7989),
     audit(88-10-06,Farley), install(88-10-10,MR12.2-1155):
     Fix so that PV label information is not displayed in error messages
     until it is read from the disk.
                                                   END HISTORY COMMENTS */


/* =================================================== */

	labelp, vtoc_headerp, vol_mapp = null;		/* Init variables */
	have_pv_label = "0"b;			/* Don't have a PV label to display. */
	pvt_arrayp = addr (pvt$array);

	pvtep = addr (pvt_array (tx));		/* Get ptr to the subject pvte. */

/* If shutting the volume down, write out maps and dumper bit map */

	if SHUT = 1 then do;

/* If the volmap_seg exists, update the header and write it to disk.
   It may not exist because of crashes during mount/demount or
   ESD failures */

	     if pvte.volmap_astep ^= null ()
	     then do;

		astep = pvte.volmap_astep;

		call pmut$swap_sdw (addr (volmap_abs_seg$), addr (pvte.volmap_seg_sdw));

		if pvte.vtoc_map_stock_ptr ^= null ()
		then do;

		     call vtoce_stock_man$drain_stock (pvtep);
		     vtoc_mapp = ptr (addr (volmap_abs_seg$), pvte.vtoc_map_offset);

		     on page_fault_error begin;
			call dsker (WRITE, VTOC_MAP);
			goto END_VTOC_MAP_UPDATE;
		     end;

		     vtoc_map.n_free_vtoce = pvte.n_free_vtoce;
END_VTOC_MAP_UPDATE:
		     vtoce_stockp = pvte.vtoc_map_stock_ptr;
		     call stock_man$free_vtoce_stock (pvtep, vtoce_stockp);

		     revert page_fault_error;
		end;

		if pvte.volmap_stock_ptr ^= null ()
		then do;

		     call page$drain_record_stock (pvtep);
		     vol_mapp = addr (volmap_abs_seg$);

		     on page_fault_error begin;
			call dsker (WRITE, VOL_MAP);
			goto END_VOLMAP_UPDATE;
		     end;

		     vol_map.n_free_rec = pvte.nleft;
		     vol_map.n_rec = pvte.totrec;

END_VOLMAP_UPDATE:
		     record_stockp = pvte.volmap_stock_ptr;
		     call stock_man$free_record_stock (pvtep, record_stockp);

		     revert page_fault_error;
		end;

		tsdw = 0;
		call pmut$swap_sdw (addr (volmap_abs_seg$), addr (tsdw));

	     end;

	     if pvte.volmap_astep ^= null () then do;
		pvte.volmap_seg_sdw = 0;
		astep = pvte.volmap_astep;
		call page$cleanup (astep);
		call lock$lock_ast;
		call put_aste (astep);
		call lock$unlock_ast;
		aste.volmap_seg = "0"b;
		pvte.volmap_astep = null ();
	     end;

/* Not get the dumber bit map back to disk */

	     vtoc_headerp = addr (buffer);		/* Re-use the buffer */
	     call read_disk (tx, DUMPER_BIT_MAP_ADDR, vtoc_headerp, ec); /* Must read in old VTOC header */
	     if ec = 0 then do;			/* header successfully read, so merge new items */
		do i = 0, 1;
		     call dbm_man$free_map (tx, addr (buffer), i, ec);
		     call write_disk (tx, DUMPER_BIT_MAP_ADDR + i, addr (buffer), ec);
		     if ec ^= 0 then call dsker (WRITE, VOL_MAP);
		     clearbuf = "0"b;
		end;
	     end;

	     else do;				/* Otherwise, complain and discard old dumper maps */
		call dsker (READ, VTOC_HEADER);
		call syserr (ANNOUNCE, "fsout_vol: Discarding old dumper bit maps for ^a_^a^[^a^;^1s^].",
		     pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name);

		do i = 0, 1;
		     call dbm_man$free_map (tx, addr (buffer), i, ec);
		     clearbuf = "0"b;
		end;
	     end;
	     vtoc_headerp = null;			/* Done with VTOC head */
	end;

/* set the time map updated and the time unmounted in the label. */


	labelp = addr (buffer);			/* Again re-use buffer */
	call read_disk (tx, LABEL_ADDR, labelp, ec);	/* Read in old label. */
	if ec ^= 0 then call dsker (READ, VOL_LABEL);
	else do;
	     have_pv_label = "1"b;			/* Now we know what PV is mounted here. */
	     label.flagpad = ""b;			/* clear all pad fields */
	     unspec (label.pad1) = ""b;
	     unspec (label.pad6) = ""b;
	     unspec (label.pad1a) = ""b;
	     unspec (label.pad2) = ""b;
	     label.root.pad7 = ""b;
	     unspec (label.pad3) = ""b;
	     do i = 1 to hbound (label.parts, 1);
		unspec (label.parts (i).pad5) = ""b;
	     end;
	     unspec (label.pad4) = ""b;		/* end pad clear */
	     now = clock ();
	     if label.pvid ^= pvte.pvid then		/* A simple check.. */
		call syserr (ANNOUNCE, "fsout_vol: label for ^a (^a_^a^[^a^;^1s^]) uid does not match pvt.",
		     label.pv_name, pvte.devname, convert (p99, pvte.logical_area_number),
		     pvte.is_sv, pvte.sv_name);
	     else do;
		label.time_map_updated = now;		/* unless vol_trouble later */
		if tx = pvt$root_pvtx then do;	/* Root case */
		     label.disk_table_vtocx = pvt$disk_table_vtocx;
		     label.disk_table_uid = pvt$disk_table_uid;
		     label.root.shutdown_state = pvt$shutdown_state;
		     label.root.esd_state = pvt$esd_state;
		end;
		label.time_of_boot = pvt$time_of_bootload;
		label.vol_trouble_count = pvte.vol_trouble_count;
		label.inconsistent_dbm = pvte.inconsistent_dbm;

		if SHUT = 1 then do;		/* If shutting down volume, */
		     label.time_unmounted = now;
		     label.last_pvtx = 0;		/* No need to salvage or flush pd */
		     if (pvte.vol_trouble_count > 0) & (pvte.lvid = pvt$root_lvid) then do;
			if pvte.nleft < MIN_RECORDS | pvte.n_vtoce < MIN_VTOCES
			then severity = ANNOUNCE;
			else severity = LOG;
			call syserr (severity, "fsout_vol: ^d volume inconsistenc^[y^;ies^] on ^a (^a_^a^[^a^;^1s^]). ^d free records. ^d free VTOCEs",
			     pvte.vol_trouble_count, (pvte.vol_trouble_count = 1), label.pv_name,
			     pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name,
			     pvte.nleft, pvte.n_free_vtoce);
		     end;
		end;
		else label.last_pvtx = tx;		/* Needed for pdflush */
		call write_disk (tx, LABEL_ADDR, labelp, ec); /* Write new label */
		if ec ^= 0 then call dsker (WRITE, VOL_LABEL);
	     end;
	end;
	labelp = null;				/* Thru with buffer */
	return;


/* --------------------------------------------------- */

dsker: proc (rw, database);

dcl  rw fixed bin,					/* 0 = read, 1 = write */
     database fixed bin;				/* what data we failed on */

dcl  pv_name_from_label char (32);
dcl  RW (0:1) char (4) static init ("read", "writ");
dcl  DATA (1:4) char (12) static init ("vol map", "vtoc header", "vol label", "vtoc map");

	if have_pv_label then pv_name_from_label = label.pv_name;
	else pv_name_from_label = "";			/* prevent null ptr reference */
	call syserr$error_code (ANNOUNCE, ec, "fsout_vol: Error ^aing ^a for ^a_^a^[^a^;^1s^]^[ (^a)^;^s^]",
	     RW (rw), DATA (database),
	     pvte.devname, convert (p99, pvte.logical_area_number), pvte.is_sv, pvte.sv_name, have_pv_label, pv_name_from_label);

     end;
%page;
dcl  tx fixed bin,					/* PVT index for disk to shut */
     SHUT fixed bin;				/* INPUT argument. 1 to dismount all volumes */

dcl  ec fixed bin (35),				/* errcode */
     now fixed bin (52),
     tsdw fixed bin (71),
     severity fixed bin,
     p99 pic "99",
     i fixed bin,
     have_pv_label bit (1);

dcl  (MIN_RECORDS init (200),
     MIN_VTOCES init (100),
     READ init (0),
     WRITE init (1),
     VOL_MAP init (1),
     VTOC_HEADER init (2),
     VOL_LABEL init (3),
     VTOC_MAP init (4))
	fixed bin int static options (constant);

dcl  pvt$disk_table_vtocx fixed bin external;
dcl  pvt$disk_table_uid bit (36) aligned external;
dcl  pvt$esd_state fixed bin external;
dcl  pvt$root_lvid bit (36) aligned external;
dcl  pvt$root_pvtx fixed bin external;
dcl  pvt$shutdown_state fixed bin external;
dcl  pvt$time_of_bootload fixed bin (71) external;
dcl  volmap_abs_seg$ external;

dcl  dbm_man$free_map entry (fixed bin, ptr, fixed bin, fixed bin (35));
dcl  lock$lock_ast entry;
dcl  lock$unlock_ast entry;
dcl  page$cleanup entry (ptr);
dcl  page$drain_record_stock entry (ptr);
dcl  pmut$swap_sdw entry (ptr, ptr);
dcl  put_aste entry (ptr);
dcl  read_disk entry (fixed bin, fixed bin (17), ptr, fixed bin (35));
dcl  stock_man$free_record_stock entry (ptr, ptr);
dcl  stock_man$free_vtoce_stock entry (ptr, ptr);
dcl  (syserr, syserr$error_code) ext entry options (variable);
dcl  vtoce_stock_man$drain_stock entry (ptr);
dcl  write_disk entry (fixed bin, fixed bin (17), ptr, fixed bin (35));

dcl  (addr, clock, convert, hbound, null, ptr, unspec) builtin;

dcl  buffer (512) fixed bin (71) aligned;
dcl  clearbuf bit (36864) aligned based (addr (buffer));

dcl  page_fault_error condition;
%page; %include aste;
%page; %include disk_pack;
%page; %include fs_vol_label;
%page; %include pvte;
%page; %include stock_seg;
%page; %include syserr_constants;
%page; %include vol_map;
%page; %include vtoc_header;
%page; %include vtoc_map;
%page;
/* BEGIN MESSAGE DOCUMENTATION
   Message:
   fsout_vol: Discarding old dumper bit maps for dskX_NNS.

   S: $info

   T: System shutdown and volume demounting.

   M: An error occurred attempting to read the VTOC header from physical volume
   on dskX_NNS.  Writing of the dumper bit maps to disk will be
   bypassed.  The dumper bit maps will be freed and the system will attempt
   to continue, however, the dumper bit maps may not be accurate on disk.

   A: $inform

   Message:
   fsout_vol: label for PVNAME (dskX_NNS) uid does not match pvt.

   S: $info

   T: System shutdown, volume mounting and demounting.

   M: The unique physical volume ID in the label of the pack on dskX_NNS
   (PVNAME) does not compare with the value it had when the pack was first
   mounted.  Damage to the pack has probably occurred.

   A: Attempt to demount the volume if this has not already been done.
   Save the pack for inspection and dumping by the system programming staff.
   Initiate volume recovery procedures.

   Message:
   fsout_vol: {REASON} Error OPERATION OBJECT_TYPE for dskX_NNS {(PVNAME)}

   S: $info

   T: System shutdown and volume mounting and demounting.

   M: A physical device error has occured while attempting
   to read or write (OPERATION) volume header information (OBJECT_TYPE) of the
   pack (PVNAME) on dskX_NNS.

   A: If this message occurs at volume mounting time, check
   the drive specified for write-protect or standby status, and retry
   the add_lv command for the logical volume. If this message occurs at
   shutdown or demount time, the volume may contain inconsistencies
   (lost free records or free VTOCEs). These inconsistencies can be
   corrected by a physical volume salvage.

   Message:
   fsout_vol: XXX volume inconsistenices on PVNAME (dskX_NNS). YYYYY free records. ZZZZZ free VTOCEs.

   S: Logged only if the number of free records and the number of free
   VTOCEs are both above threshold values. Printed and logged if either
   is below threshold.

   T: Volume demounting and system shutdown time.

   M: At some time during the use of volume PVNAME (on drive dskX_NNS),
   the system encountered problems which left the volume in
   an inconsistent state. The effect of this is that some free records
   and/or free VTOCEs are unavailable (lost) to the system. These
   inconsistencies can be corrected by a volume salvage. The number
   of unused records and VTOCEs which are available for use is printed.

   A: If the number of free records or free vtoces is low, a physical
   volume salvage should be done on the volume prior to mounting it
   again to recover the lost items.

   END MESSAGE DOCUMENTATION */
     end fsout_vol;




		    get_pvtx.pl1                    11/11/89  1138.3r w 11/11/89  0838.7       89226



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */
/* format: style2,indcomtxt */

/**** *
      get_pvtx$get_pvtx
      $hold_pvtx
      $release_pvtx
      $drain_pvtx
      $cleanup
      $reset

      04/25/75	Andre Bensoussan - Written for the new storage system.
      Modified 03/06/82, J. Bongiovanni, for new PVTE
      Modified 84-01-17, BIM, for $reset. */
/*    Modified 85-03-28, EJ Sharpe, changed $cleanup to return bit(1) and
   to log what happens. */

get_pvtx:
     procedure (pvid, code) returns (fixed bin (17));


	dcl     pvid		 bit (36) aligned,
	        pvtx		 fixed bin,
	        code		 fixed bin (35);

	dcl     released_something	 bit (1) aligned;

	dcl     (i, w)		 fixed bin (17);

	dcl     word		 bit (36) aligned;
	dcl     my_apterp		 bit (18);

	dcl     error_table_$pvid_not_found
				 fixed bin (35) ext;
	dcl     tc_data$system_shutdown
				 bit (1) aligned ext;

	dcl     pds$apt_ptr		 ptr ext;
	dcl     pds$process_group_id	 char (32) ext;

	dcl     CST		 fixed bin (35) internal static
				 init (011000001000000000000000000000000000b) options (constant);
	dcl     PV_HOLDT		 (1:64) bit (36) aligned internal static init ((64) (36)"0"b);

	dcl     pxss$addevent	 entry (fixed bin (35));
	dcl     pxss$delevent	 entry (fixed bin (35));
	dcl     pxss$notify		 entry (fixed bin (35));
	dcl     pxss$wait		 entry;

	dcl     stacq		 entry (ptr, bit (36) aligned, bit (36) aligned) returns (bit (1));
	dcl     syserr		 entry options (variable);

	dcl     pvt$n_entries	 fixed bin external;

	dcl     (addr, bit, fixed, hbound, lbound, null, rel, stac, unspec)
				 builtin;

/*
   get_pvtx : entry (pvid, code)  returns (fixed bin(17));
*/



/* FUNCTION - This procedure returns the physical volume  table  index
   associated with the physical volume id specified by the input argument
   "pvid".  If  the  pvid  is found in a pvt entry in use, it returns its
   pvtx and sets the code to  zero.   If  a  used  pvt  entry  holds  the
   specified  pvid, then its index is returned with code=0 If no used pvt
   entry holds the specified pvid,  the  value  zero  (invalid  pvtx)  is
   returned, with code=error_table_$pvid_not_found. */


	code = 0;
	pvt_arrayp = addr (pvt$array);

	do i = 1 to pvt$n_entries;
	     pvtep = addr (pvt_array (i));

	     if pvte.used
	     then if pvte.pvid = pvid
		then if ^pvte.being_demounted
		     then if pvte.pvid = pvid
			then return (i);
	end;

	code = error_table_$pvid_not_found;

	return (0);

hold_pvtx:
     entry (pvid, pvtx, code);



/* FUNCTION - The procedure "hold_pvtx" causes the system to  remember
   that  one more request has been issued to keep the binding between the
   pvid and the pvtx specified as input arguments, and also  to  remember
   the  name  of  the  process  who  is  issuing the request. The binding
   between a pvid and a pvtx cannot change while the number  of  requests
   to keep it is non-zero.  If the pvid and the pvtx are not bound at the
   time this procedure is called, the ony effect of the call is to return
   the code = error_table_$pvid_not_found. */



	pv_holdtp = addr (PV_HOLDT);
	pvt_arrayp = addr (pvt$array);
	pvtep = addr (pvt_array (pvtx));

	code = 0;

	if pvte.pvid ^= pvid | pvte.being_demounted
	then do;
		code = error_table_$pvid_not_found;
		return;
	     end;

	word = bit (fixed (pvtx, 18), 18) || rel (pds$apt_ptr);

	do i = 1 to hbound (pv_holdt, 1) while (^stac (addr (pv_holdt (i)), word));
	end;

	if i > hbound (pv_holdt, 1)
	then call syserr (SYSERR_CRASH_SYSTEM, "get_pvtx: hold_pvtx finds table full");

	if pvte.pvid ^= pvid | pvte.being_demounted
	then do;
		call ZERO_ENTRY (i);
		code = error_table_$pvid_not_found;
		return;
	     end;

	return;

release_pvtx:
     entry (pvid, pvtx);



/* FUNCTION - The procedure  "release_pvtx"  is  the  inverse  of  the
   hold_pvtx  procedure.  It  causes the system to forget whatever it was
   caused to remember by the last call to hold_pvtx in this process  with
   the  same  pvid  and  pvtx  arguments.  The  following sequence:  call
   get_pvtx$hold_pvtx ( pvid, pvtx, code )  ;  if  code  =  0  then  call
   get_pvtx$release_pvtx(pvid, pvtx) is equivalent to a null statement. */



	pv_holdtp = addr (PV_HOLDT);
	pvt_arrayp = addr (pvt$array);
	pvtep = addr (pvt_array (pvtx));

	my_apterp = rel (pds$apt_ptr);

	do i = 1 to hbound (pv_holdt, 1) while (pv_holdt (i).apterp ^= my_apterp | pv_holdt (i).pvtx ^= pvtx);
	end;

	if i > hbound (pv_holdt, 1) | pvte.pvid ^= pvid
	then call syserr (SYSERR_CRASH_SYSTEM, "get_pvtx: release_pvtx: mark not found");

	call ZERO_ENTRY (i);

	return;

drain_pvtx:
     entry (pvtx);



/* FUNCTION - The procedure "drain_pvtx" causes the system  to  refuse
   any subsequent requests to hold the pvtx with the pvid it is now bound
   to,  and  to wait until the number of hold requests that may have been
   issued for this pvtx prior to this instant to drop to zero. */



	pv_holdtp = addr (PV_HOLDT);
	pvt_arrayp = addr (pvt$array);
	pvtep = addr (pvt_array (pvtx));

	if pvte.being_demounted = "0"b
	then call syserr (SYSERR_CRASH_SYSTEM, "get_pvtx: drain_pvtx: pvte.being_demounted should be on");

	w = -1;
	do while (w ^= 0);

	     w = 0;
	     do i = 1 to hbound (pv_holdt, 1);
		if pv_holdt (i).pvtx = pvtx
		then if ^tc_data$system_shutdown
		     then do;
			     call pxss$addevent (CST + i);
			     if pv_holdt (i).pvtx = pvtx
			     then do;
				     call pxss$wait;
				     w = w + 1;
				end;
			     else call pxss$delevent (CST + i);
			end;

		     else pvte.vol_trouble_count = pvte.vol_trouble_count + 1;

	     end;

	end;

	return;

cleanup:
     entry () returns (bit (1) aligned);


/* FUNCTION - The procedure "cleanup" is executed by a process  before
   crawling  out  of  ring  zero. It causes the system to forget any hold
   request that may have been issued by this process for any pvtx */



	released_something = "0"b;
	pv_holdtp = addr (PV_HOLDT);
	pvt_arrayp = addr (pvt$array);
	pvtep = null ();

	do i = 1 to hbound (pv_holdt, 1);
	     if pv_holdt (i).apterp = rel (pds$apt_ptr)
	     then do;
		     pvt_array (pv_holdt (i).pvtx).vol_trouble_count =
			pvt_array (pv_holdt (i).pvtx).vol_trouble_count + 1;
		     call ZERO_ENTRY (i);
		     call syserr (SYSERR_LOG_OR_PRINT, "get_pvtx$cleanup: Force released hold on pvtx ^d for ^a.",
			pv_holdt (i).pvtx, pds$process_group_id);
		     released_something = "1"b;
		end;
	end;

	return (released_something);



reset:
     entry;

/**** FUNCTION - at emergency_shutdown time, bump the inconsistency count
      in the pvte for all held volumes, and release all of them.
      Thus will produce some spurious scavenges, but will also tend to
      detect a variety of interrupted operations. */


	pv_holdtp = addr (PV_HOLDT);
	pvt_arrayp = addr (pvt$array);
	do i = lbound (pv_holdt, 1) to hbound (pv_holdt, 1);
	     if pv_holdt (i).apterp ^= ""b
	     then do;
		     pvtep = addr (pvt_array (pv_holdt (i).pvtx));
		     pvte.vol_trouble_count = pvte.vol_trouble_count + 1;
		     call ZERO_ENTRY (i);
		end;
	end;
	return;


/**** FUNCTION -- return address of static table to be put in
      easily readable spot in sst_seg. */


ret_pvhtp:
     entry returns (ptr);

	return (addr (PV_HOLDT));			/* For debugging */






ZERO_ENTRY:
     proc (i);

	dcl     (i, x)		 fixed bin;
	dcl     word		 bit (36) aligned;

	x = pv_holdt (i).pvtx;
	word = unspec (pv_holdt (i));

	if ^stacq (addr (pv_holdt (i)), word, (36)"0"b)
	then call syserr (SYSERR_CRASH_SYSTEM, "get_pvtx: ZERO_ENTRY fails");

	if pvt_array (x).being_demounted
	then call pxss$notify (CST + i);

	return;

     end;

%include pvte;

%include pv_holdt;

%include syserr_constants;

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   get_pvtx: hold_pvtx finds table full

   S: $crash

   T: $run

   M: There are no free entries in the physical volume hold table.
   There should never be more than twice the number of eligible
   processes of used entries.
   $err

   A: $recover

   Message:
   get_pvtx: release_pvtx: mark not found

   S: $crash

   T: $run

   M: While attempting to release a physical volume from demount protection,
   the mark made by the protection could not be found in the physical volume
   hold table.  This message can also occur if somehow the physical
   volume was demounted in spite of this protection, or this entry
   point is being used improperly.
   $err

   A: $recover

   Message:
   get_pvtx: drain_pvtx: pvte.being_demounted should be on.

   S: $crash

   T: $run

   M: The entry to the physical volume demount protection mechanism
   which awaits all use of the volume to cease is being called improperly.
   A necessary precondition for its
   proper operation (pvte.being_demounted) is not met.
   $err

   A: $recover

   Message:
   get_pvtx: ZERO_ENTRY fails

   S: $crash

   T: $run

   M: The STACQ instruction has failed to clear an entry in the
   physical volume hold table.
   $err

   A: $recover


   Message:
   get_pvtx$cleanup: Force released hold on pvtx ^d for USER_ID.

   S:	$info

   T:	$run

   M:	$err
   A condition was signalled in ring-0 which caused a crawlout.
   get_pvtx$cleanup will release all PV holds for the process.

   A:	$notify

   END MESSAGE DOCUMENTATION */

     end;




		    init_volmap_seg.pl1             11/11/89  1138.3r w 11/11/89  0838.7      139851



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        *********************************************************** */
/* format: style3 */
init_volmap_seg:
     proc (Pvtx, Pvname, Code);

/* Program to accomplish the following at physical volume mount time:

     1. Create a volmap_seg for the volume

     2. Determine whether the volume requires salvage

     3. Allocate a record stock

     4. Allocate a VTOCE stock

     5. Initialize the dumper bit map


   A volume is salvaged automatically if the following
   conditions hold:

     1. The volume is a member of the RLV

     2. The vol_trouble_count is non-zero (i.e., the volume was not shut
        down, or volume inconsistencies were detected).

     3. The number of records left is less than 200, or the number of
        VTOCEs left is less than 100.

   Some care is required in order than an RPV volume may be salvaged.
   Specifically, no PVTE fields needed for HC partition withdrawal can be 
   modified until it is known that the RPV does not need salvage. That way, we 
   return an error code (causing the volume salvager to be invoked), and pages
   can be withdrawn against the HC partition. We don't special-case the
   RPV, but just order things so that the relevant PVTE fields are not
   modified until after the check for salvage required.

   Written March 1982 by J. Bongiovanni
   Modified September 1982 by J. Bongiovanni to set aste.vtocx
   Modified January 1985 by Keith Loepere to return real error codes.
*/

/*  Parameter  */

dcl	Pvtx		fixed bin parameter;	/* PVTE index */
dcl	Pvname		char (*) parameter;		/* Physical volume name for error message */
dcl	Code		fixed bin (35);		/* Return code */

/*  Automatic  */

dcl	base_add		fixed bin;
dcl	bias		fixed bin;
dcl	code		fixed bin (35);
dcl	n_free_vtoce	fixed bin;
dcl	ox		fixed bin;
dcl	p99		pic "99";
dcl	page_left		fixed bin;
dcl	page_n_words	fixed bin;
dcl	page_offset	fixed bin (19);
dcl	pagex		fixed bin;
dcl	ptp		ptr;
dcl	severity		fixed bin;
dcl	tsdw		fixed bin (71);
dcl	unused_mapp	ptr;
dcl	unused_map_words	fixed bin;
dcl	vastep		ptr;
dcl	vleft		fixed bin;
dcl	vsdw		fixed bin (71);
dcl	vtoc_header_pages	fixed bin;
dcl	vtoc_map_offset	bit (18);

/*  Static  */

dcl	MIN_RECORDS	fixed bin int static options (constant) init (200);
dcl	MIN_VTOCES	fixed bin int static options (constant) init (100);

/*  Based  */

dcl	unused_map	(unused_map_words) bit (36) aligned based (unused_mapp);
dcl	1 vaste		aligned like aste based (vastep);

/*  External  */

dcl	abs_seg$		external;
dcl	error_table_$fsdisk_not_salv fixed bin (35) ext static;
dcl	error_table_$fsdisk_phydev_err fixed bin (35) ext static;
dcl	sst$astsize	fixed bin external;
dcl	1 sst$level	(0:3) aligned external,
	  2 ausedp	bit (18) unaligned,
	  2 no_aste	bit (18) unaligned;
dcl	volmap_abs_seg$	external;

/*  Entry  */

dcl	dbm_man$init_map	entry (fixed bin, ptr, fixed bin (35));
dcl	get_aste		entry (fixed bin) returns (ptr);
dcl	get_ptrs_$given_astep
			entry (ptr) returns (fixed bin (71));
dcl	init_hc_part$terminate_hc_part
			entry (fixed bin);
dcl	lock$lock_ast	entry;
dcl	lock$unlock_ast	entry;
dcl	map_free_count	entry (ptr, fixed bin, fixed bin);
dcl	pc$cleanup	entry (ptr);
dcl	pmut$swap_sdw	entry (ptr, ptr);
dcl	ptw_util_$make_disk entry (ptr, fixed bin);
dcl	put_aste		entry (ptr);
dcl	sdw_util_$set_size	entry (ptr, fixed bin (19));
dcl	stock_man$allocate_record_stock
			entry (ptr, ptr);
dcl	stock_man$allocate_vtoce_stock
			entry (ptr, ptr);
dcl	stock_man$free_record_stock
			entry (ptr, ptr);
dcl	stock_man$free_vtoce_stock
			entry (ptr, ptr);
dcl	syserr		entry options (variable);
dcl	thread$out	entry (ptr, bit (18) unaligned);

/*  Builtin  */

dcl	addr		builtin;
dcl	addrel		builtin;
dcl	bin		builtin;
dcl	convert		builtin;
dcl	divide		builtin;
dcl	hbound		builtin;
dcl	null		builtin;
dcl	ptr		builtin;
dcl	size		builtin;
dcl	unspec		builtin;

/*  Condition  */

dcl	page_fault_error	condition;

%page;
	pvt_arrayp = addr (pvt$array);
	pvtep = addr (pvt_array (Pvtx));
	astep = null ();
	vastep = null ();
	tsdw = 0;
	vsdw = 0;
	record_stockp = null ();
	vtoce_stockp = null ();


/*  Get an ASTE for the volmap_seg and one to read the VTOC header  */

	call lock$lock_ast;

	vtoc_header_pages = divide (size (vtoc_header) + 1023, 1024, 17);
	astep = get_aste (vtoc_header_pages);
	if astep = null ()
	then call syserr (CRASH, "init_volmap_seg: Unable to get ^dK ASTE for VTOC header.", vtoc_header_pages);
	call thread$out (astep, sst$level (bin (aste.ptsi, 17)).ausedp);

	aste.pvtx = Pvtx;
	aste.nqsw, aste.dnzp, aste.ddnp = "1"b;
	aste.vtocx = -1;
	tsdw = get_ptrs_$given_astep (astep);
	call pmut$swap_sdw (addr (abs_seg$), addr (tsdw));

	vastep = get_aste (N_OLD_VOLMAP_PAGES + 1);
	if vastep = null ()
	then call syserr (CRASH, "init_volmap_seg: Unable to get ^dK ASTE for volmap_seg.", N_OLD_VOLMAP_PAGES + 1);
	call thread$out (vastep, sst$level (bin (vaste.ptsi)).ausedp);

	vaste.pvtx = Pvtx;
	vaste.nqsw, vaste.dnzp, vaste.ddnp = "1"b;
	vaste.volmap_seg = "1"b;
	vaste.vtocx = -1;
	vsdw = get_ptrs_$given_astep (vastep);
	call sdw_util_$set_size (addr (vsdw), ((N_OLD_VOLMAP_PAGES + 1) * 1024));
	call pmut$swap_sdw (addr (volmap_abs_seg$), addr (vsdw));

	call lock$unlock_ast;


/* Fill in disk addresses */

	ptp = addrel (astep, sst$astsize);
	do pagex = 1 to vtoc_header_pages;
	     call ptw_util_$make_disk (addrel (ptp, pagex - 1), DUMPER_BIT_MAP_ADDR + pagex - 1);
	end;

	ptp = addrel (vastep, sst$astsize);
	do pagex = 1 to N_OLD_VOLMAP_PAGES;
	     call ptw_util_$make_disk (addrel (ptp, pagex - 1), VOLMAP_ADDR + pagex - 1);
	end;
	call ptw_util_$make_disk (addrel (ptp, N_OLD_VOLMAP_PAGES), VTOC_MAP_ADDR);

	on page_fault_error goto CLEANUP_AFTER_IO_ERROR;

%page;
/* Clear unused space in Volume Map pages */

	vol_mapp = addr (volmap_abs_seg$);

	if vol_map.bit_map_n_words < hbound (vol_map.bit_map, 1)
						/* There is unused space */
	then do;
		unused_mapp = addr (vol_map.bit_map (vol_map.bit_map_n_words + 1));
		unused_map_words = hbound (vol_map.bit_map, 1) - vol_map.bit_map_n_words;
		unspec (unused_map) = "0"b;
	     end;

/* Determine the number of records really left in the Volume Map (it may
   be different from the value in the header if the volume was not shut
   down properly). */

	call map_free_count (addr (vol_map.bit_map), vol_map.bit_map_n_words, vleft);
	if vleft ^= vol_map.n_free_rec
	then do;
		call syserr (LOG, "init_volmap_seg: Records left on ^a_^a(^a) changed from ^d to ^d.", pvte.devname,
		     convert (p99, pvte.logical_area_number), Pvname, vol_map.n_free_rec, vleft);
		vol_map.n_free_rec = vleft;
	     end;
%page;
/* Setup the VTOC Map */

	vtoc_map_offset = bit (bin (1024 * N_OLD_VOLMAP_PAGES, 18), 18);
	vtoc_mapp = ptr (addr (volmap_abs_seg$), vtoc_map_offset);

/* Clear any unused space in the VTOC Map */

	if vtoc_map.bit_map_n_words < hbound (vtoc_map.bit_map, 1) + 1
	then do;
		unused_mapp = addr (vtoc_map.bit_map (vtoc_map.bit_map_n_words));
		unused_map_words = hbound (vtoc_map.bit_map, 1) + 1 - vtoc_map.bit_map_n_words;
		unspec (unused_map) = ""b;
	     end;

/* Get the count of free VTOCEs from the bit map, and compare with the
   value in the header */

	call map_free_count (addr (vtoc_map.bit_map), vtoc_map.bit_map_n_words, n_free_vtoce);
	if n_free_vtoce ^= vtoc_map.n_free_vtoce
	then do;
		call syserr (LOG, "init_volmap_seg: VTOCEs left on ^a_^a(^a) changed from ^d to ^d.", pvte.devname,
		     convert (p99, pvte.logical_area_number), Pvname, vtoc_map.n_free_vtoce, n_free_vtoce);
		vtoc_map.n_free_vtoce = n_free_vtoce;
	     end;


%page;
/* Check to see whether a salvage is required. If so, undo everything and
   return an error code indicating this. */

	if pvte.vol_trouble_count > 0
	then do;
		if vleft < MIN_RECORDS | n_free_vtoce < MIN_VTOCES
		then severity = ANNOUNCE;
		else severity = LOG;
		call syserr (severity,
		     "init_volmap_seg: ^d volume inconsistenc^[y^;ies^] on ^a_^a(^a). ^d records left. ^d VTOCEs left."
		     , pvte.vol_trouble_count, (pvte.vol_trouble_count = 1), pvte.devname,
		     convert (p99, pvte.logical_area_number), Pvname, vleft, n_free_vtoce);
		if pvte.hc_part_used
		then do;				/* Volume of RLV */
			if vleft < MIN_RECORDS | n_free_vtoce < MIN_VTOCES
			then do;
				code = error_table_$fsdisk_not_salv;
				goto CLEANUP_AFTER_ERROR;
			     end;
		     end;
	     end;
%page;
/* Now we know that we're really going to mount the volume. So we can allocate
   record and vtoce stocks, and fill in the fields in the PVTE from what we've
   already done.
*/

	revert page_fault_error;

	if pvte.hc_part_used
	then call init_hc_part$terminate_hc_part (Pvtx);	/* No more use of HC partition */

	call stock_man$allocate_record_stock (pvtep, record_stockp);
	call stock_man$allocate_vtoce_stock (pvtep, vtoce_stockp);

	pvte.volmap_astep = vastep;
	pvte.volmap_seg_sdw = vsdw;
	pvte.totrec = vol_map.n_rec;
	pvte.nleft = vol_map.n_free_rec;
	pvte.vtoc_map_offset = vtoc_map_offset;
	pvte.n_free_vtoce = vtoc_map.n_free_vtoce;
	pvte.vtoc_size = vtoc_map.vtoc_last_recno + 1;
	pvte.n_vtoce = vtoc_map.n_vtoce;

/* Walk the Bit Map and compute the base address and number of free records
   in each page. There is a kludge for the first page's base address to make
   life simple for Page Control. This is that the base address in the stock
   is 64*32 lower than the actual base address, since the first 64 words
   of the Volume Map are the header. */

	bias = 64 * 32;
	base_add, pvte.baseadd = vol_map.base_add;
	page_offset = 64;
	page_n_words = 1024 - 64;

	do ox = 1 to N_OLD_VOLMAP_PAGES;
	     call map_free_count (ptr (vol_mapp, page_offset), page_n_words, page_left);
						/* Count free records */
	     record_stock.volmap_page (ox).n_free = page_left;
	     record_stock.volmap_page (ox).baseadd = base_add - bias;
	     base_add = base_add + 1024 * 32;
	     page_offset = page_offset + page_n_words;
	     page_n_words = 1024;
	end;




%page;
/* Allocate a dumper bit map for the volume */

	vtoc_headerp = addr (abs_seg$);

	call dbm_man$init_map (Pvtx, addr (vtoc_header.dmpr_bit_map), code);
	if code ^= 0
	then call syserr (ANNOUNCE, "init_volmap_seg: Unable to initialize dumper map for ^a_^a(^a)", pvte.devname,
		convert (p99, pvte.logical_area_number), Pvname);
	code = 0;

%page;
	call lock$lock_ast;

CLEANUP_FINISH:
	if astep ^= null ()
	then do;
		tsdw = 0;
		call pmut$swap_sdw (addr (abs_seg$), addr (tsdw));
		call pc$cleanup (astep);
		call put_aste (astep);
	     end;

	vsdw = 0;
	call pmut$swap_sdw (addr (volmap_abs_seg$), addr (vsdw));

	call lock$unlock_ast;

	Code = code;

	return;


CLEANUP_AFTER_IO_ERROR:
	code = error_table_$fsdisk_phydev_err;

CLEANUP_AFTER_ERROR:
	call lock$lock_ast;

	if vastep ^= null ()
	then do;
		if record_stockp ^= null ()
		then call stock_man$free_record_stock (pvtep, record_stockp);
		if vtoce_stockp ^= null ()
		then call stock_man$free_vtoce_stock (pvtep, vtoce_stockp);

		vsdw = 0;
		call pmut$swap_sdw (addr (volmap_abs_seg$), addr (vsdw));
		call pc$cleanup (vastep);
		call put_aste (vastep);
	     end;


	goto CLEANUP_FINISH;

%page;
%include aste;
%page;
%include disk_pack;
%page;
%include pvte;
%page;
%include stock_seg;
%page;
%include syserr_constants;
%page;
%include vol_map;
%page;
%include vtoc_header;
%page;
%include vtoc_map;
%page;
/* BEGIN MESSAGE DOCUMENTATION

   Message:
   init_volmap_seg: Unable to initialize dumper map for dskX_NN(PVNAME)

   S:     $info

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     An unexpected error was encountered in initializing the
   backup queue bit map for the Physical Volume Dumper. The volume
   on which the error occurred cannot be backed up with the Physical
   Volume Dumper.

   A:     $inform


   Message:
   init_volmap_seg: Unable to get NK ASTE for VTOC header.

   S:     $crash

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     An NK ASTE was not available for accessing the VTOC header.
   The most likely cause is an ASTE pool size which is too small.

   A:     $recover
   Increase the number of ASTEs in the appropriate pool by means of the
   SST configuration card.

   Message:
   init_volmap_seg: Unable to get NK ASTE for volmap_seg.

   S:     $crash

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     An NK ASTE was not available for accessing the Volume Map.
   The most likely cause is an ASTE pool size which is too small.

   A:     $recover
   Increase the number of ASTEs in the appropriate pool by means of the
   SST configuration card.

   Message:
   init_volmap_seg: Records left on dskX_NN(PVNAME) changed from X to Y.

   S:     $log

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     A VTOC header was encountered which did not agree with the Volume
   Map. This will occur when a volume which was not shut down properly is
   mounted.

   A:     $inform

   Message:
   init_volmap_seg: VTOCEs left on dskX_NN(PVNAME) changed from X to Y.

   S:     $log

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     A VTOC header was encountered which did not agree with the VTOC
   Map. This will occur when a volume which was not shut down properly is
   mounted.

   A:     $inform

   Message:
   init_volmap_seg: YYYY volume inconsistencies on dskX_NN(PVNAME). UUUU records left. VVVV VTOCEs left.

   S:     Logged only if the number of free records and the number of free
   VTOCEs are both above thresholds. Logged and printed on the console if
   either is below threshold.

   T:	During system initialization as physical volumes of the Root
   Logical Volume (RLV) are accepted, during system start_up as physical
   volumes which were mounted at the last shutdown are accepted, or
   when a physical volume is mounted and accepted.

   M:     The volume was not shut down properly or inconsistencies were
   detected while the volume was mounted. The effect of these inconsistencies
   is that free records and free VTOCEs are lost to the system. Lost records
   and VTOCEs can be recovered by a volume salvage.

   A:     $inform

   END MESSAGE DOCUMENTATION */

     end init_volmap_seg;




		    logical_volume_manager.pl1      11/11/89  1138.3r w 11/11/89  0838.7       60066



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */


logical_volume_manager: proc ();

/*

   Written on Janurary 26, 1976 by R. Bratt

   Last modified:

   March 1982, J. Bongiovanni, for new PVTE
   June 1982, J. Bongiovanni, for deactivate_for_demount

   logical_volume_manager manages the ring zero logical volume table (LVT). The add, delete, and add_pv
   entry points are intended to be used exclusively by ring one RCP. These operations are assumed to be
   performed under the protection of a global RCP lock. As a result, no lock is provided in the LVT.
   When mounting a LV, RCP should call ring zero to mount each PV in the LV and finally it should
   call logical_volume_manager$add to define the LV for segment control. At this time the physical
   volume table (PVT) is scanned and all PVs belonging to the LV are threaded from the LVTE.
   If a LV is grown then RCP should call the add_pv entry point to logically add the PV to the LV.
   Before demounting a LV, RCP should call logical_volume_manager$delete to remove segment control's knowledge
   of the LV before any PVs of the LV are demounted. The final entry point, logical_volume_manager$lvtep,
   is called to locate information about a LV. Programs using this entry point must be prepared to have the LVTE
   disappear from under there noses. This program does not demount physical volumes,
   but must be called before any physical volumes in a logical volume are demounted.

*/

dcl  a_lvtep ptr,
     a_lvid bit (36) aligned,
     a_code fixed bin (35),
     a_pvid bit (36) aligned;

dcl 1 local_lvte aligned like lvte,
     must_exist bit (1) aligned static init ("1"b),
     must_not_exist bit (1) aligned static init ("0"b),
     code fixed bin (35),
    (pvtex, next_pvtex) fixed bin (8),
     lvid bit (36) aligned,
     prev_lvtep ptr;

dcl (error_table_$logical_volume_table_full, error_table_$logical_volume_is_defined,
     error_table_$pv_is_in_lv, error_table_$argerr,
     error_table_$logical_volume_not_defined) ext fixed bin (35);

dcl  pvt$n_entries fixed bin external;

dcl  syserr entry options (variable),
     deactivate_for_demount$lv entry (bit (36) aligned, fixed bin (35)),
     get_pvtx entry (bit (36) aligned, fixed bin (35)) returns (fixed bin (8));

/*  */
add:	entry (a_lvtep, a_code);
	local_lvte = a_lvtep -> lvte;
	a_code = 0;
	call find (local_lvte.lvid, (must_not_exist));
	call get_lvte ();
	lvte = local_lvte;
	lvte.lvtep = null ();			/* initialize threads in lvte */
	lvte.pvtex = 0;
	pvt_arrayp = addr (pvt$array);		/* collect PV thread */
	do pvtex = 1 to pvt$n_entries;
	     if (pvt_array (pvtex).lvid = lvte.lvid) & pvt_array (pvtex).used
	     then do;
		if pvt_array (pvtex).brother_pvtx ^= 0
		then call syserr (1, "logical_volume_manager: nonzero brother pvt thread");
		pvt_array (pvtex).brother_pvtx = lvte.pvtex;
		lvte.pvtex = pvtex;
	     end;
	end;
	prev_lvtep -> lvte.lvtep = lvtep;		/* attach LV to hash  thread */
	return;

lvtep:	entry (a_lvid, a_lvtep, a_code);
	a_code = 0;
	a_lvtep = null ();
	call find ((a_lvid), (must_exist));
	a_lvtep = lvtep;
	return;

delete:	entry (a_lvid, a_code);
	a_code = 0;
	lvid = a_lvid;
	call find (lvid, (must_exist));
	lvte.lvid = "0"b;				/* stop find from locating this LV */
	pvt_arrayp = addr (pvt$array);		/* cleanup all PVs of this LV */
	do pvtex = lvte.pvtex repeat (pvt_array (pvtex).brother_pvtx) while (pvtex ^= 0);
	     pvt_array (pvtex).being_demounted = "1"b;
	end;
	call deactivate_for_demount$lv (lvid, code);	/* deactivate all segments on the LV */
	if code ^= 0 then do;			/* error -back out */
	     lvte.lvid = lvid;
	     do pvtex = lvte.pvtex repeat (pvt_array (pvtex).brother_pvtx) while (pvtex ^= 0);
		pvt_array (pvtex).being_demounted = "0"b;
	     end;
	     call abort (code);
	end;

	do pvtex = lvte.pvtex repeat (pvt_array (pvtex).brother_pvtx) while (pvtex ^= 0);
	     pvt_array (pvtex).brother_pvtx = 0;
	end;
	prev_lvtep -> lvte.lvtep = lvte.lvtep;		/* thread out of hash class */
	lvte.lvtep = lvt.free_lvtep;			/* thread onto free list */
	lvt.free_lvtep = lvtep;
	return;

add_pv:	entry (a_lvid, a_pvid, a_code);
	a_code = 0;
	lvid = a_lvid;
	pvtex = get_pvtx ((a_pvid), code);
	if code ^= 0 then call abort (code);
	pvt_arrayp = addr (pvt$array);
	if pvt_array (pvtex).lvid ^= lvid
	then call abort (error_table_$argerr);
	if pvt_array (pvtex).brother_pvtx ^= 0
	then call abort (error_table_$pv_is_in_lv);
	call find (lvid, (must_exist));
	pvt_array (pvtex).brother_pvtx = lvte.pvtex;
	lvte.pvtex = pvtex;
	return;

/*  */
find:	proc (lvid, match_desired /* ,lvtp, prev_lvtep, lvtep */);
dcl  lvid bit (36) aligned,
     match_desired bit (1) aligned,
     hashx fixed bin (35);

	     lvtp = addr (lvt$);
	     hashx = mod (bin (bin (lvid), 35), dimension (lvt.ht, 1));
	     prev_lvtep = addr (lvt.ht (hashx));
	     do lvtep = lvt.ht (hashx) repeat (lvte.lvtep) while (lvtep ^= null ());
		if lvte.lvid = lvid
		then if match_desired
		     then return;
		     else call abort (error_table_$logical_volume_is_defined);
		prev_lvtep = lvtep;
	     end;
	     if match_desired
	     then call abort (error_table_$logical_volume_not_defined);
	     else return;
	end find;

get_lvte:	proc ( /* lvtp, lvtep */);
	     if lvt.free_lvtep ^= null ()
	     then do;
		lvtep = lvt.free_lvtep;
		lvt.free_lvtep = lvte.lvtep;
		return;
	     end;
	     else if lvt.high_water_lvtex < lvt.max_lvtex
	     then do;
		lvt.high_water_lvtex = lvt.high_water_lvtex + 1;
		lvtep = addr (lvt.lvtes (lvt.high_water_lvtex));
		return;
	     end;
	     else call abort (error_table_$logical_volume_table_full);
	end get_lvte;

abort:	proc (code);
dcl  code fixed bin (35);
	     a_code = code;
	     go to return_to_caller;
	end abort;

return_to_caller:
	return;
						/*
						   
						   */

%  include lvt;
/*
   
*/

% include pvte;

/* BEGIN MESSAGE DOCUMENTATION

Message:
logical_volume_manager: nonzero brother pvt thread

S:	$crash

T:	$run

M:	$err

A:	$recover


END MESSAGE DOCUMENTATION */

     end logical_volume_manager;




		    map_free_count.alm              11/11/89  1138.3r w 11/11/89  0838.7       20322



" ***********************************************************
" *                                                         *
" * Copyright, (C) Honeywell Bull Inc., 1987                *
" *                                                         *
" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
" *                                                         *
" ***********************************************************

" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
"
"	map_free_count
"
"	Routine to examine a part of a bit-map in standard format and
"	return the number of free entries in the map. Standard format
"	means the following:
"
"	    1. Each word represents 32 items
"
"	    2. Bit ON => the item is free
"
"	    3. Bits 1 - 32 only are used
"
"	The Volume Map and the VTOC Map are in this format.
"
"	call map_free_count (map_ptr, map_n_words, free_count)
"
"	where
"	    map_ptr points to the first word (Input)
"	    map_n_words is the number of words (Input)
"	    free_count is the number of free entries (Output)
"
"	This is coded in ALM to perform the computation with ruthless
"	efficiency.
"
"	Written March 1982 by J. Bongiovanni
"	Modified December 1982 by J. Bongiovanni to reset overflow before fno
"
" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "

	name	map_free_count

	entry	map_free_count

map_mask:
	oct	377777777770		" Mask of used bits in word
map_low_bits:
	oct	177777777770		" To strip out high bit


map_free_count:
	
	eppbp	ap|2,*			" bp -> ptr -> map
	eppbp	bp|0,*			" bp -> map
	lxl0	ap|4,*			" x0 = number of words
	ldx1	0,du			" x1 = number free items

	stz	ap|6,*			" Clear return value

map_word_loop:
	eax0	-1,x0			" Decrement word count
	tmi	map_returns_count		" Done
	ldq	0,dl
	lda	bp|0,x0			" Next word
	ana	map_mask			" Used bits only
	tze	map_word_loop		" No free items this word
	arl	1			" Initial alignment

map_bit_loop:
	eax1	1,x1			" One more free
	ldi	0,dl			" Make sure overflow is Off
	lde	0,du
	fno				" Get next On bit high
	ana	map_low_bits		" And strip it out
	tze	map_word_loop		" Done this word
	tra	map_bit_loop		" More On bits this word

map_returns_count:
	sxl1	ap|6,*			" Number free items
	short_return

	end




		    partition_io.pl1                11/11/89  1138.3r w 11/11/89  0838.7       93915



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1983 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */

/* format: style2 */

partition_io:
     proc ();

	return;					/* Not an entrypoint */

/* *	Privileged (hphcs_) procedure to write data to/from a disk partition.
   *	This is intended mostly as a way of writing BOOT partitions.
   *
   *
   *	I also chose this cheerful little program to implement a phcs_ accessable
   *	volume label reader, something we've needed for years.
   *
   *	Created 09/29/80 W. Olin Sibert, for Bootload Multics.
   *	Fixed to use get_pvtx, added read_label, 10/18/80 WOS
   *	Modified to add find_partition entry, March 1982, J. Bongiovanni
   *      Modified to use a real abs_seg, BIM, 3/83.
   *	Modified for find_partition_given_drive, K. Loepere, 4/84.
   *	Moved find_partition into its own routine, Keith Loepere, 1/85.
   */


/****^  HISTORY COMMENTS:
  1) change(85-09-12,Farley), approve(86-07-10,MCR7273),
     audit(86-07-15,Fawcett), install(86-07-17,MR12.0-1097):
     Set aste.records to correct value and set aste.dnzp to force writting of
     zero pages back to the partition.
                                                   END HISTORY COMMENTS */


%page;
	dcl     (
	        a_pvid		 bit (36) aligned,	/* PVID of volume with partition */
	        a_part_name		 char (*),	/* Name of partition */
	        a_offset		 fixed bin (35),	/* Word offset from base of partition */
	        a_data_ptr		 pointer,		/* Pointer to user supplied data */
	        a_data_size		 fixed bin (18),	/* Number of words to read or write */
	        a_label_ptr		 pointer,		/* Pointer to user label area */
	        a_code		 fixed bin (35)
	        )			 parameter;	/* Error code */

	dcl     pvid		 bit (36) aligned;
	dcl     part_name		 char (4) aligned;
	dcl     offset		 fixed bin (35);
	dcl     data_ptr		 pointer;
	dcl     data_size		 fixed bin (18);
	dcl     data		 (0:data_size - 1) based (data_ptr) bit (36) aligned;

	dcl     code		 fixed bin (35);
	dcl     pvtx		 fixed bin (8);
	dcl     ptsi		 fixed bin;
	dcl     first_record	 fixed bin (18);
	dcl     offset_in_abs_seg	 fixed bin (18);
	dcl     part_abs_seg_ptr	 pointer;
	dcl     tsdwp		 pointer;
	dcl     tsdw		 bit (72) aligned;

/* These switches should ALL be initialized at EVERY entrypoint. */

	dcl     label_sw		 bit (1) aligned;	/* Whether we're to just return the label */
	dcl     write_sw		 bit (1) aligned;	/* Wether we're to read or write */

	dcl     part_idx		 fixed bin;
	dcl     part_start		 fixed bin (18);	/* First record and size of specified partition */
	dcl     part_nrecs		 fixed bin (18);
	dcl     (first_word_in_data, last_word_in_data)
				 fixed bin (35);
	dcl     first_page		 fixed bin;
	dcl     n_pages		 fixed bin;
	dcl     ptp		 pointer;
	dcl     record_buffer	 (1024) bit (36) aligned;
	dcl     i			 fixed bin;

	dcl     sys_info$page_size	 fixed bin external;
	dcl     sys_info$max_seg_size	 fixed bin (18) external;
	dcl     abs_seg$		 external;
	dcl     sst$astsize		 fixed bin external;
	dcl     1 sst$level		 (0:3) aligned external static,
		2 ausedp		 bit (18) unaligned,
		2 no_aste		 bit (18) unaligned;

	dcl     condition_		 entry (char (*), entry);
	dcl     privileged_mode_ut$swap_sdw
				 ext entry (ptr, ptr);
	dcl     thread$out		 entry (ptr, bit (18) unal);
	dcl     read_disk		 entry (fixed bin (8), fixed bin (18), pointer, fixed bin (35));
	dcl     lock$lock_ast	 entry;
	dcl     lock$unlock_ast	 entry;
	dcl     get_ptrs_$given_astep	 ext entry (ptr) returns (bit (72) aligned);
	dcl     pc$cleanup		 entry (ptr);
	dcl     get_aste		 ext entry (fixed bin) returns (ptr);
	dcl     put_aste		 ext entry (ptr);
	dcl     ptw_util_$make_disk	 entry (pointer, fixed bin (20));


	dcl     get_pvtx$get_pvtx	 entry (bit (36) aligned, fixed bin (35)) returns (fixed bin (8));
	dcl     get_pvtx$hold_pvtx	 entry (bit (36) aligned, fixed bin (8), fixed bin (35));
	dcl     get_pvtx$release_pvtx	 entry (bit (36) aligned, fixed bin (8));

	dcl     (
	        error_table_$bad_arg,
	        error_table_$noentry,
	        error_table_$out_of_bounds,
	        error_table_$pvid_not_found
	        )			 fixed bin (35) external static;

	dcl     (addr, addwordno, bin, bit, divide, fixed, mod, null, setwordno, wordno)
				 builtin;
%page;
partition_io$priv_read:
     entry (a_pvid, a_part_name, a_offset, a_data_ptr, a_data_size, a_code);

	label_sw = "0"b;
	write_sw = "0"b;
	goto COMMON;


partition_io$priv_write:
     entry (a_pvid, a_part_name, a_offset, a_data_ptr, a_data_size, a_code);

	label_sw = "0"b;
	write_sw = "1"b;
	goto COMMON;


partition_io$read_label:
     entry (a_pvid, a_label_ptr, a_code);

/* This entry is SPECIAL: it only reads the label, and returns. This is implemented
   here because it's convenient, but the implementation here does involve a handful
   of kludgy switches and tests (this is what label_sw means); so, be careful when
   you modify it. The other entries are relatively unsurprising.
   */

	label_sw = "1"b;
	write_sw = "0"b;
	goto COMMON;
%page;
COMMON:
	pvid = a_pvid;				/* Copy parameters */
	if ^label_sw
	then do;					/* Copy partition parameters, if not just reading label */
		part_name = a_part_name;
		offset = a_offset;
		data_ptr = a_data_ptr;
		data_size = a_data_size;
		if data_size < 0
		then do;
			a_code = error_table_$bad_arg;/* avoid problems with negative values */
			return;
		     end;
		else if data_size = 0
		then do;
			a_code = 0;
			return;
		     end;
	     end;

	pvtx = -1;
	code = 0;
	astep = null ();

	pvtx = get_pvtx$get_pvtx (pvid, code);
	if code ^= 0
	then go to FINISHED;

	call get_pvtx$hold_pvtx (pvid, pvtx, code);
	if code ^= 0
	then goto FINISHED;

	labelp = addr (record_buffer);
	call read_disk (pvtx, 0, labelp, code);		/* First, inspect the label to find the partition */
	if code ^= 0
	then /* Can't read the label */
	     goto FINISHED;

	if label.Multics ^= Multics_ID_String
	then do;					/* Can't happen, but just in case */
		code = error_table_$pvid_not_found;
		goto FINISHED;
	     end;

	if label_sw
	then do;					/* We are just to read the label, and return */
		a_label_ptr -> label = label;		/* copy it out */
		code = 0;
		goto FINISHED;
	     end;					/* ALL DONE with label reading entry */
%page;
	do part_idx = 1 to label.nparts;		/* Now, look forthe partition we're supposed to use */
	     if label.parts (part_idx).part = part_name
	     then do;				/* Found it */
		     part_start = label.parts (part_idx).frec;
		     part_nrecs = label.parts (part_idx).nrec;
		     goto FOUND_PARTITION;
		end;
	end;

	code = error_table_$noentry;			/* If we fall through, it ain't there */
	goto FINISHED;


FOUND_PARTITION:					/* Come here to start doing actual work */
	if (offset + data_size) > (sys_info$page_size * part_nrecs)
	then do;					/* Reference outside the partition */
		code = error_table_$out_of_bounds;	/* Nice try, chum. */
		goto FINISHED;
	     end;

	if (wordno (data_ptr) + data_size) > sys_info$max_seg_size
	then do;					/* Trying to reference past */
		code = error_table_$out_of_bounds;	/* the end of our input segment? Sorry, no. */
		goto FINISHED;
	     end;
%page;
	first_word_in_data = offset;			/* The first and last words of user supplied data */
	last_word_in_data = offset + data_size - 1;

	first_page = divide (first_word_in_data, sys_info$page_size, 18, 0);
						/* The first and last records we must deal with */
	n_pages = divide (last_word_in_data, sys_info$page_size, 18, 0) - first_page + 1;
	first_record = part_start + first_page;
	offset_in_abs_seg = mod (offset, sys_info$page_size);
%page;

/* Now create an abs_seg through which to look at the partition */

	part_abs_seg_ptr = addr (abs_seg$);		/* get pointer to abs_seg */
	tsdwp = addr (tsdw);			/* get a pointer to the SDW to be used */
	call lock$lock_ast;
	astep = get_aste (n_pages);			/* get a large page table / ASTE */
	ptsi = fixed (aste.ptsi, 2);
	call thread$out (astep, sst$level.ausedp (ptsi));
	call lock$unlock_ast;
	ptp = addwordno (astep, sst$astsize);		/* get a pointer to the page table */
	tsdw = get_ptrs_$given_astep (astep);		/* get the actual SDW to use */
	call privileged_mode_ut$swap_sdw (part_abs_seg_ptr, tsdwp);
						/* make abs_seg point to the dump seg */
	aste.pvtx = pvtx;
	aste.csl = bit (bin (n_pages, 9), 9);		/* Set correct current length in AST entry. */
	aste.records = bit (bin (n_pages, 9), 9);	/* Set correct records being used */
	aste.nqsw = "1"b;				/* indicate no quota for this segment */
	aste.dnzp = "1"b;				/* force zero pages to the partition */
%page;

/* Set up a condition in case we bomb out. */

	call condition_ ("any_other", any_other_handler);

	do i = 0 to (n_pages - 1);			/* <= 255 */
	     call ptw_util_$make_disk (addwordno (ptp, i), (first_record + i));
						/* The disk record */
	end;

	aste.npfs = "0"b;				/* Make sure page faults are legal */

	begin;
	     declare part_ptr	      pointer;
	     declare part		      (0:data_size - 1) bit (36) aligned based (part_ptr);

	     part_ptr = setwordno (part_abs_seg_ptr, offset_in_abs_seg);
	     if write_sw
	     then part = data;
	     else data = part;
	end;

	code = 0;
FINISHED:
	if astep ^= null ()
	then do;
		call pc$cleanup (astep);
		call lock$lock_ast;
		call put_aste (astep);		/* return the AST entry */
		call lock$unlock_ast;
		tsdw = ""b;
		call privileged_mode_ut$swap_sdw (part_abs_seg_ptr, tsdwp);
	     end;
	if pvtx > 0
	then /* We had a pvtx, so release it */
	     call get_pvtx$release_pvtx (pvid, pvtx);
	a_code = code;				/* copy the error code */
	return;					/* and return to our caller */


any_other_handler:
     procedure (MC_ptr);
	declare MC_ptr		 pointer;
%include mc;

	mcp = MC_ptr;
	code = mc.errcode;
	go to FINISHED;
     end any_other_handler;


/* format: off */

%page; %include aste;
%page; %include fs_vol_label;
	end partition_io;




		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved
